Skip to content

Commit d82ebec

Browse files
authored
feat: capabilities (#695)
1 parent 462db0b commit d82ebec

File tree

4 files changed

+53
-11
lines changed

4 files changed

+53
-11
lines changed

src/http/routes/admin/tenants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
multitenantKnex,
99
getTenantConfig,
1010
jwksManager,
11+
getTenantCapabilities,
1112
} from '@internal/database'
1213
import { dbSuperUser, storage } from '../../plugins'
1314
import {
@@ -184,6 +185,8 @@ export default async function routes(fastify: FastifyInstance) {
184185
disable_events,
185186
} = tenant
186187

188+
const capabilities = await getTenantCapabilities(request.params.tenantId)
189+
187190
return {
188191
anonKey: decrypt(anon_key),
189192
databaseUrl: decrypt(database_url),
@@ -199,6 +202,7 @@ export default async function routes(fastify: FastifyInstance) {
199202
jwtSecret: decrypt(jwt_secret),
200203
jwks,
201204
serviceKey: decrypt(service_key),
205+
capabilities,
202206
features: {
203207
imageTransformation: {
204208
enabled: feature_image_transformation,

src/internal/database/tenant.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { JWTPayload } from 'jose'
55
import { PubSubAdapter } from '../pubsub'
66
import { createMutexByKey } from '../concurrency'
77
import { ERRORS } from '@internal/errors'
8-
import { DBMigration } from '@internal/database/migrations'
8+
import { DBMigration, lastLocalMigrationName } from '@internal/database/migrations'
99
import { JWKSManager } from './jwks-manager'
1010
import { JWKSManagerStoreKnex } from './jwks-manager/store-knex'
1111
import {
@@ -57,7 +57,8 @@ export enum TenantMigrationStatus {
5757
FAILED_STALE = 'FAILED_STALE',
5858
}
5959

60-
const { isMultitenant, dbServiceRole, serviceKeyAsync, jwtSecret } = getConfig()
60+
const { isMultitenant, dbServiceRole, serviceKeyAsync, jwtSecret, dbMigrationFreezeAt } =
61+
getConfig()
6162

6263
const tenantConfigCache = new Map<string, TenantConfig>()
6364

@@ -201,6 +202,33 @@ export async function getServiceKey(tenantId: string): Promise<string> {
201202
return serviceKey
202203
}
203204

205+
enum Capability {
206+
LIST_V2 = 'list_V2',
207+
}
208+
209+
/**
210+
* Get the capabilities for a specific tenant
211+
* @param tenantId
212+
*/
213+
export async function getTenantCapabilities(tenantId: string) {
214+
const capabilities: Record<Capability, boolean> = {
215+
[Capability.LIST_V2]: false,
216+
}
217+
218+
let latestMigrationName = dbMigrationFreezeAt || (await lastLocalMigrationName())
219+
220+
if (isMultitenant) {
221+
const { migrationVersion } = await getTenantConfig(tenantId)
222+
latestMigrationName = migrationVersion || 'initialmigration'
223+
}
224+
225+
if (DBMigration[latestMigrationName] >= DBMigration['optimise-existing-functions']) {
226+
capabilities[Capability.LIST_V2] = true
227+
}
228+
229+
return capabilities
230+
}
231+
204232
/**
205233
* Get the jwt key from the tenant config
206234
* @param tenantId

src/test/tenant.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const payload = {
3131
migrationStatus: 'COMPLETED',
3232
migrationVersion,
3333
tracingMode: 'basic',
34+
capabilities: {
35+
list_V2: true,
36+
},
3437
features: {
3538
imageTransformation: {
3639
enabled: true,
@@ -59,6 +62,9 @@ const payload2 = {
5962
migrationStatus: 'COMPLETED',
6063
migrationVersion,
6164
tracingMode: 'basic',
65+
capabilities: {
66+
list_V2: true,
67+
},
6268
features: {
6369
imageTransformation: {
6470
enabled: false,
@@ -113,10 +119,12 @@ describe('Tenant configs', () => {
113119
})
114120
expect(response.statusCode).toBe(200)
115121
const responseJSON = JSON.parse(response.body)
122+
const { capabilities, ...finalPayload } = payload
123+
116124
expect(responseJSON).toEqual([
117125
{
118126
id: 'abc',
119-
...payload,
127+
...finalPayload,
120128
},
121129
])
122130
})

src/test/x-forwarded-host.test.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,17 @@ jest.spyOn(tenant, 'getTenantConfig').mockImplementation(async () => ({
2828
},
2929
}))
3030

31-
const mockBucketResult = [{ id: 'abc123', name: 'def456' }]
32-
const storageDbMock = jest.fn().mockImplementation(() => ({
33-
listBuckets: jest.fn().mockResolvedValue(mockBucketResult),
31+
// Mock module with inline implementation that doesn't depend on variables
32+
jest.mock('@storage/database', () => ({
33+
StorageKnexDB: jest.fn().mockImplementation(() => ({
34+
listBuckets: jest.fn().mockResolvedValue([{ id: 'abc123', name: 'def456' }]),
35+
})),
3436
}))
35-
jest.mock('@storage/database', () => {
36-
return {
37-
StorageKnexDB: storageDbMock,
38-
}
39-
})
37+
38+
// Access the mock after it's been created by the Jest runtime
39+
const storageDbMock = require('@storage/database').StorageKnexDB
40+
41+
// Use this reference in tests
4042

4143
getConfig()
4244
mergeConfig({

0 commit comments

Comments
 (0)