From afc3a0dd9690c53de7f26826418b3ca2606c4c50 Mon Sep 17 00:00:00 2001 From: Aaron Tainter Date: Wed, 15 Apr 2026 14:26:49 -0700 Subject: [PATCH 1/2] Remove legacy FGA package --- src/common/net/fetch-client.spec.ts | 82 +- src/common/net/http-client.ts | 4 +- src/fga/fga-live-test.spec.ts | 1196 ----------------- src/fga/fga.spec.ts | 809 ----------- src/fga/fga.ts | 288 ---- src/fga/interfaces/check-op.enum.ts | 4 - src/fga/interfaces/check.interface.ts | 117 -- src/fga/interfaces/index.ts | 8 - src/fga/interfaces/list.interface.ts | 10 - src/fga/interfaces/query.interface.ts | 33 - src/fga/interfaces/resource-op.enum.ts | 4 - src/fga/interfaces/resource.interface.ts | 80 -- src/fga/interfaces/warning.interface.ts | 11 - src/fga/interfaces/warrant-op.enum.ts | 4 - src/fga/interfaces/warrant-token.interface.ts | 7 - src/fga/interfaces/warrant.interface.ts | 76 -- ...atch-write-resources-options.serializer.ts | 35 - .../serializers/check-options.serializer.ts | 76 -- .../create-resource-options.serializer.ts | 19 - .../delete-resource-options.serializer.ts | 18 - src/fga/serializers/index.ts | 13 - .../list-resources-options.serializer.ts | 15 - .../list-warrants-options.serializer.ts | 17 - src/fga/serializers/list.serializer.ts | 12 - .../serializers/query-options.serializer.ts | 12 - .../serializers/query-result.serializer.ts | 27 - src/fga/serializers/resource.serializer.ts | 17 - .../serializers/warrant-token.serializer.ts | 10 - src/fga/serializers/warrant.serializer.ts | 13 - .../write-warrant-options.serializer.ts | 30 - src/fga/utils/fetch-and-deserialize-list.ts | 23 - src/fga/utils/fga-paginatable.ts | 24 - src/fga/utils/interface-check.ts | 19 - src/index.ts | 1 - src/index.worker.ts | 1 - src/workos.ts | 2 - 36 files changed, 8 insertions(+), 3109 deletions(-) delete mode 100644 src/fga/fga-live-test.spec.ts delete mode 100644 src/fga/fga.spec.ts delete mode 100644 src/fga/fga.ts delete mode 100644 src/fga/interfaces/check-op.enum.ts delete mode 100644 src/fga/interfaces/check.interface.ts delete mode 100644 src/fga/interfaces/index.ts delete mode 100644 src/fga/interfaces/list.interface.ts delete mode 100644 src/fga/interfaces/query.interface.ts delete mode 100644 src/fga/interfaces/resource-op.enum.ts delete mode 100644 src/fga/interfaces/resource.interface.ts delete mode 100644 src/fga/interfaces/warning.interface.ts delete mode 100644 src/fga/interfaces/warrant-op.enum.ts delete mode 100644 src/fga/interfaces/warrant-token.interface.ts delete mode 100644 src/fga/interfaces/warrant.interface.ts delete mode 100644 src/fga/serializers/batch-write-resources-options.serializer.ts delete mode 100644 src/fga/serializers/check-options.serializer.ts delete mode 100644 src/fga/serializers/create-resource-options.serializer.ts delete mode 100644 src/fga/serializers/delete-resource-options.serializer.ts delete mode 100644 src/fga/serializers/index.ts delete mode 100644 src/fga/serializers/list-resources-options.serializer.ts delete mode 100644 src/fga/serializers/list-warrants-options.serializer.ts delete mode 100644 src/fga/serializers/list.serializer.ts delete mode 100644 src/fga/serializers/query-options.serializer.ts delete mode 100644 src/fga/serializers/query-result.serializer.ts delete mode 100644 src/fga/serializers/resource.serializer.ts delete mode 100644 src/fga/serializers/warrant-token.serializer.ts delete mode 100644 src/fga/serializers/warrant.serializer.ts delete mode 100644 src/fga/serializers/write-warrant-options.serializer.ts delete mode 100644 src/fga/utils/fetch-and-deserialize-list.ts delete mode 100644 src/fga/utils/fga-paginatable.ts delete mode 100644 src/fga/utils/interface-check.ts diff --git a/src/common/net/fetch-client.spec.ts b/src/common/net/fetch-client.spec.ts index 74bea0f2e..680f7f58a 100644 --- a/src/common/net/fetch-client.spec.ts +++ b/src/common/net/fetch-client.spec.ts @@ -15,73 +15,6 @@ describe('Fetch client', () => { beforeEach(() => fetch.resetMocks()); describe('fetchRequestWithRetry', () => { - it('get for FGA path should call fetchRequestWithRetry and return response', async () => { - fetchOnce({ data: 'response' }); - const mockFetchRequestWithRetry = jest.spyOn( - FetchHttpClient.prototype as any, - 'fetchRequestWithRetry', - ); - - const response = await fetchClient.get('/fga/v1/resources', {}); - - expect(mockFetchRequestWithRetry).toHaveBeenCalledTimes(1); - expect(fetchURL()).toBe('https://test.workos.com/fga/v1/resources'); - expect(await response.toJSON()).toEqual({ data: 'response' }); - }); - - it('post for FGA path should call fetchRequestWithRetry and return response', async () => { - fetchOnce({ data: 'response' }); - const mockFetchRequestWithRetry = jest.spyOn( - FetchHttpClient.prototype as any, - 'fetchRequestWithRetry', - ); - - const response = await fetchClient.post('/fga/v1/resources', {}, {}); - - expect(mockFetchRequestWithRetry).toHaveBeenCalledTimes(1); - expect(fetchURL()).toBe('https://test.workos.com/fga/v1/resources'); - expect(await response.toJSON()).toEqual({ data: 'response' }); - }); - - it('put for FGA path should call fetchRequestWithRetry and return response', async () => { - fetchOnce({ data: 'response' }); - const mockFetchRequestWithRetry = jest.spyOn( - FetchHttpClient.prototype as any, - 'fetchRequestWithRetry', - ); - - const response = await fetchClient.put( - '/fga/v1/resources/user/user-1', - {}, - {}, - ); - - expect(mockFetchRequestWithRetry).toHaveBeenCalledTimes(1); - expect(fetchURL()).toBe( - 'https://test.workos.com/fga/v1/resources/user/user-1', - ); - expect(await response.toJSON()).toEqual({ data: 'response' }); - }); - - it('delete for FGA path should call fetchRequestWithRetry and return response', async () => { - fetchOnce({ data: 'response' }); - const mockFetchRequestWithRetry = jest.spyOn( - FetchHttpClient.prototype as any, - 'fetchRequestWithRetry', - ); - - const response = await fetchClient.delete( - '/fga/v1/resources/user/user-1', - {}, - ); - - expect(mockFetchRequestWithRetry).toHaveBeenCalledTimes(1); - expect(fetchURL()).toBe( - 'https://test.workos.com/fga/v1/resources/user/user-1', - ); - expect(await response.toJSON()).toEqual({ data: 'response' }); - }); - it('get for Vault path should call fetchRequestWithRetry and return response', async () => { fetchOnce({ data: 'response' }); const mockFetchRequestWithRetry = jest.spyOn( @@ -153,7 +86,7 @@ describe('Fetch client', () => { const mockSleep = jest.spyOn(fetchClient, 'sleep'); mockSleep.mockImplementation(() => Promise.resolve()); - const response = await fetchClient.get('/fga/v1/resources', {}); + const response = await fetchClient.get('/vault/v1/kv', {}); expect(mockShouldRetryRequest).toHaveBeenCalledTimes(2); expect(mockSleep).toHaveBeenCalledTimes(1); @@ -175,7 +108,7 @@ describe('Fetch client', () => { const mockSleep = jest.spyOn(fetchClient, 'sleep'); mockSleep.mockImplementation(() => Promise.resolve()); - const response = await fetchClient.get('/fga/v1/resources', {}); + const response = await fetchClient.get('/vault/v1/kv', {}); expect(mockShouldRetryRequest).toHaveBeenCalledTimes(2); expect(mockSleep).toHaveBeenCalledTimes(1); @@ -197,7 +130,7 @@ describe('Fetch client', () => { const mockSleep = jest.spyOn(fetchClient, 'sleep'); mockSleep.mockImplementation(() => Promise.resolve()); - const response = await fetchClient.get('/fga/v1/resources', {}); + const response = await fetchClient.get('/vault/v1/kv', {}); expect(mockShouldRetryRequest).toHaveBeenCalledTimes(2); expect(mockSleep).toHaveBeenCalledTimes(1); @@ -236,7 +169,7 @@ describe('Fetch client', () => { const mockSleep = jest.spyOn(fetchClient, 'sleep'); mockSleep.mockImplementation(() => Promise.resolve()); - await expect(fetchClient.get('/fga/v1/resources', {})).rejects.toThrow( + await expect(fetchClient.get('/vault/v1/kv', {})).rejects.toThrow( 'Gateway Timeout', ); @@ -256,7 +189,7 @@ describe('Fetch client', () => { 'shouldRetryRequest', ); - await expect(fetchClient.get('/fga/v1/resources', {})).rejects.toThrow( + await expect(fetchClient.get('/vault/v1/kv', {})).rejects.toThrow( 'Bad Request', ); @@ -275,7 +208,7 @@ describe('Fetch client', () => { const mockSleep = jest.spyOn(fetchClient, 'sleep'); mockSleep.mockImplementation(() => Promise.resolve()); - const response = await fetchClient.get('/fga/v1/resources', {}); + const response = await fetchClient.get('/vault/v1/kv', {}); expect(mockFetchRequest).toHaveBeenCalledTimes(2); expect(mockSleep).toHaveBeenCalledTimes(1); @@ -314,8 +247,7 @@ describe('Fetch client', () => { } }); - it('should throw ParseError for non-FGA endpoints with invalid JSON response', async () => { - // Test with a non-FGA endpoint to ensure the error handling works for regular requests too + it('should throw ParseError for endpoints with invalid JSON response', async () => { fetch.mockResponseOnce('Not JSON content', { status: 400, statusText: 'Bad Request', diff --git a/src/common/net/http-client.ts b/src/common/net/http-client.ts index 3b9332878..d29764bae 100644 --- a/src/common/net/http-client.ts +++ b/src/common/net/http-client.ts @@ -107,9 +107,7 @@ export abstract class HttpClient implements HttpClientInterface { static isPathRetryable(path: string): boolean { return ( - path.startsWith('/fga/') || - path.startsWith('/vault/') || - path.startsWith('/audit_logs/events') + path.startsWith('/vault/') || path.startsWith('/audit_logs/events') ); } diff --git a/src/fga/fga-live-test.spec.ts b/src/fga/fga-live-test.spec.ts deleted file mode 100644 index def25b96e..000000000 --- a/src/fga/fga-live-test.spec.ts +++ /dev/null @@ -1,1196 +0,0 @@ -import { disableFetchMocks, enableFetchMocks } from 'jest-fetch-mock'; - -import { WorkOS } from '../workos'; -import { CheckOp, ResourceOp, WarrantOp } from './interfaces'; - -describe.skip('FGA Live Test', () => { - let workos: WorkOS; - - beforeAll(() => { - disableFetchMocks(); - workos = new WorkOS('API_KEY'); - }); - - afterAll(() => { - enableFetchMocks(); - }); - - it('CRUD resources', async () => { - const resource1 = await workos.fga.createResource({ - resource: { resourceType: 'document' }, - }); - expect(resource1.resourceType).toEqual('document'); - expect(resource1.resourceId).toBeDefined(); - expect(resource1.meta).toBeUndefined(); - - let resource2 = await workos.fga.createResource({ - resource: { resourceType: 'folder', resourceId: 'planning' }, - }); - let refetchedResource = await workos.fga.getResource(resource2); - expect(refetchedResource.resourceType).toEqual(resource2.resourceType); - expect(refetchedResource.resourceId).toEqual(resource2.resourceId); - expect(refetchedResource.meta).toEqual(resource2.meta); - - resource2 = await workos.fga.updateResource({ - resource: { resourceType: 'folder', resourceId: 'planning' }, - meta: { description: 'Second document' }, - }); - refetchedResource = await workos.fga.getResource(resource2); - expect(refetchedResource.resourceType).toEqual(resource2.resourceType); - expect(refetchedResource.resourceId).toEqual(resource2.resourceId); - expect(refetchedResource.meta).toEqual(resource2.meta); - - let resourcesList = await workos.fga.listResources({ limit: 10 }); - expect(resourcesList.data.length).toEqual(2); - expect(resourcesList.data[0].resourceType).toEqual(resource2.resourceType); - expect(resourcesList.data[0].resourceId).toEqual(resource2.resourceId); - expect(resourcesList.data[1].resourceType).toEqual(resource1.resourceType); - expect(resourcesList.data[1].resourceId).toEqual(resource1.resourceId); - - resourcesList = await workos.fga.listResources({ - limit: 10, - search: 'planning', - }); - expect(resourcesList.data.length).toEqual(1); - expect(resourcesList.data[0].resourceType).toEqual(resource2.resourceType); - expect(resourcesList.data[0].resourceId).toEqual(resource2.resourceId); - - await workos.fga.deleteResource(resource1); - await workos.fga.deleteResource(resource2); - resourcesList = await workos.fga.listResources({ limit: 10 }); - expect(resourcesList.data.length).toEqual(0); - }); - - it('multi-tenancy example', async () => { - // Create users - const user1 = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - const user2 = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - - // Create tenants - const tenant1 = await workos.fga.createResource({ - resource: { resourceType: 'tenant', resourceId: 'tenant-1' }, - meta: { name: 'Tenant 1' }, - }); - const tenant2 = await workos.fga.createResource({ - resource: { resourceType: 'tenant', resourceId: 'tenant-2' }, - meta: { name: 'Tenant 2' }, - }); - - let user1TenantsList = await workos.fga.query( - { - q: `select tenant where user:${user1.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(user1TenantsList.data.length).toEqual(0); - let tenant1UsersList = await workos.fga.query( - { - q: `select member of type user for tenant:${tenant1.resourceId}`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(tenant1UsersList.data.length).toEqual(0); - - // Assign user1 -> tenant1 - await workos.fga.writeWarrant({ - resource: tenant1, - relation: 'member', - subject: user1, - }); - - user1TenantsList = await workos.fga.query( - { - q: `select tenant where user:${user1.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(user1TenantsList.data.length).toEqual(1); - expect(user1TenantsList.data[0].resourceType).toEqual('tenant'); - expect(user1TenantsList.data[0].resourceId).toEqual('tenant-1'); - expect(user1TenantsList.data[0].meta).toEqual({ name: 'Tenant 1' }); - - tenant1UsersList = await workos.fga.query( - { - q: `select member of type user for tenant:${tenant1.resourceId}`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(tenant1UsersList.data.length).toEqual(1); - expect(tenant1UsersList.data[0].resourceType).toEqual('user'); - expect(tenant1UsersList.data[0].resourceId).toEqual(user1.resourceId); - expect(tenant1UsersList.data[0].meta).toBeUndefined(); - - // Remove user1 -> tenant1 - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: tenant1, - relation: 'member', - subject: user1, - }); - - user1TenantsList = await workos.fga.query( - { - q: `select tenant where user:${user1.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(user1TenantsList.data.length).toEqual(0); - tenant1UsersList = await workos.fga.query( - { - q: `select member of type user for tenant:${tenant1.resourceId}`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(tenant1UsersList.data.length).toEqual(0); - - // Clean up - await workos.fga.deleteResource(user1); - await workos.fga.deleteResource(user2); - await workos.fga.deleteResource(tenant1); - await workos.fga.deleteResource(tenant2); - }); - - it('RBAC example', async () => { - // Create users - const adminUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - const viewerUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - - // Create roles - const adminRole = await workos.fga.createResource({ - resource: { resourceType: 'role', resourceId: 'admin' }, - meta: { name: 'Admin', description: 'The admin role' }, - }); - const viewerRole = await workos.fga.createResource({ - resource: { resourceType: 'role', resourceId: 'viewer' }, - meta: { name: 'Viewer', description: 'The viewer role' }, - }); - - // Create permissions - const createPermission = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'create-report' }, - meta: { - name: 'Create Report', - description: 'Permission to create reports', - }, - }); - const viewPermission = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'view-report' }, - meta: { name: 'View Report', description: 'Permission to view reports' }, - }); - - let adminUserRolesList = await workos.fga.query( - { - q: `select role where user:${adminUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - let adminRolePermissionsList = await workos.fga.query( - { - q: `select permission where role:${adminRole.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(adminUserRolesList.data.length).toEqual(0); - expect(adminRolePermissionsList.data.length).toEqual(0); - - let adminUserHasPermission = await workos.fga.check( - { - checks: [ - { - resource: createPermission, - relation: 'member', - subject: adminUser, - }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(adminUserHasPermission.isAuthorized()).toEqual(false); - - // Assign 'create-report' -> admin role -> admin user - await workos.fga.writeWarrant({ - resource: createPermission, - relation: 'member', - subject: adminRole, - }); - await workos.fga.writeWarrant({ - resource: adminRole, - relation: 'member', - subject: adminUser, - }); - - adminUserHasPermission = await workos.fga.check( - { - checks: [ - { - resource: createPermission, - relation: 'member', - subject: adminUser, - }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(adminUserHasPermission.isAuthorized()).toEqual(true); - - adminUserRolesList = await workos.fga.query( - { - q: `select role where user:${adminUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(adminUserRolesList.data.length).toEqual(1); - expect(adminUserRolesList.data[0].resourceType).toEqual('role'); - expect(adminUserRolesList.data[0].resourceId).toEqual('admin'); - expect(adminUserRolesList.data[0].meta).toEqual({ - name: 'Admin', - description: 'The admin role', - }); - - adminRolePermissionsList = await workos.fga.query( - { - q: `select permission where role:${adminRole.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(adminRolePermissionsList.data.length).toEqual(1); - expect(adminRolePermissionsList.data[0].resourceType).toEqual('permission'); - expect(adminRolePermissionsList.data[0].resourceId).toEqual( - 'create-report', - ); - expect(adminRolePermissionsList.data[0].meta).toEqual({ - name: 'Create Report', - description: 'Permission to create reports', - }); - - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: createPermission, - relation: 'member', - subject: adminRole, - }); - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: adminRole, - relation: 'member', - subject: adminUser, - }); - - adminUserHasPermission = await workos.fga.check( - { - checks: [ - { - resource: createPermission, - relation: 'member', - subject: adminUser, - }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(adminUserHasPermission.isAuthorized()).toEqual(false); - - adminUserRolesList = await workos.fga.query( - { - q: `select role where user:${adminUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(adminUserRolesList.data.length).toEqual(0); - - adminRolePermissionsList = await workos.fga.query( - { - q: `select permission where role:${adminRole.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(adminRolePermissionsList.data.length).toEqual(0); - - // Assign 'view-report' -> viewer user - let viewerUserHasPermission = await workos.fga.check( - { - checks: [ - { resource: viewPermission, relation: 'member', subject: viewerUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserHasPermission.isAuthorized()).toEqual(false); - - let viewerUserPermissionsList = await workos.fga.query( - { - q: `select permission where user:${viewerUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserPermissionsList.data.length).toEqual(0); - - await workos.fga.writeWarrant({ - resource: viewPermission, - relation: 'member', - subject: viewerUser, - }); - - viewerUserHasPermission = await workos.fga.check( - { - checks: [ - { resource: viewPermission, relation: 'member', subject: viewerUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserHasPermission.isAuthorized()).toEqual(true); - - viewerUserPermissionsList = await workos.fga.query( - { - q: `select permission where user:${viewerUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserPermissionsList.data.length).toEqual(1); - expect(viewerUserPermissionsList.data[0].resourceType).toEqual( - 'permission', - ); - expect(viewerUserPermissionsList.data[0].resourceId).toEqual('view-report'); - expect(viewerUserPermissionsList.data[0].meta).toEqual({ - name: 'View Report', - description: 'Permission to view reports', - }); - - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: viewPermission, - relation: 'member', - subject: viewerUser, - }); - - viewerUserHasPermission = await workos.fga.check( - { - checks: [ - { resource: viewPermission, relation: 'member', subject: viewerUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserHasPermission.isAuthorized()).toEqual(false); - - viewerUserPermissionsList = await workos.fga.query( - { - q: `select permission where user:${viewerUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(viewerUserPermissionsList.data.length).toEqual(0); - - // Clean up - await workos.fga.deleteResource(adminUser); - await workos.fga.deleteResource(viewerUser); - await workos.fga.deleteResource(adminRole); - await workos.fga.deleteResource(viewerRole); - await workos.fga.deleteResource(createPermission); - await workos.fga.deleteResource(viewPermission); - }, 10000); - - it('pricing tiers, features, and users example', async () => { - // Create users - const freeUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - const paidUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - - // Create pricing tiers - const freeTier = await workos.fga.createResource({ - resource: { resourceType: 'pricing-tier', resourceId: 'free' }, - meta: { name: 'Free Tier' }, - }); - const paidTier = await workos.fga.createResource({ - resource: { resourceType: 'pricing-tier', resourceId: 'paid' }, - }); - - // Create features - const customFeature = await workos.fga.createResource({ - resource: { resourceType: 'feature', resourceId: 'custom-feature' }, - meta: { name: 'Custom Feature' }, - }); - const feature1 = await workos.fga.createResource({ - resource: { resourceType: 'feature', resourceId: 'feature-1' }, - }); - const feature2 = await workos.fga.createResource({ - resource: { resourceType: 'feature', resourceId: 'feature-2' }, - }); - - // Assign 'custom-feature' -> paid user - let paidUserHasFeature = await workos.fga.check( - { - checks: [ - { resource: customFeature, relation: 'member', subject: paidUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(paidUserHasFeature.isAuthorized()).toEqual(false); - - let paidUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${paidUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(paidUserFeaturesList.data.length).toEqual(0); - - await workos.fga.writeWarrant({ - resource: customFeature, - relation: 'member', - subject: paidUser, - }); - - paidUserHasFeature = await workos.fga.check( - { - checks: [ - { resource: customFeature, relation: 'member', subject: paidUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(paidUserHasFeature.isAuthorized()).toEqual(true); - - paidUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${paidUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(paidUserFeaturesList.data.length).toEqual(1); - expect(paidUserFeaturesList.data[0].resourceType).toEqual('feature'); - expect(paidUserFeaturesList.data[0].resourceId).toEqual('custom-feature'); - expect(paidUserFeaturesList.data[0].meta).toEqual({ - name: 'Custom Feature', - }); - - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: customFeature, - relation: 'member', - subject: paidUser, - }); - - paidUserHasFeature = await workos.fga.check( - { - checks: [ - { resource: customFeature, relation: 'member', subject: paidUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(paidUserHasFeature.isAuthorized()).toEqual(false); - - paidUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${paidUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(paidUserFeaturesList.data.length).toEqual(0); - - // Assign 'feature-1' -> 'free' tier -> free user - let freeUserHasFeature = await workos.fga.check( - { - checks: [{ resource: feature1, relation: 'member', subject: freeUser }], - }, - { warrantToken: 'latest' }, - ); - expect(freeUserHasFeature.isAuthorized()).toEqual(false); - - let freeUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserFeaturesList.data.length).toEqual(0); - - let freeUserTiersList = await workos.fga.query( - { - q: `select pricing-tier where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserTiersList.data.length).toEqual(0); - - await workos.fga.writeWarrant({ - resource: feature1, - relation: 'member', - subject: freeTier, - }); - await workos.fga.writeWarrant({ - resource: freeTier, - relation: 'member', - subject: freeUser, - }); - - freeUserHasFeature = await workos.fga.check( - { - checks: [{ resource: feature1, relation: 'member', subject: freeUser }], - }, - { warrantToken: 'latest' }, - ); - expect(freeUserHasFeature.isAuthorized()).toEqual(true); - - freeUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserFeaturesList.data.length).toEqual(1); - expect(freeUserFeaturesList.data[0].resourceType).toEqual('feature'); - expect(freeUserFeaturesList.data[0].resourceId).toEqual('feature-1'); - expect(freeUserFeaturesList.data[0].meta).toBeUndefined(); - - freeUserTiersList = await workos.fga.query( - { - q: `select pricing-tier where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserTiersList.data.length).toEqual(1); - expect(freeUserTiersList.data[0].resourceType).toEqual('pricing-tier'); - expect(freeUserTiersList.data[0].resourceId).toEqual('free'); - expect(freeUserTiersList.data[0].meta).toEqual({ name: 'Free Tier' }); - - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: feature1, - relation: 'member', - subject: freeTier, - }); - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: freeTier, - relation: 'member', - subject: freeUser, - }); - - freeUserHasFeature = await workos.fga.check( - { - checks: [{ resource: feature1, relation: 'member', subject: freeUser }], - }, - { warrantToken: 'latest' }, - ); - expect(freeUserHasFeature.isAuthorized()).toEqual(false); - - freeUserFeaturesList = await workos.fga.query( - { - q: `select feature where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserFeaturesList.data.length).toEqual(0); - - freeUserTiersList = await workos.fga.query( - { - q: `select pricing-tier where user:${freeUser.resourceId} is member`, - limit: 10, - }, - { warrantToken: 'latest' }, - ); - expect(freeUserTiersList.data.length).toEqual(0); - - // Clean up - await workos.fga.deleteResource(freeUser); - await workos.fga.deleteResource(paidUser); - await workos.fga.deleteResource(freeTier); - await workos.fga.deleteResource(paidTier); - await workos.fga.deleteResource(customFeature); - await workos.fga.deleteResource(feature1); - await workos.fga.deleteResource(feature2); - }, 10000); - - it('warrants', async () => { - const user1 = await workos.fga.createResource({ - resource: { resourceType: 'user', resourceId: 'userA' }, - }); - const user2 = await workos.fga.createResource({ - resource: { resourceType: 'user', resourceId: 'userB' }, - }); - const newPermission = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm1' }, - meta: { name: 'Permission 1', description: 'Permission 1' }, - }); - - let userHasPermission = await workos.fga.check( - { - checks: [ - { resource: newPermission, relation: 'member', subject: user1 }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermission.isAuthorized()).toEqual(false); - - const warrant1 = await workos.fga.writeWarrant({ - resource: newPermission, - relation: 'member', - subject: user1, - }); - expect(warrant1.warrantToken).toBeDefined(); - const warrant2 = await workos.fga.writeWarrant({ - resource: newPermission, - relation: 'member', - subject: user2, - policy: 'region == "us"', - }); - expect(warrant2.warrantToken).toBeDefined(); - - const warrants1 = await workos.fga.listWarrants( - { limit: 1 }, - { warrantToken: 'latest' }, - ); - expect(warrants1.data.length).toEqual(1); - expect(warrants1.data[0].resourceType).toEqual('permission'); - expect(warrants1.data[0].resourceId).toEqual('perm1'); - expect(warrants1.data[0].relation).toEqual('member'); - expect(warrants1.data[0].subject.resourceType).toEqual('user'); - expect(warrants1.data[0].subject.resourceId).toEqual(user2.resourceId); - expect(warrants1.data[0].policy).toEqual('region == "us"'); - - const warrants2 = await workos.fga.listWarrants( - { - limit: 1, - after: warrants1.listMetadata.after, - }, - { warrantToken: 'latest' }, - ); - expect(warrants2.data.length).toEqual(1); - expect(warrants2.data[0].resourceType).toEqual('permission'); - expect(warrants2.data[0].resourceId).toEqual('perm1'); - expect(warrants2.data[0].relation).toEqual('member'); - expect(warrants2.data[0].subject.resourceType).toEqual('user'); - expect(warrants2.data[0].subject.resourceId).toEqual(user1.resourceId); - - const warrants3 = await workos.fga.listWarrants( - { subjectType: 'user', subjectId: user1.resourceId }, - { warrantToken: 'latest' }, - ); - expect(warrants3.data.length).toEqual(1); - expect(warrants3.data[0].resourceType).toEqual('permission'); - expect(warrants3.data[0].resourceId).toEqual('perm1'); - expect(warrants3.data[0].relation).toEqual('member'); - expect(warrants3.data[0].subject.resourceType).toEqual('user'); - expect(warrants3.data[0].subject.resourceId).toEqual(user1.resourceId); - - userHasPermission = await workos.fga.check( - { - checks: [ - { resource: newPermission, relation: 'member', subject: user1 }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermission.isAuthorized()).toEqual(true); - - const query = `select permission where user:${user1.resourceId} is member`; - const response = await workos.fga.query( - { q: query }, - { warrantToken: 'latest' }, - ); - expect(response.data.length).toEqual(1); - expect(response.data[0].resourceType).toEqual('permission'); - expect(response.data[0].resourceId).toEqual('perm1'); - expect(response.data[0].relation).toEqual('member'); - - await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: newPermission, - relation: 'member', - subject: user1, - }); - - userHasPermission = await workos.fga.check( - { - checks: [ - { resource: newPermission, relation: 'member', subject: user1 }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermission.isAuthorized()).toEqual(false); - - // Clean up - await workos.fga.deleteResource(user1); - await workos.fga.deleteResource(user2); - await workos.fga.deleteResource(newPermission); - }); - - it('check many warrants', async () => { - const newUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - const permission1 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm1' }, - meta: { name: 'Permission 1', description: 'Permission 1' }, - }); - const permission2 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm2' }, - meta: { name: 'Permission 2', description: 'Permission 2' }, - }); - - const userHasPermissions = await workos.fga.check( - { - op: CheckOp.AnyOf, - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermissions.isAuthorized()).toEqual(false); - - let warrantResponse = await workos.fga.writeWarrant({ - resource: permission1, - relation: 'member', - subject: newUser, - }); - expect(warrantResponse.warrantToken).toBeDefined(); - - let userHasAtLeastOnePermission = await workos.fga.check( - { - op: CheckOp.AnyOf, - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasAtLeastOnePermission.isAuthorized()).toEqual(true); - - let userHasAllPermissions = await workos.fga.check( - { - op: CheckOp.AllOf, - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasAllPermissions.isAuthorized()).toEqual(false); - - warrantResponse = await workos.fga.writeWarrant({ - resource: permission2, - relation: 'member', - subject: newUser, - }); - expect(warrantResponse.warrantToken).toBeDefined(); - - userHasAtLeastOnePermission = await workos.fga.check( - { - op: CheckOp.AnyOf, - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasAtLeastOnePermission.isAuthorized()).toEqual(true); - - userHasAllPermissions = await workos.fga.check( - { - op: CheckOp.AllOf, - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasAllPermissions.isAuthorized()).toEqual(true); - - warrantResponse = await workos.fga.batchWriteWarrants([ - { - op: WarrantOp.Delete, - resource: permission1, - relation: 'member', - subject: newUser, - }, - { - op: WarrantOp.Delete, - resource: permission2, - relation: 'member', - subject: newUser, - }, - ]); - expect(warrantResponse.warrantToken).toBeDefined(); - - // Clean up - await workos.fga.deleteResource(newUser); - await workos.fga.deleteResource(permission1); - await workos.fga.deleteResource(permission2); - }); - - it('batch create/delete/check warrants', async () => { - const newUser = await workos.fga.createResource({ - resource: { resourceType: 'user' }, - }); - const permission1 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm1' }, - meta: { name: 'Permission 1', description: 'Permission 1' }, - }); - const permission2 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm2' }, - meta: { name: 'Permission 2', description: 'Permission 2' }, - }); - - let userHasPermissions = await workos.fga.checkBatch( - { - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermissions[0].isAuthorized()).toEqual(false); - expect(userHasPermissions[1].isAuthorized()).toEqual(false); - - const warrants = await workos.fga.batchWriteWarrants([ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ]); - expect(warrants.warrantToken).toBeDefined(); - - userHasPermissions = await workos.fga.checkBatch( - { - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermissions[0].isAuthorized()).toEqual(true); - expect(userHasPermissions[1].isAuthorized()).toEqual(true); - - const warrantToken = await workos.fga.batchWriteWarrants([ - { - op: WarrantOp.Delete, - resource: permission1, - relation: 'member', - subject: newUser, - }, - { - op: WarrantOp.Delete, - resource: permission2, - relation: 'member', - subject: newUser, - }, - ]); - expect(warrantToken).toBeDefined(); - - userHasPermissions = await workos.fga.checkBatch( - { - checks: [ - { resource: permission1, relation: 'member', subject: newUser }, - { resource: permission2, relation: 'member', subject: newUser }, - ], - }, - { warrantToken: 'latest' }, - ); - expect(userHasPermissions[0].isAuthorized()).toEqual(false); - expect(userHasPermissions[1].isAuthorized()).toEqual(false); - - await workos.fga.deleteResource(newUser); - await workos.fga.deleteResource(permission1); - await workos.fga.deleteResource(permission2); - }); - - it('warrant with policy', async () => { - let writeResult = await workos.fga.writeWarrant({ - resource: { resourceType: 'permission', resourceId: 'test-permission' }, - relation: 'member', - subject: { resourceType: 'user', resourceId: 'user-1' }, - policy: `geo == "us"`, - }); - expect(writeResult.warrantToken).toBeDefined(); - - let checkResult = await workos.fga.check( - { - checks: [ - { - resource: { - resourceType: 'permission', - resourceId: 'test-permission', - }, - relation: 'member', - subject: { resourceType: 'user', resourceId: 'user-1' }, - context: { geo: 'us' }, - }, - ], - }, - { - warrantToken: 'latest', - }, - ); - expect(checkResult.isAuthorized()).toEqual(true); - - checkResult = await workos.fga.check( - { - checks: [ - { - resource: { - resourceType: 'permission', - resourceId: 'test-permission', - }, - relation: 'member', - subject: { resourceType: 'user', resourceId: 'user-1' }, - context: { geo: 'eu' }, - }, - ], - }, - { - warrantToken: 'latest', - }, - ); - expect(checkResult.isAuthorized()).toEqual(false); - - writeResult = await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: { resourceType: 'permission', resourceId: 'test-permission' }, - relation: 'member', - subject: { resourceType: 'user', resourceId: 'user-1' }, - policy: `geo == "us"`, - }); - expect(writeResult.warrantToken).toBeDefined(); - - // Clean up - await workos.fga.deleteResource({ - resourceType: 'permission', - resourceId: 'test-permission', - }); - await workos.fga.deleteResource({ - resourceType: 'user', - resourceId: 'user-1', - }); - }); - - it('query', async () => { - const userA = await workos.fga.createResource({ - resource: { resourceType: 'user', resourceId: 'userA' }, - }); - const userB = await workos.fga.createResource({ - resource: { resourceType: 'user', resourceId: 'userB' }, - }); - const permission1 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm1' }, - meta: { name: 'Permission 1', description: 'This is permission 1.' }, - }); - const permission2 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm2' }, - }); - const permission3 = await workos.fga.createResource({ - resource: { resourceType: 'permission', resourceId: 'perm3' }, - meta: { name: 'Permission 3', description: 'This is permission 3.' }, - }); - const role1 = await workos.fga.createResource({ - resource: { resourceType: 'role', resourceId: 'role1' }, - meta: { name: 'Role 1', description: 'This is role 1.' }, - }); - const role2 = await workos.fga.createResource({ - resource: { resourceType: 'role', resourceId: 'role2' }, - meta: { name: 'Role 2' }, - }); - - await workos.fga.writeWarrant({ - resource: permission1, - relation: 'member', - subject: role1, - }); - await workos.fga.writeWarrant({ - resource: permission2, - relation: 'member', - subject: role2, - }); - await workos.fga.writeWarrant({ - resource: permission3, - relation: 'member', - subject: role2, - }); - await workos.fga.writeWarrant({ - resource: role2, - relation: 'member', - subject: role1, - }); - await workos.fga.writeWarrant({ - resource: permission1, - relation: 'member', - subject: role2, - policy: 'tenantId == 123', - }); - await workos.fga.writeWarrant({ - resource: role1, - relation: 'member', - subject: userA, - }); - await workos.fga.writeWarrant({ - resource: role2, - relation: 'member', - subject: userB, - }); - - let resultSet = await workos.fga.query( - { q: 'select role where user:userA is member', limit: 1, order: 'asc' }, - { warrantToken: 'latest' }, - ); - expect(resultSet.data.length).toEqual(1); - expect(resultSet.data[0].resourceType).toEqual('role'); - expect(resultSet.data[0].resourceId).toEqual('role1'); - expect(resultSet.data[0].relation).toEqual('member'); - expect(resultSet.data[0].warrant.resourceType).toEqual('role'); - expect(resultSet.data[0].warrant.resourceId).toEqual('role1'); - expect(resultSet.data[0].warrant.relation).toEqual('member'); - expect(resultSet.data[0].warrant.subject.resourceType).toEqual('user'); - expect(resultSet.data[0].warrant.subject.resourceId).toEqual('userA'); - expect(resultSet.data[0].warrant.policy).toBeUndefined(); - expect(resultSet.data[0].isImplicit).toEqual(false); - - resultSet = await workos.fga.query( - { - q: 'select role where user:userA is member', - limit: 1, - order: 'asc', - after: resultSet.listMetadata.after, - }, - { warrantToken: 'latest' }, - ); - expect(resultSet.data.length).toEqual(1); - expect(resultSet.data[0].resourceType).toEqual('role'); - expect(resultSet.data[0].resourceId).toEqual('role2'); - expect(resultSet.data[0].relation).toEqual('member'); - expect(resultSet.data[0].warrant.resourceType).toEqual('role'); - expect(resultSet.data[0].warrant.resourceId).toEqual('role2'); - expect(resultSet.data[0].warrant.relation).toEqual('member'); - expect(resultSet.data[0].warrant.subject.resourceType).toEqual('role'); - expect(resultSet.data[0].warrant.subject.resourceId).toEqual('role1'); - expect(resultSet.data[0].warrant.policy).toBeUndefined(); - expect(resultSet.data[0].isImplicit).toEqual(true); - - resultSet = await workos.fga.query( - { - q: 'select permission where user:userB is member', - context: { tenantId: 123 }, - order: 'asc', - }, - { warrantToken: 'latest' }, - ); - expect(resultSet.data.length).toEqual(3); - expect(resultSet.data[0].resourceType).toEqual('permission'); - expect(resultSet.data[0].resourceId).toEqual('perm1'); - expect(resultSet.data[0].relation).toEqual('member'); - expect(resultSet.data[1].resourceType).toEqual('permission'); - expect(resultSet.data[1].resourceId).toEqual('perm2'); - expect(resultSet.data[1].relation).toEqual('member'); - expect(resultSet.data[2].resourceType).toEqual('permission'); - expect(resultSet.data[2].resourceId).toEqual('perm3'); - expect(resultSet.data[2].relation).toEqual('member'); - - // Clean up - await workos.fga.deleteResource(role1); - await workos.fga.deleteResource(role2); - await workos.fga.deleteResource(permission1); - await workos.fga.deleteResource(permission2); - await workos.fga.deleteResource(permission3); - await workos.fga.deleteResource(userA); - await workos.fga.deleteResource(userB); - }); - - it('batch write resources', async () => { - const objects = await workos.fga.batchWriteResources({ - op: ResourceOp.Create, - resources: [ - { - resource: { - resourceType: 'user', - resourceId: 'user1', - }, - }, - { - resource: { - resourceType: 'user', - resourceId: 'user2', - }, - }, - { - resource: { - resourceType: 'tenant', - resourceId: 'tenantA', - }, - meta: { - name: 'Tenant A', - }, - }, - ], - }); - expect(objects.length).toEqual(3); - expect(objects[0].resourceType).toEqual('user'); - expect(objects[0].resourceId).toEqual('user1'); - expect(objects[1].resourceType).toEqual('user'); - expect(objects[1].resourceId).toEqual('user2'); - expect(objects[2].resourceType).toEqual('tenant'); - expect(objects[2].resourceId).toEqual('tenantA'); - expect(objects[2].meta).toEqual({ name: 'Tenant A' }); - - await workos.fga.batchWriteResources({ - op: ResourceOp.Delete, - resources: [ - { - resourceType: 'user', - resourceId: 'user1', - }, - { - resourceType: 'user', - resourceId: 'user2', - }, - { - resourceType: 'tenant', - resourceId: 'tenantA', - }, - ], - }); - }); -}); diff --git a/src/fga/fga.spec.ts b/src/fga/fga.spec.ts deleted file mode 100644 index 45f44fa40..000000000 --- a/src/fga/fga.spec.ts +++ /dev/null @@ -1,809 +0,0 @@ -import fetch from 'jest-fetch-mock'; -import { - fetchBody, - fetchHeaders, - fetchOnce, - fetchSearchParams, - fetchURL, -} from '../common/utils/test-utils'; - -import { WorkOS } from '../workos'; -import { ResourceOp, WarrantOp } from './interfaces'; - -const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU'); - -describe('FGA', () => { - beforeEach(() => fetch.resetMocks()); - - describe('check', () => { - it('makes check request', async () => { - fetchOnce({ - result: 'authorized', - is_implicit: false, - warrant_token: 'abc', - }); - const checkResult = await workos.fga.check({ - checks: [ - { - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - ], - }); - expect(fetchURL()).toContain('/fga/v1/check'); - expect(checkResult).toMatchObject({ - result: 'authorized', - isImplicit: false, - warrantToken: 'abc', - }); - }); - - it('deserializes warnings in check response', async () => { - fetchOnce({ - result: 'authorized', - is_implicit: false, - warrant_token: 'abc', - warnings: [ - { - code: 'missing_context_keys', - message: 'Missing required context keys', - keys: ['tenant_id', 'region'], - }, - { - code: 'some_other_warning', - message: 'Some other warning message', - }, - ], - }); - const checkResult = await workos.fga.check({ - checks: [ - { - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - ], - }); - expect(fetchURL()).toContain('/fga/v1/check'); - expect(checkResult).toMatchObject({ - result: 'authorized', - isImplicit: false, - warrantToken: 'abc', - warnings: [ - { - code: 'missing_context_keys', - message: 'Missing required context keys', - keys: ['tenant_id', 'region'], - }, - { - code: 'some_other_warning', - message: 'Some other warning message', - }, - ], - }); - }); - }); - - describe('createResource', () => { - it('creates resource', async () => { - fetchOnce({ - resource_type: 'role', - resource_id: 'admin', - }); - const resource = await workos.fga.createResource({ - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - }); - expect(fetchURL()).toContain('/fga/v1/resources'); - expect(resource).toMatchObject({ - resourceType: 'role', - resourceId: 'admin', - }); - }); - - it('creates resource with metadata', async () => { - fetchOnce({ - resource_type: 'role', - resource_id: 'admin', - meta: { - description: 'The admin role', - }, - }); - const resource = await workos.fga.createResource({ - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - meta: { - description: 'The admin role', - }, - }); - expect(fetchURL()).toContain('/fga/v1/resources'); - expect(resource).toMatchObject({ - resourceType: 'role', - resourceId: 'admin', - meta: { - description: 'The admin role', - }, - }); - }); - }); - - describe('getResource', () => { - it('gets resource', async () => { - fetchOnce({ - resource_type: 'role', - resource_id: 'admin', - }); - const resource = await workos.fga.getResource({ - resourceType: 'role', - resourceId: 'admin', - }); - expect(fetchURL()).toContain('/fga/v1/resources/role/admin'); - expect(resource).toMatchObject({ - resourceType: 'role', - resourceId: 'admin', - }); - }); - }); - - describe('listResources', () => { - it('lists resources', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - }, - { - resource_type: 'role', - resource_id: 'manager', - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - const { data: resources } = await workos.fga.listResources(); - expect(fetchURL()).toContain('/fga/v1/resources'); - expect(resources).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - }, - { - resourceType: 'role', - resourceId: 'manager', - }, - ]); - }); - - it('sends correct params when filtering', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - }, - { - resource_type: 'role', - resource_id: 'manager', - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - await workos.fga.listResources({ - resourceType: 'role', - }); - expect(fetchURL()).toContain('/fga/v1/resources'); - expect(fetchSearchParams()).toEqual({ - resource_type: 'role', - order: 'desc', - }); - }); - }); - - describe('deleteResource', () => { - it('should delete resource', async () => { - fetchOnce(); - const response = await workos.fga.deleteResource({ - resourceType: 'role', - resourceId: 'admin', - }); - expect(fetchURL()).toContain('/fga/v1/resources/role/admin'); - expect(response).toBeUndefined(); - }); - }); - - describe('batchWriteResources', () => { - it('batch create resources', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - meta: { - description: 'The admin role', - }, - }, - { - resource_type: 'role', - resource_id: 'manager', - }, - { - resource_type: 'role', - resource_id: 'employee', - }, - ], - }); - const createdResources = await workos.fga.batchWriteResources({ - op: ResourceOp.Create, - resources: [ - { - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - meta: { - description: 'The admin role', - }, - }, - { - resource: { - resourceType: 'role', - resourceId: 'manager', - }, - }, - { - resource: { - resourceType: 'role', - resourceId: 'employee', - }, - }, - ], - }); - expect(fetchURL()).toContain('/fga/v1/resources/batch'); - expect(createdResources).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - meta: { - description: 'The admin role', - }, - }, - { - resourceType: 'role', - resourceId: 'manager', - }, - { - resourceType: 'role', - resourceId: 'employee', - }, - ]); - }); - - it('batch delete resources', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - }, - { - resource_type: 'role', - resource_id: 'manager', - }, - { - resource_type: 'role', - resource_id: 'employee', - }, - ], - }); - const deletedResources = await workos.fga.batchWriteResources({ - op: ResourceOp.Delete, - resources: [ - { - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - meta: { - description: 'The admin role', - }, - }, - { - resource: { - resourceType: 'role', - resourceId: 'manager', - }, - }, - { - resource: { - resourceType: 'role', - resourceId: 'employee', - }, - }, - ], - }); - expect(fetchURL()).toContain('/fga/v1/resources/batch'); - expect(deletedResources).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - }, - { - resourceType: 'role', - resourceId: 'manager', - }, - { - resourceType: 'role', - resourceId: 'employee', - }, - ]); - }); - }); - - describe('writeWarrant', () => { - it('should create warrant with no op', async () => { - fetchOnce({ - warrant_token: 'some_token', - }); - const warrantToken = await workos.fga.writeWarrant({ - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(fetchBody()).toEqual({ - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }); - expect(warrantToken).toMatchObject({ - warrantToken: 'some_token', - }); - }); - - it('should create warrant with create op', async () => { - fetchOnce({ - warrant_token: 'some_token', - }); - const warrantToken = await workos.fga.writeWarrant({ - op: WarrantOp.Create, - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(fetchBody()).toEqual({ - op: 'create', - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }); - expect(warrantToken).toMatchObject({ - warrantToken: 'some_token', - }); - }); - - it('should delete warrant with delete op', async () => { - fetchOnce({ - warrant_token: 'some_token', - }); - const warrantToken = await workos.fga.writeWarrant({ - op: WarrantOp.Delete, - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(fetchBody()).toEqual({ - op: 'delete', - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }); - expect(warrantToken).toMatchObject({ - warrantToken: 'some_token', - }); - }); - }); - - describe('batchWriteWarrants', () => { - it('should create warrants with no op or create op and delete warrants with delete op', async () => { - fetchOnce({ - warrant_token: 'some_token', - }); - const warrantToken = await workos.fga.batchWriteWarrants([ - { - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - { - op: WarrantOp.Create, - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_124', - }, - }, - { - op: WarrantOp.Delete, - resource: { - resourceType: 'role', - resourceId: 'admin', - }, - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_125', - }, - }, - ]); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(fetchBody()).toEqual([ - { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - { - op: 'create', - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_124', - }, - }, - { - op: 'delete', - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_125', - }, - }, - ]); - expect(warrantToken).toMatchObject({ - warrantToken: 'some_token', - }); - }); - }); - - describe('listWarrants', () => { - it('should list warrants', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_124', - }, - policy: 'region == "us"', - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - const { data: warrants } = await workos.fga.listWarrants(); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(warrants).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - { - resourceType: 'role', - resourceId: 'admin', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_124', - }, - policy: 'region == "us"', - }, - ]); - }); - - it('sends correct params when filtering', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - await workos.fga.listWarrants({ - subjectType: 'user', - subjectId: 'user_123', - }); - expect(fetchURL()).toContain('/fga/v1/warrants'); - expect(fetchSearchParams()).toEqual({ - subject_type: 'user', - subject_id: 'user_123', - order: 'desc', - }); - }); - }); - - describe('query', () => { - it('makes query request', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - warrant: { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - is_implicit: false, - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - const { data: queryResults } = await workos.fga.query({ - q: 'select role where user:user_123 is member', - }); - expect(fetchURL()).toContain('/fga/v1/query'); - expect(queryResults).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - warrant: { - resourceType: 'role', - resourceId: 'admin', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - isImplicit: false, - }, - ]); - }); - - it('deserializes warnings in query response', async () => { - fetchOnce({ - data: [ - { - resource_type: 'role', - resource_id: 'admin', - warrant: { - resource_type: 'role', - resource_id: 'admin', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - is_implicit: false, - }, - { - resource_type: 'role', - resource_id: 'manager', - warrant: { - resource_type: 'role', - resource_id: 'manager', - relation: 'member', - subject: { - resource_type: 'user', - resource_id: 'user_123', - }, - }, - is_implicit: true, - }, - ], - list_metadata: { - before: null, - after: null, - }, - warnings: [ - { - code: 'missing_context_keys', - message: 'Missing required context keys', - keys: ['tenant_id'], - }, - { - code: 'some_other_warning', - message: 'Some other warning message', - }, - ], - }); - const result = await workos.fga.query({ - q: 'select role where user:user_123 is member', - }); - expect(fetchURL()).toContain('/fga/v1/query'); - expect(result.data).toMatchObject([ - { - resourceType: 'role', - resourceId: 'admin', - warrant: { - resourceType: 'role', - resourceId: 'admin', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - isImplicit: false, - }, - { - resourceType: 'role', - resourceId: 'manager', - warrant: { - resourceType: 'role', - resourceId: 'manager', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - isImplicit: true, - }, - ]); - expect(result.warnings).toMatchObject([ - { - code: 'missing_context_keys', - message: 'Missing required context keys', - keys: ['tenant_id'], - }, - { - code: 'some_other_warning', - message: 'Some other warning message', - }, - ]); - }); - - it('sends correct params and options', async () => { - fetchOnce({ - data: [ - { - resourceType: 'role', - resourceId: 'admin', - warrant: { - resourceType: 'role', - resourceId: 'admin', - relation: 'member', - subject: { - resourceType: 'user', - resourceId: 'user_123', - }, - }, - isImplicit: false, - }, - ], - list_metadata: { - before: null, - after: null, - }, - }); - await workos.fga.query( - { - q: 'select role where user:user_123 is member', - order: 'asc', - }, - { - warrantToken: 'some_token', - }, - ); - expect(fetchURL()).toContain('/fga/v1/query'); - expect(fetchSearchParams()).toEqual({ - q: 'select role where user:user_123 is member', - order: 'asc', - }); - expect(fetchHeaders()).toMatchObject({ - 'Warrant-Token': 'some_token', - }); - }); - }); -}); diff --git a/src/fga/fga.ts b/src/fga/fga.ts deleted file mode 100644 index d649c4103..000000000 --- a/src/fga/fga.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { WorkOS } from '../workos'; -import { - Resource, - CheckBatchOptions, - CheckOptions, - CheckRequestOptions, - CheckResult, - CheckResultResponse, - CreateResourceOptions, - DeleteResourceOptions, - ListResourcesOptions, - ListWarrantsRequestOptions, - ListWarrantsOptions, - QueryOptions, - QueryRequestOptions, - QueryResult, - QueryResultResponse, - ResourceInterface, - ResourceOptions, - ResourceResponse, - UpdateResourceOptions, - WriteWarrantOptions, - Warrant, - WarrantResponse, - WarrantToken, - WarrantTokenResponse, - BatchWriteResourcesOptions, - BatchWriteResourcesResponse, - SerializedListWarrantsOptions, - SerializedListResourcesOptions, - SerializedQueryOptions, -} from './interfaces'; -import { - deserializeBatchWriteResourcesResponse, - deserializeResource, - deserializeWarrant, - deserializeWarrantToken, - deserializeQueryResult, - serializeBatchWriteResourcesOptions, - serializeCheckBatchOptions, - serializeCheckOptions, - serializeCreateResourceOptions, - serializeListResourceOptions, - serializeListWarrantsOptions, - serializeQueryOptions, - serializeWriteWarrantOptions, -} from './serializers'; -import { isResourceInterface } from './utils/interface-check'; -import { AutoPaginatable } from '../common/utils/pagination'; -import { fetchAndDeserialize } from '../common/utils/fetch-and-deserialize'; -import { FgaPaginatable } from './utils/fga-paginatable'; -import { fetchAndDeserializeFGAList } from './utils/fetch-and-deserialize-list'; - -/** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ -export class FGA { - constructor(private readonly workos: WorkOS) {} - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async check( - checkOptions: CheckOptions, - options: CheckRequestOptions = {}, - ): Promise { - const { data } = await this.workos.post( - `/fga/v1/check`, - serializeCheckOptions(checkOptions), - options, - ); - return new CheckResult(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async checkBatch( - checkOptions: CheckBatchOptions, - options: CheckRequestOptions = {}, - ): Promise { - const { data } = await this.workos.post( - `/fga/v1/check`, - serializeCheckBatchOptions(checkOptions), - options, - ); - return data.map( - (checkResult: CheckResultResponse) => new CheckResult(checkResult), - ); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async createResource(resource: CreateResourceOptions): Promise { - const { data } = await this.workos.post( - '/fga/v1/resources', - serializeCreateResourceOptions(resource), - ); - - return deserializeResource(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async getResource( - resource: ResourceInterface | ResourceOptions, - ): Promise { - const resourceType = isResourceInterface(resource) - ? resource.getResourceType() - : resource.resourceType; - const resourceId = isResourceInterface(resource) - ? resource.getResourceId() - : resource.resourceId; - - const { data } = await this.workos.get( - `/fga/v1/resources/${resourceType}/${resourceId}`, - ); - - return deserializeResource(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async listResources( - options?: ListResourcesOptions, - ): Promise> { - return new AutoPaginatable( - await fetchAndDeserialize( - this.workos, - '/fga/v1/resources', - deserializeResource, - options ? serializeListResourceOptions(options) : undefined, - ), - (params) => - fetchAndDeserialize( - this.workos, - '/fga/v1/resources', - deserializeResource, - params, - ), - options ? serializeListResourceOptions(options) : undefined, - ); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async updateResource(options: UpdateResourceOptions): Promise { - const resourceType = isResourceInterface(options.resource) - ? options.resource.getResourceType() - : options.resource.resourceType; - const resourceId = isResourceInterface(options.resource) - ? options.resource.getResourceId() - : options.resource.resourceId; - - const { data } = await this.workos.put( - `/fga/v1/resources/${resourceType}/${resourceId}`, - { - meta: options.meta, - }, - ); - - return deserializeResource(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async deleteResource(resource: DeleteResourceOptions): Promise { - const resourceType = isResourceInterface(resource) - ? resource.getResourceType() - : resource.resourceType; - const resourceId = isResourceInterface(resource) - ? resource.getResourceId() - : resource.resourceId; - - await this.workos.delete(`/fga/v1/resources/${resourceType}/${resourceId}`); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async batchWriteResources( - options: BatchWriteResourcesOptions, - ): Promise { - const { data } = await this.workos.post( - '/fga/v1/resources/batch', - serializeBatchWriteResourcesOptions(options), - ); - return deserializeBatchWriteResourcesResponse(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async writeWarrant(options: WriteWarrantOptions): Promise { - const { data } = await this.workos.post( - '/fga/v1/warrants', - serializeWriteWarrantOptions(options), - ); - - return deserializeWarrantToken(data); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async batchWriteWarrants( - options: WriteWarrantOptions[], - ): Promise { - const { data: warrantToken } = await this.workos.post( - '/fga/v1/warrants', - options.map(serializeWriteWarrantOptions), - ); - - return deserializeWarrantToken(warrantToken); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async listWarrants( - options?: ListWarrantsOptions, - requestOptions?: ListWarrantsRequestOptions, - ): Promise> { - return new AutoPaginatable( - await fetchAndDeserialize( - this.workos, - '/fga/v1/warrants', - deserializeWarrant, - options ? serializeListWarrantsOptions(options) : undefined, - requestOptions, - ), - (params) => - fetchAndDeserialize( - this.workos, - '/fga/v1/warrants', - deserializeWarrant, - params, - requestOptions, - ), - options ? serializeListWarrantsOptions(options) : undefined, - ); - } - - /** - * @deprecated The FGA module is deprecated. Use the Authorization module instead. - * @see src/authorization/authorization.ts - */ - async query( - options: QueryOptions, - requestOptions: QueryRequestOptions = {}, - ): Promise> { - return new FgaPaginatable( - await fetchAndDeserializeFGAList( - this.workos, - '/fga/v1/query', - deserializeQueryResult, - serializeQueryOptions(options), - requestOptions, - ), - (params) => - fetchAndDeserializeFGAList( - this.workos, - '/fga/v1/query', - deserializeQueryResult, - params, - requestOptions, - ), - serializeQueryOptions(options), - ); - } -} diff --git a/src/fga/interfaces/check-op.enum.ts b/src/fga/interfaces/check-op.enum.ts deleted file mode 100644 index d3e2896ca..000000000 --- a/src/fga/interfaces/check-op.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum CheckOp { - AllOf = 'all_of', - AnyOf = 'any_of', -} diff --git a/src/fga/interfaces/check.interface.ts b/src/fga/interfaces/check.interface.ts deleted file mode 100644 index d49f07d8d..000000000 --- a/src/fga/interfaces/check.interface.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { ResourceInterface, ResourceOptions } from './resource.interface'; -import { PolicyContext, SerializedSubject, Subject } from './warrant.interface'; -import { CheckOp } from './check-op.enum'; -import { PostOptions } from '../../common/interfaces'; -import { deserializeDecisionTreeNode } from '../serializers/check-options.serializer'; -import { Warning } from './warning.interface'; - -const CHECK_RESULT_AUTHORIZED = 'authorized'; - -export interface CheckWarrantOptions { - resource: ResourceInterface | ResourceOptions; - relation: string; - subject: ResourceInterface | Subject; - context?: PolicyContext; -} - -export interface SerializedCheckWarrantOptions { - resource_type: string; - resource_id: string; - relation: string; - subject: SerializedSubject; - context: PolicyContext; -} - -export interface CheckOptions { - op?: CheckOp; - checks: CheckWarrantOptions[]; - debug?: boolean; -} - -export interface CheckBatchOptions { - checks: CheckWarrantOptions[]; - debug?: boolean; -} - -export interface SerializedCheckOptions { - op?: CheckOp; - checks: SerializedCheckWarrantOptions[]; - debug?: boolean; -} - -export interface SerializedCheckBatchOptions { - op: 'batch'; - checks: SerializedCheckWarrantOptions[]; - debug?: boolean; -} - -export interface CheckResultResponse { - result: string; - is_implicit: boolean; - warrant_token: string; - debug_info?: DebugInfoResponse; - warnings?: Warning[]; -} - -export interface DebugInfo { - processingTime: number; - decisionTree: DecisionTreeNode; -} - -export interface DecisionTreeNode { - check: CheckWarrantOptions; - policy?: string; - decision: string; - processingTime: number; - children: DecisionTreeNode[]; -} - -export interface DebugInfoResponse { - processing_time: number; - decision_tree: DecisionTreeNodeResponse; -} - -export interface DecisionTreeNodeResponse { - check: SerializedCheckWarrantOptions; - policy?: string; - decision: string; - processing_time: number; - children: DecisionTreeNodeResponse[]; -} - -export interface CheckResultInterface { - result: string; - isImplicit: boolean; - warrantToken: string; - debugInfo?: DebugInfo; - warnings?: Warning[]; -} - -export class CheckResult implements CheckResultInterface { - public result: string; - public isImplicit: boolean; - public warrantToken: string; - public debugInfo?: DebugInfo; - public warnings?: Warning[]; - - constructor(json: CheckResultResponse) { - this.result = json.result; - this.isImplicit = json.is_implicit; - this.warrantToken = json.warrant_token; - this.debugInfo = json.debug_info - ? { - processingTime: json.debug_info.processing_time, - decisionTree: deserializeDecisionTreeNode( - json.debug_info.decision_tree, - ), - } - : undefined; - this.warnings = json.warnings; - } - - isAuthorized(): boolean { - return this.result === CHECK_RESULT_AUTHORIZED; - } -} - -export type CheckRequestOptions = Pick; diff --git a/src/fga/interfaces/index.ts b/src/fga/interfaces/index.ts deleted file mode 100644 index 0c94e50fe..000000000 --- a/src/fga/interfaces/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from './check-op.enum'; -export * from './check.interface'; -export * from './query.interface'; -export * from './resource-op.enum'; -export * from './resource.interface'; -export * from './warrant-op.enum'; -export * from './warrant-token.interface'; -export * from './warrant.interface'; diff --git a/src/fga/interfaces/list.interface.ts b/src/fga/interfaces/list.interface.ts deleted file mode 100644 index 99bea2396..000000000 --- a/src/fga/interfaces/list.interface.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { List, ListResponse } from '../../common/interfaces'; -import { Warning } from './warning.interface'; - -export interface FGAListResponse extends ListResponse { - warnings?: Warning[]; -} - -export interface FGAList extends List { - warnings?: Warning[]; -} diff --git a/src/fga/interfaces/query.interface.ts b/src/fga/interfaces/query.interface.ts deleted file mode 100644 index 4fec4270f..000000000 --- a/src/fga/interfaces/query.interface.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Warrant, PolicyContext, WarrantResponse } from './warrant.interface'; -import { PaginationOptions } from '../../common/interfaces/pagination-options.interface'; -import { GetOptions } from '../../common/interfaces'; - -export interface QueryOptions extends PaginationOptions { - q: string; - context?: PolicyContext; -} - -export interface SerializedQueryOptions extends PaginationOptions { - q: string; - context?: string; -} - -export interface QueryResult { - resourceType: string; - resourceId: string; - relation: string; - warrant: Warrant; - isImplicit: boolean; - meta?: { [key: string]: any }; -} - -export interface QueryResultResponse { - resource_type: string; - resource_id: string; - relation: string; - warrant: WarrantResponse; - is_implicit: boolean; - meta?: Record; -} - -export type QueryRequestOptions = Pick; diff --git a/src/fga/interfaces/resource-op.enum.ts b/src/fga/interfaces/resource-op.enum.ts deleted file mode 100644 index 4431b990c..000000000 --- a/src/fga/interfaces/resource-op.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum ResourceOp { - Create = 'create', - Delete = 'delete', -} diff --git a/src/fga/interfaces/resource.interface.ts b/src/fga/interfaces/resource.interface.ts deleted file mode 100644 index ab222e61c..000000000 --- a/src/fga/interfaces/resource.interface.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { PaginationOptions } from '../../common/interfaces/pagination-options.interface'; -import { ResourceOp } from './resource-op.enum'; - -export interface ResourceInterface { - getResourceType(): string; - getResourceId(): string; -} - -export interface ResourceOptions { - resourceType: string; - resourceId?: string; -} - -export interface SerializedResourceOptions { - resource_type: string; - resource_id?: string; -} - -export interface CreateResourceOptions { - resource: ResourceInterface | ResourceOptions; - meta?: { [key: string]: any }; -} - -export interface SerializedCreateResourceOptions { - resource_type: string; - resource_id?: string; - meta?: { [key: string]: any }; -} - -export type GetResourceOptions = ResourceInterface | ResourceOptions; - -export interface ListResourcesOptions extends PaginationOptions { - resourceType?: string; - search?: string; -} - -export interface SerializedListResourcesOptions extends PaginationOptions { - resource_type?: string; - search?: string; -} - -export interface UpdateResourceOptions { - resource: ResourceInterface | ResourceOptions; - meta: { [key: string]: any }; -} - -export type DeleteResourceOptions = ResourceInterface | ResourceOptions; - -export interface SerializedDeleteResourceOptions { - resource_type: string; - resource_id: string; -} - -export interface Resource { - resourceType: string; - resourceId: string; - meta?: { [key: string]: any }; -} - -export interface ResourceResponse { - resource_type: string; - resource_id: string; - meta?: { [key: string]: any }; -} - -export interface BatchWriteResourcesOptions { - op: ResourceOp; - resources: CreateResourceOptions[] | DeleteResourceOptions[]; -} - -export interface SerializedBatchWriteResourcesOptions { - op: string; - resources: - | SerializedCreateResourceOptions[] - | SerializedDeleteResourceOptions[]; -} - -export interface BatchWriteResourcesResponse { - data: ResourceResponse[]; -} diff --git a/src/fga/interfaces/warning.interface.ts b/src/fga/interfaces/warning.interface.ts deleted file mode 100644 index 754f79601..000000000 --- a/src/fga/interfaces/warning.interface.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface BaseWarning { - code: string; - message: string; -} - -export interface MissingContextKeysWarning extends BaseWarning { - code: 'missing_context_keys'; - keys: string[]; -} - -export type Warning = BaseWarning | MissingContextKeysWarning; diff --git a/src/fga/interfaces/warrant-op.enum.ts b/src/fga/interfaces/warrant-op.enum.ts deleted file mode 100644 index 7c372d6a3..000000000 --- a/src/fga/interfaces/warrant-op.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum WarrantOp { - Create = 'create', - Delete = 'delete', -} diff --git a/src/fga/interfaces/warrant-token.interface.ts b/src/fga/interfaces/warrant-token.interface.ts deleted file mode 100644 index e999ad01b..000000000 --- a/src/fga/interfaces/warrant-token.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface WarrantToken { - warrantToken: string; -} - -export interface WarrantTokenResponse { - warrant_token: string; -} diff --git a/src/fga/interfaces/warrant.interface.ts b/src/fga/interfaces/warrant.interface.ts deleted file mode 100644 index d66c36c68..000000000 --- a/src/fga/interfaces/warrant.interface.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { GetOptions } from '../../common/interfaces'; -import { ResourceInterface, ResourceOptions } from './resource.interface'; -import { WarrantOp } from './warrant-op.enum'; - -export interface ListWarrantsOptions { - resourceType?: string; - resourceId?: string; - relation?: string; - subjectType?: string; - subjectId?: string; - subjectRelation?: string; - limit?: number; - after?: string | null; -} - -export interface SerializedListWarrantsOptions { - resource_type?: string; - resource_id?: string; - relation?: string; - subject_type?: string; - subject_id?: string; - subject_relation?: string; - limit?: number; - after?: string | null; -} - -export interface PolicyContext { - [key: string]: any; -} - -export interface Subject { - resourceType: string; - resourceId: string; - relation?: string; -} - -export interface SerializedSubject { - resource_type: string; - resource_id: string; - relation?: string; -} - -export interface Warrant { - resourceType: string; - resourceId: string; - relation: string; - subject: Subject; - policy?: string; -} - -export interface WriteWarrantOptions { - op?: WarrantOp; - resource: ResourceInterface | ResourceOptions; - relation: string; - subject: ResourceInterface | Subject; - policy?: string; -} - -export interface SerializedWriteWarrantOptions { - op?: WarrantOp; - resource_type: string; - resource_id: string; - relation: string; - subject: SerializedSubject; - policy?: string; -} - -export type ListWarrantsRequestOptions = Pick; - -export interface WarrantResponse { - resource_type: string; - resource_id: string; - relation: string; - subject: SerializedSubject; - policy?: string; -} diff --git a/src/fga/serializers/batch-write-resources-options.serializer.ts b/src/fga/serializers/batch-write-resources-options.serializer.ts deleted file mode 100644 index b2543b0ca..000000000 --- a/src/fga/serializers/batch-write-resources-options.serializer.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - BatchWriteResourcesOptions, - CreateResourceOptions, - DeleteResourceOptions, - ResourceOp, - SerializedBatchWriteResourcesOptions, - SerializedCreateResourceOptions, - SerializedDeleteResourceOptions, -} from '../interfaces'; -import { serializeCreateResourceOptions } from './create-resource-options.serializer'; -import { serializeDeleteResourceOptions } from './delete-resource-options.serializer'; - -export const serializeBatchWriteResourcesOptions = ( - options: BatchWriteResourcesOptions, -): SerializedBatchWriteResourcesOptions => { - let serializedResources: - | SerializedCreateResourceOptions[] - | SerializedDeleteResourceOptions[] = []; - if (options.op === ResourceOp.Create) { - const resources = options.resources as CreateResourceOptions[]; - serializedResources = resources.map((options: CreateResourceOptions) => - serializeCreateResourceOptions(options), - ); - } else if (options.op === ResourceOp.Delete) { - const resources = options.resources as DeleteResourceOptions[]; - serializedResources = resources.map((options: DeleteResourceOptions) => - serializeDeleteResourceOptions(options), - ); - } - - return { - op: options.op, - resources: serializedResources, - }; -}; diff --git a/src/fga/serializers/check-options.serializer.ts b/src/fga/serializers/check-options.serializer.ts deleted file mode 100644 index 77ceb655a..000000000 --- a/src/fga/serializers/check-options.serializer.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - CheckBatchOptions, - CheckOptions, - CheckWarrantOptions, - DecisionTreeNode, - DecisionTreeNodeResponse, - SerializedCheckBatchOptions, - SerializedCheckOptions, - SerializedCheckWarrantOptions, -} from '../interfaces'; -import { isSubject, isResourceInterface } from '../utils/interface-check'; - -export const serializeCheckOptions = ( - options: CheckOptions, -): SerializedCheckOptions => ({ - op: options.op, - checks: options.checks.map(serializeCheckWarrantOptions), - debug: options.debug, -}); - -export const serializeCheckBatchOptions = ( - options: CheckBatchOptions, -): SerializedCheckBatchOptions => ({ - op: 'batch', - checks: options.checks.map(serializeCheckWarrantOptions), - debug: options.debug, -}); - -const serializeCheckWarrantOptions = ( - warrant: CheckWarrantOptions, -): SerializedCheckWarrantOptions => { - return { - resource_type: isResourceInterface(warrant.resource) - ? warrant.resource.getResourceType() - : warrant.resource.resourceType, - resource_id: isResourceInterface(warrant.resource) - ? warrant.resource.getResourceId() - : warrant.resource.resourceId - ? warrant.resource.resourceId - : '', - relation: warrant.relation, - subject: isSubject(warrant.subject) - ? { - resource_type: warrant.subject.resourceType, - resource_id: warrant.subject.resourceId, - } - : { - resource_type: warrant.subject.getResourceType(), - resource_id: warrant.subject.getResourceId(), - }, - context: warrant.context ?? {}, - }; -}; - -export const deserializeDecisionTreeNode = ( - response: DecisionTreeNodeResponse, -): DecisionTreeNode => { - return { - check: { - resource: { - resourceType: response.check.resource_type, - resourceId: response.check.resource_id, - }, - relation: response.check.relation, - subject: { - resourceType: response.check.subject.resource_type, - resourceId: response.check.subject.resource_id, - }, - context: response.check.context, - }, - policy: response.policy, - decision: response.decision, - processingTime: response.processing_time, - children: response.children.map(deserializeDecisionTreeNode), - }; -}; diff --git a/src/fga/serializers/create-resource-options.serializer.ts b/src/fga/serializers/create-resource-options.serializer.ts deleted file mode 100644 index 91914cff3..000000000 --- a/src/fga/serializers/create-resource-options.serializer.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { - CreateResourceOptions, - SerializedCreateResourceOptions, -} from '../interfaces'; -import { isResourceInterface } from '../utils/interface-check'; - -export const serializeCreateResourceOptions = ( - options: CreateResourceOptions, -): SerializedCreateResourceOptions => ({ - resource_type: isResourceInterface(options.resource) - ? options.resource.getResourceType() - : options.resource.resourceType, - resource_id: isResourceInterface(options.resource) - ? options.resource.getResourceId() - : options.resource.resourceId - ? options.resource.resourceId - : '', - meta: options.meta, -}); diff --git a/src/fga/serializers/delete-resource-options.serializer.ts b/src/fga/serializers/delete-resource-options.serializer.ts deleted file mode 100644 index 481918631..000000000 --- a/src/fga/serializers/delete-resource-options.serializer.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - DeleteResourceOptions, - SerializedDeleteResourceOptions, -} from '../interfaces'; -import { isResourceInterface } from '../utils/interface-check'; - -export const serializeDeleteResourceOptions = ( - options: DeleteResourceOptions, -): SerializedDeleteResourceOptions => ({ - resource_type: isResourceInterface(options) - ? options.getResourceType() - : options.resourceType, - resource_id: isResourceInterface(options) - ? options.getResourceId() - : options.resourceId - ? options.resourceId - : '', -}); diff --git a/src/fga/serializers/index.ts b/src/fga/serializers/index.ts deleted file mode 100644 index 3bb36abd9..000000000 --- a/src/fga/serializers/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from './check-options.serializer'; -export * from './batch-write-resources-options.serializer'; -export * from './create-resource-options.serializer'; -export * from './delete-resource-options.serializer'; -export * from './list-resources-options.serializer'; -export * from './list-warrants-options.serializer'; -export * from './query-options.serializer'; -export * from './query-result.serializer'; -export * from './resource.serializer'; -export * from './warrant-token.serializer'; -export * from './warrant.serializer'; -export * from './write-warrant-options.serializer'; -export * from './list.serializer'; diff --git a/src/fga/serializers/list-resources-options.serializer.ts b/src/fga/serializers/list-resources-options.serializer.ts deleted file mode 100644 index 4aa90f399..000000000 --- a/src/fga/serializers/list-resources-options.serializer.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - ListResourcesOptions, - SerializedListResourcesOptions, -} from '../interfaces'; - -export const serializeListResourceOptions = ( - options: ListResourcesOptions, -): SerializedListResourcesOptions => ({ - resource_type: options.resourceType, - search: options.search, - limit: options.limit, - before: options.before, - after: options.after, - order: options.order, -}); diff --git a/src/fga/serializers/list-warrants-options.serializer.ts b/src/fga/serializers/list-warrants-options.serializer.ts deleted file mode 100644 index 016a29b84..000000000 --- a/src/fga/serializers/list-warrants-options.serializer.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { - ListWarrantsOptions, - SerializedListWarrantsOptions, -} from '../interfaces'; - -export const serializeListWarrantsOptions = ( - options: ListWarrantsOptions, -): SerializedListWarrantsOptions => ({ - resource_type: options.resourceType, - resource_id: options.resourceId, - relation: options.relation, - subject_type: options.subjectType, - subject_id: options.subjectId, - subject_relation: options.subjectRelation, - limit: options.limit, - after: options.after, -}); diff --git a/src/fga/serializers/list.serializer.ts b/src/fga/serializers/list.serializer.ts deleted file mode 100644 index 2920fb654..000000000 --- a/src/fga/serializers/list.serializer.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { FGAList } from '../interfaces/list.interface'; -import { ListResponse } from '../../common/interfaces'; - -export const deserializeFGAList = ( - response: ListResponse & { warnings?: any[] }, - deserializeFn: (data: T) => U, -): FGAList => ({ - object: 'list', - data: response.data.map(deserializeFn), - listMetadata: response.list_metadata, - warnings: response.warnings, -}); diff --git a/src/fga/serializers/query-options.serializer.ts b/src/fga/serializers/query-options.serializer.ts deleted file mode 100644 index 6d148a73d..000000000 --- a/src/fga/serializers/query-options.serializer.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { QueryOptions, SerializedQueryOptions } from '../interfaces'; - -export const serializeQueryOptions = ( - options: QueryOptions, -): SerializedQueryOptions => ({ - q: options.q, - context: JSON.stringify(options.context), - limit: options.limit, - before: options.before, - after: options.after, - order: options.order, -}); diff --git a/src/fga/serializers/query-result.serializer.ts b/src/fga/serializers/query-result.serializer.ts deleted file mode 100644 index 8d175bc0b..000000000 --- a/src/fga/serializers/query-result.serializer.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { QueryResult, QueryResultResponse } from '../interfaces'; -import { Warning } from '../interfaces/warning.interface'; -import { ListResponse } from '../../common/interfaces'; - -export interface QueryResultListResponse extends ListResponse { - warnings?: Warning[]; -} - -export const deserializeQueryResult = ( - queryResult: QueryResultResponse, -): QueryResult => ({ - resourceType: queryResult.resource_type, - resourceId: queryResult.resource_id, - relation: queryResult.relation, - warrant: { - resourceType: queryResult.warrant.resource_type, - resourceId: queryResult.warrant.resource_id, - relation: queryResult.warrant.relation, - subject: { - resourceType: queryResult.warrant.subject.resource_type, - resourceId: queryResult.warrant.subject.resource_id, - relation: queryResult.warrant.subject.relation, - }, - }, - isImplicit: queryResult.is_implicit, - meta: queryResult.meta, -}); diff --git a/src/fga/serializers/resource.serializer.ts b/src/fga/serializers/resource.serializer.ts deleted file mode 100644 index fc02d128a..000000000 --- a/src/fga/serializers/resource.serializer.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { - BatchWriteResourcesResponse, - Resource, - ResourceResponse, -} from '../interfaces'; - -export const deserializeResource = (response: ResourceResponse): Resource => ({ - resourceType: response.resource_type, - resourceId: response.resource_id, - meta: response.meta, -}); - -export const deserializeBatchWriteResourcesResponse = ( - response: BatchWriteResourcesResponse, -): Resource[] => { - return response.data.map((resource) => deserializeResource(resource)); -}; diff --git a/src/fga/serializers/warrant-token.serializer.ts b/src/fga/serializers/warrant-token.serializer.ts deleted file mode 100644 index 4dca28355..000000000 --- a/src/fga/serializers/warrant-token.serializer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { - WarrantToken, - WarrantTokenResponse, -} from '../interfaces/warrant-token.interface'; - -export const deserializeWarrantToken = ( - warrantToken: WarrantTokenResponse, -): WarrantToken => ({ - warrantToken: warrantToken.warrant_token, -}); diff --git a/src/fga/serializers/warrant.serializer.ts b/src/fga/serializers/warrant.serializer.ts deleted file mode 100644 index 5b049eba2..000000000 --- a/src/fga/serializers/warrant.serializer.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Warrant, WarrantResponse } from '../interfaces'; - -export const deserializeWarrant = (warrant: WarrantResponse): Warrant => ({ - resourceType: warrant.resource_type, - resourceId: warrant.resource_id, - relation: warrant.relation, - subject: { - resourceType: warrant.subject.resource_type, - resourceId: warrant.subject.resource_id, - relation: warrant.subject.relation, - }, - policy: warrant.policy, -}); diff --git a/src/fga/serializers/write-warrant-options.serializer.ts b/src/fga/serializers/write-warrant-options.serializer.ts deleted file mode 100644 index 23d17f1b8..000000000 --- a/src/fga/serializers/write-warrant-options.serializer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - SerializedWriteWarrantOptions, - WriteWarrantOptions, -} from '../interfaces'; -import { isSubject, isResourceInterface } from '../utils/interface-check'; - -export const serializeWriteWarrantOptions = ( - warrant: WriteWarrantOptions, -): SerializedWriteWarrantOptions => ({ - op: warrant.op, - resource_type: isResourceInterface(warrant.resource) - ? warrant.resource.getResourceType() - : warrant.resource.resourceType, - resource_id: isResourceInterface(warrant.resource) - ? warrant.resource.getResourceId() - : warrant.resource.resourceId - ? warrant.resource.resourceId - : '', - relation: warrant.relation, - subject: isSubject(warrant.subject) - ? { - resource_type: warrant.subject.resourceType, - resource_id: warrant.subject.resourceId, - } - : { - resource_type: warrant.subject.getResourceType(), - resource_id: warrant.subject.getResourceId(), - }, - policy: warrant.policy, -}); diff --git a/src/fga/utils/fetch-and-deserialize-list.ts b/src/fga/utils/fetch-and-deserialize-list.ts deleted file mode 100644 index ecb5ec081..000000000 --- a/src/fga/utils/fetch-and-deserialize-list.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { WorkOS } from '../../workos'; -import { FGAList } from '../interfaces/list.interface'; -import { QueryRequestOptions } from '../interfaces'; -import { PaginationOptions } from '../../common/interfaces'; -import { ListResponse } from '../../common/interfaces'; -import { deserializeFGAList } from '../serializers/list.serializer'; - -export const fetchAndDeserializeFGAList = async ( - workos: WorkOS, - endpoint: string, - deserializeFn: (data: T) => U, - options?: PaginationOptions, - requestOptions?: QueryRequestOptions, -): Promise> => { - const { data: response } = await workos.get< - ListResponse & { warnings?: any[] } - >(endpoint, { - query: options, - ...requestOptions, - }); - - return deserializeFGAList(response, deserializeFn); -}; diff --git a/src/fga/utils/fga-paginatable.ts b/src/fga/utils/fga-paginatable.ts deleted file mode 100644 index 7b27c26f6..000000000 --- a/src/fga/utils/fga-paginatable.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AutoPaginatable } from '../../common/utils/pagination'; -import { FGAList } from '../interfaces/list.interface'; -import { Warning } from '../interfaces/warning.interface'; -import { PaginationOptions } from '../../common/interfaces'; - -export class FgaPaginatable< - T, - P extends PaginationOptions = PaginationOptions, -> extends AutoPaginatable { - protected override list: FGAList; - - constructor( - list: FGAList, - apiCall: (params: PaginationOptions) => Promise>, - options?: P, - ) { - super(list, apiCall, options); - this.list = list; - } - - get warnings(): Warning[] | undefined { - return this.list.warnings; - } -} diff --git a/src/fga/utils/interface-check.ts b/src/fga/utils/interface-check.ts deleted file mode 100644 index 91336d453..000000000 --- a/src/fga/utils/interface-check.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Subject, ResourceInterface } from '../interfaces'; - -export function isSubject(resource: any): resource is Subject { - return ( - Object.prototype.hasOwnProperty.call(resource, 'resourceType') && - Object.prototype.hasOwnProperty.call(resource, 'resourceId') - ); -} - -export function isResourceInterface( - resource: unknown, -): resource is ResourceInterface { - return ( - !!resource && - typeof resource === 'object' && - 'getResouceType' in resource && - 'getResourceId' in resource - ); -} diff --git a/src/index.ts b/src/index.ts index 973b0dcf7..6a7e8d1d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,6 @@ export * from './directory-sync/interfaces'; export * from './events/interfaces'; export * from './feature-flags/interfaces'; export { FeatureFlagsRuntimeClient } from './feature-flags/runtime-client'; -export * from './fga/interfaces'; export * from './organizations/interfaces'; export * from './organization-domains/interfaces'; export * from './passwordless/interfaces'; diff --git a/src/index.worker.ts b/src/index.worker.ts index c7cbfe685..aeaab70bc 100644 --- a/src/index.worker.ts +++ b/src/index.worker.ts @@ -15,7 +15,6 @@ export * from './common/interfaces'; export * from './common/utils/pagination'; export * from './directory-sync/interfaces'; export * from './events/interfaces'; -export * from './fga/interfaces'; export * from './organizations/interfaces'; export * from './organization-domains/interfaces'; export * from './passwordless/interfaces'; diff --git a/src/workos.ts b/src/workos.ts index 4d5b45156..1014c4a5c 100644 --- a/src/workos.ts +++ b/src/workos.ts @@ -30,7 +30,6 @@ import { Webhooks } from './webhooks/webhooks'; import { Mfa } from './mfa/mfa'; import { AuditLogs } from './audit-logs/audit-logs'; import { UserManagement } from './user-management/user-management'; -import { FGA } from './fga/fga'; import { BadRequestException } from './common/exceptions/bad-request.exception'; import { FeatureFlags } from './feature-flags/feature-flags'; @@ -71,7 +70,6 @@ export class WorkOS { readonly directorySync = new DirectorySync(this); readonly events = new Events(this); readonly featureFlags = new FeatureFlags(this); - readonly fga = new FGA(this); readonly mfa = new Mfa(this); readonly organizations = new Organizations(this); readonly organizationDomains = new OrganizationDomains(this); From 7c1b98bdd79b58fe6ecd5c83479e3b62d3c6866b Mon Sep 17 00:00:00 2001 From: Aaron Tainter Date: Wed, 15 Apr 2026 14:31:58 -0700 Subject: [PATCH 2/2] Update http-client.ts --- src/common/net/http-client.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/net/http-client.ts b/src/common/net/http-client.ts index d29764bae..f50a563cc 100644 --- a/src/common/net/http-client.ts +++ b/src/common/net/http-client.ts @@ -106,9 +106,7 @@ export abstract class HttpClient implements HttpClientInterface { } static isPathRetryable(path: string): boolean { - return ( - path.startsWith('/vault/') || path.startsWith('/audit_logs/events') - ); + return path.startsWith('/vault/') || path.startsWith('/audit_logs/events'); } private getSleepTimeInMilliseconds(retryAttempt: number): number {