import type * as Analytics from '../../analytics/Analytics.js' import * as ApiKeys from '../../ApiKeys.js' import * as BillingSettings from '../../db/tables/billingSettings.js' import * as EnabledBillingSources from '../../db/tables/enabledBillingSources.js' import * as Memberships from '../../db/tables/memberships.js' import * as Organizations from '../../db/tables/organizations.js' import * as Projects from '../../db/tables/projects.js' import * as SponsoredTransactions from '../../db/tables/sponsoredTransactions.js' import * as StripeCustomers from '../../db/tables/stripeCustomers.js' import * as Users from '../../db/tables/users.js' import * as WebhookDeliveries from '../../db/tables/webhookDeliveries.js' import * as WebhookSubscriptions from '../../db/tables/webhookSubscriptions.js' import * as Viem from '../../internal/Viem.js' import * as TestAdmin from '../../../test/Admin.js' import * as TestApp from '../../../test/App.js' import * as AdminOrganizations from './organizations.js' describe('GET /organizations', () => { test('lists summaries newest first with member and project counts', async () => { const { client, db } = TestAdmin.setup() const user = await Users.upsertByAddress(db, { address: `0x${'11'.repeat(20)}`, }) await Users.setEmail(db, user.id, 'owner@acme.example') const organization = await Organizations.createOwned(db, { name: 'Acme', userId: user.id }) await Projects.create(db, { name: 'Checkout', orgId: organization.id }) await Projects.create(db, { name: 'Treasury', orgId: organization.id }) const response = await client.organizations.$get({ query: {} }) const body = await TestApp.json(response, AdminOrganizations.schema.listOrganizations.Response) expect(response.status).toBe(200) expect(body.nextCursor).toBeNull() expect(body.data).toHaveLength(1) expect(body.data[0]).toMatchObject({ id: organization.id, memberCount: 1, name: 'Acme', projectCount: 2, userId: user.id, }) }) test('searches organization and member identity fields case-insensitively', async () => { const { client, db } = TestAdmin.setup() const user = await Users.upsertByAddress(db, { address: `0x${'22'.repeat(20)}`, }) await Users.setEmail(db, user.id, 'Owner@Example.com') const organization = await Organizations.createOwned(db, { name: 'Merchant Operations', userId: user.id, }) await Organizations.create(db, { id: 'org_unrelated', name: 'Unrelated' }) for (const query of ['merchant', organization.id, user.id, 'owner@']) { const response = await client.organizations.$get({ query: { query } }) const body = await TestApp.json( response, AdminOrganizations.schema.listOrganizations.Response, ) expect(body.data.map(({ id }) => id)).toEqual([organization.id]) } }) test('treats SQL wildcard characters as literal search text', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'A_B Merchant' }) await Organizations.create(db, { name: 'AcB Merchant' }) const response = await client.organizations.$get({ query: { query: 'a_b' } }) const body = await TestApp.json(response, AdminOrganizations.schema.listOrganizations.Response) expect(body.data.map(({ id }) => id)).toEqual([organization.id]) }) test('orders distinct creation times newest first', async () => { const { client, db } = TestAdmin.setup() vi.useFakeTimers() try { vi.setSystemTime(new Date('2026-01-01T00:00:00.000Z')) const older = await Organizations.create(db, { name: 'Older' }) vi.setSystemTime(new Date('2026-01-02T00:00:00.000Z')) const newer = await Organizations.create(db, { name: 'Newer' }) const response = await client.organizations.$get({ query: {} }) const body = await TestApp.json( response, AdminOrganizations.schema.listOrganizations.Response, ) expect(body.data.map(({ id }) => id)).toEqual([newer.id, older.id]) } finally { vi.useRealTimers() } }) test('rejects broad queries shorter than three characters', async () => { const { client } = TestAdmin.setup() const response = await client.organizations.$get({ query: { query: 'a' } }) expect(response.status).toBe(400) }) test('walks a stable cursor without duplicate organizations', async () => { const { client, db } = TestAdmin.setup() for (const id of ['org_f', 'org_e', 'org_d', 'org_c', 'org_b', 'org_a']) await Organizations.create(db, { id, name: id }) const firstResponse = await client.organizations.$get({ query: { limit: '5' } }) const first = await TestApp.json( firstResponse, AdminOrganizations.schema.listOrganizations.Response, ) expect(first.data).toHaveLength(5) expect(first.nextCursor).not.toBeNull() const secondResponse = await client.organizations.$get({ query: { cursor: first.nextCursor!, limit: '5' }, }) const second = await TestApp.json( secondResponse, AdminOrganizations.schema.listOrganizations.Response, ) expect(second.data).toHaveLength(1) expect(second.nextCursor).toBeNull() expect(new Set([...first.data, ...second.data].map(({ id }) => id)).size).toBe(6) }) }) describe('GET /organizations/:orgId', () => { test('returns counts and billing state split by environment', async () => { const { client, db } = TestAdmin.setup() const user = await Users.upsertByAddress(db, { address: `0x${'33'.repeat(20)}`, }) await Users.setEmail(db, user.id, 'owner@tempo.xyz') const organization = await Organizations.createOwned(db, { name: 'Tempo', userId: user.id }) await EnabledBillingSources.add(db, { createdBy: TestAdmin.identity.email, orgId: organization.id, source: 'stripe', }) await EnabledBillingSources.add(db, { createdBy: TestAdmin.identity.email, orgId: organization.id, source: 'tempo', }) await Projects.create(db, { name: 'API', orgId: organization.id }) await BillingSettings.upsert(db, { environment: 'production', orgId: organization.id, spendLimit: '250', txFeeLimit: '0.50', }) await BillingSettings.upsert(db, { environment: 'sandbox', orgId: organization.id, spendLimit: '1000', }) await StripeCustomers.create(db, { environment: 'production', orgId: organization.id, stripeCustomerId: 'cus_admin_lookup', }) await StripeCustomers.setStatus(db, organization.id, 'active', 'production') const response = await client.organizations[':orgId'].$get({ param: { orgId: organization.id }, }) const body = await TestApp.json(response, AdminOrganizations.schema.getOrganization.Response) expect(response.status).toBe(200) expect(body.memberCount).toBe(1) expect(body.projectCount).toBe(1) expect(body.billing.enabledSources).toEqual(['stripe', 'tempo']) expect(body.billing.production).toMatchObject({ settings: { spendLimit: '250', txFeeLimit: '0.50' }, source: { status: 'active', stripeCustomerId: 'cus_admin_lookup' }, }) expect(body.billing.sandbox).toMatchObject({ settings: { spendLimit: '1000', txFeeLimit: null }, source: null, }) expect(body.sponsorshipSubsidy).toEqual({ durationDays: null, projectSpendLimit: null }) }) test('returns empty counts and billing for a memberless organization', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Support-created' }) const response = await client.organizations[':orgId'].$get({ param: { orgId: organization.id }, }) const body = await TestApp.json(response, AdminOrganizations.schema.getOrganization.Response) expect(body).toMatchObject({ billing: { enabledSources: [], production: { settings: null, source: null }, sandbox: { settings: null, source: null }, }, memberCount: 0, projectCount: 0, }) }) test('returns 404 for an unknown organization', async () => { const { client } = TestAdmin.setup() const response = await client.organizations[':orgId'].$get({ param: { orgId: 'org_missing' }, }) const body = (await response.json()) as { error: { code: string } } expect(response.status).toBe(404) expect(body.error.code).toBe('not_found') }) }) describe('PUT /organizations/:orgId/sponsorship', () => { test('enables and disables a 90-day per-project policy', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Privy' }) const enabled = await client.organizations[':orgId'].sponsorship.$put({ json: { enabled: true, projectSpendLimit: '1000' }, param: { orgId: organization.id }, }) expect( await TestApp.json(enabled, AdminOrganizations.schema.organizationSponsorship.SetResponse), ).toEqual({ durationDays: 90, projectSpendLimit: '1000' }) const disabled = await client.organizations[':orgId'].sponsorship.$put({ json: { enabled: false }, param: { orgId: organization.id }, }) expect( await TestApp.json(disabled, AdminOrganizations.schema.organizationSponsorship.SetResponse), ).toEqual({ durationDays: null, projectSpendLimit: null }) }) test('enables an uncapped policy', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Privy' }) const response = await client.organizations[':orgId'].sponsorship.$put({ json: { enabled: true }, param: { orgId: organization.id }, }) expect( await TestApp.json(response, AdminOrganizations.schema.organizationSponsorship.SetResponse), ).toEqual({ durationDays: 90, projectSpendLimit: null }) }) test('rejects invalid limits and unknown organizations', async () => { const { app, client } = TestAdmin.setup() const invalid = await app.request('/organizations/org_example/sponsorship', { body: JSON.stringify({ enabled: true, projectSpendLimit: '-1' }), headers: { 'content-type': 'application/json' }, method: 'PUT', }) expect(invalid.status).toBe(400) const missing = await client.organizations[':orgId'].sponsorship.$put({ json: { enabled: true, projectSpendLimit: '1000' }, param: { orgId: 'org_missing' }, }) expect(missing.status).toBe(404) }) }) describe('PUT/DELETE /organizations/:orgId/billing-sources/:source', () => { test('enables and disables sources idempotently', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Billing sources' }) for (const source of ['tempo', 'stripe', 'stripe'] as const) { const response = await client.organizations[':orgId']['billing-sources'][':source'].$put({ param: { orgId: organization.id, source }, }) const body = await TestApp.json(response, AdminOrganizations.schema.setBillingSource.Response) expect(response.status).toBe(200) expect(body.data).toEqual(source === 'tempo' ? ['tempo'] : ['stripe', 'tempo']) } expect(await EnabledBillingSources.listByOrg(db, organization.id)).toMatchObject([ { createdBy: TestAdmin.identity.email, source: 'stripe' }, { createdBy: TestAdmin.identity.email, source: 'tempo' }, ]) for (const source of ['stripe', 'stripe'] as const) { const response = await client.organizations[':orgId']['billing-sources'][':source'].$delete({ param: { orgId: organization.id, source }, }) const body = await TestApp.json(response, AdminOrganizations.schema.setBillingSource.Response) expect(response.status).toBe(200) expect(body.data).toEqual(['tempo']) } const detailResponse = await client.organizations[':orgId'].$get({ param: { orgId: organization.id }, }) const detail = await TestApp.json( detailResponse, AdminOrganizations.schema.getOrganization.Response, ) expect(detail.billing.enabledSources).toEqual(['tempo']) }) test('rejects unsupported sources and unknown organizations', async () => { const { app, client } = TestAdmin.setup() const invalid = await app.request('/organizations/org_example/billing-sources/card', { method: 'PUT', }) expect(invalid.status).toBe(400) const missing = await client.organizations[':orgId']['billing-sources'][':source'].$put({ param: { orgId: 'org_missing', source: 'stripe' }, }) expect(missing.status).toBe(404) }) test('records billing-source mutations in the admin audit log', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Audited billing' }) await client.organizations[':orgId']['billing-sources'][':source'].$put({ param: { orgId: organization.id, source: 'tempo' }, }) const records = await db.kysely .selectFrom('admin_audit_logs') .selectAll() .orderBy('createdAt', 'desc') .execute() expect(records[0]).toMatchObject({ actor: TestAdmin.identity.email, method: 'PUT', path: `/organizations/${organization.id}/billing-sources/tempo`, status: 200, }) }) }) describe('GET /organizations/:orgId/members', () => { test('returns a bounded cursor page without duplicates', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Members' }) for (let index = 0; index < 6; index++) { const user = await Users.upsertByAddress(db, { address: `0x${String(index + 1).padStart(40, '0')}`, }) await Users.setEmail(db, user.id, `member-${index}@example.com`) await Memberships.create(db, { orgId: organization.id, role: 'member', userId: user.id }) } const firstResponse = await client.organizations[':orgId'].members.$get({ param: { orgId: organization.id }, query: { limit: '5' }, }) const first = await TestApp.json( firstResponse, AdminOrganizations.schema.listOrganizationMembers.Response, ) const secondResponse = await client.organizations[':orgId'].members.$get({ param: { orgId: organization.id }, query: { cursor: first.nextCursor!, limit: '5' }, }) const second = await TestApp.json( secondResponse, AdminOrganizations.schema.listOrganizationMembers.Response, ) expect(first.data).toHaveLength(5) expect(second.data).toHaveLength(1) expect(new Set([...first.data, ...second.data].map(({ userId }) => userId)).size).toBe(6) }) }) describe('GET /organizations/:orgId/projects', () => { test('returns a bounded cursor page without duplicates', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Projects' }) for (let index = 0; index < 6; index++) await Projects.create(db, { name: `Project ${index}`, orgId: organization.id }) const firstResponse = await client.organizations[':orgId'].projects.$get({ param: { orgId: organization.id }, query: { limit: '5' }, }) const first = await TestApp.json( firstResponse, AdminOrganizations.schema.listOrganizationProjects.Response, ) const secondResponse = await client.organizations[':orgId'].projects.$get({ param: { orgId: organization.id }, query: { cursor: first.nextCursor!, limit: '5' }, }) const second = await TestApp.json( secondResponse, AdminOrganizations.schema.listOrganizationProjects.Response, ) expect(first.data).toHaveLength(5) expect(second.data).toHaveLength(1) expect(new Set([...first.data, ...second.data].map(({ id }) => id)).size).toBe(6) }) }) describe('GET /organizations/:orgId/api-keys', () => { test('returns active key environment, scopes, and creator without tokens', async () => { const { client, db, store } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Keys' }) await ApiKeys.mint(store, { createdBy: 'ops@tempo.xyz', environment: 'sandbox', orgId: organization.id, scopes: ['data:read'], }) const response = await client.organizations[':orgId']['api-keys'].$get({ param: { orgId: organization.id }, }) const body = await TestApp.json( response, AdminOrganizations.schema.listOrganizationApiKeys.Response, ) expect(body.data[0]).toMatchObject({ createdBy: 'ops@tempo.xyz', environment: 'sandbox', scopes: ['data:read'], }) expect(body.data[0]).not.toHaveProperty('status') expect(body.data[0]).not.toHaveProperty('token') }) }) describe('GET /organizations/:orgId/usage', () => { test('returns recent totals and error breakdowns from analytics', async () => { const { client, db } = TestAdmin.setup({ analytics: usageAnalytics }) const organization = await Organizations.create(db, { name: 'Usage' }) const response = await client.organizations[':orgId'].usage.$get({ param: { orgId: organization.id }, query: { period: '7d' }, }) const body = await TestApp.json( response, AdminOrganizations.schema.getOrganizationUsage.Response, ) expect(body).toMatchObject({ byError: [{ code: 'upstream_error', requests: 2 }], byRoute: [{ averageDurationMs: 12.5, errors: 2, requests: 20, route: '/v1/tokens' }], byStatus: [{ requests: 2, status: 500 }], period: '7d', totals: { averageDurationMs: 10.5, errors: 2, requests: 25 }, }) }) }) describe('GET /organizations/:orgId/sponsorship', () => { test('returns current-period committed spend split by environment', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Sponsorship' }) await SponsoredTransactions.upsert(db, { apiKeyId: 'key_1', billable: true, chainId: Viem.chainId.mainnet, environment: 'production', feeMax: '1250000', orgId: organization.id, projectId: 'prj_1', signPayload: `0x${'11'.repeat(32)}`, transaction: `0x${'22'.repeat(32)}`, }) const response = await client.organizations[':orgId'].sponsorship.$get({ param: { orgId: organization.id }, }) const body = await TestApp.json( response, AdminOrganizations.schema.organizationSponsorship.GetResponse, ) expect(body.production).toMatchObject({ committedSpend: '1.25', currency: 'usd', period: 'month', }) expect(body.sandbox).toMatchObject({ committedSpend: '0', currency: 'usd', period: 'month', }) }) }) describe('GET /organizations/:orgId/webhooks', () => { test('redacts destinations and returns recent delivery failures', async () => { const { client, db } = TestAdmin.setup() const organization = await Organizations.create(db, { name: 'Webhooks' }) const createdAt = new Date().toISOString() await WebhookSubscriptions.insert(db, { chainId: 4217, createdAt, destination: { type: 'url', url: 'https://hooks.example.com/private/path' }, eventType: 'token:transfer', failureCount: 1, filters: {}, id: 'wh_admin_visibility', owner: { orgId: organization.id, type: 'api_key' }, secret: 'secret', status: 'active', updatedAt: createdAt, }) for (let index = 0; index < 26; index++) await WebhookDeliveries.insert( db, { attempt: 1, createdAt, envelope: { chainId: 4217, createdAt, data: {}, id: `evt_admin_visibility_${index}`, subscriptionId: 'wh_admin_visibility', type: 'token:transfer', }, error: 'HTTP 500', eventId: `evt_admin_visibility_${index}`, id: `whd_admin_visibility_${index}`, requestUrl: 'https://hooks.example.com/private/path', responseStatus: 500, status: 'failed', subscriptionId: 'wh_admin_visibility', }, new Date(Date.now() + 60_000).toISOString(), ) const oldCreatedAt = new Date(Date.now() - 8 * 24 * 60 * 60 * 1_000).toISOString() await WebhookDeliveries.insert( db, { attempt: 1, createdAt: oldCreatedAt, envelope: { chainId: 4217, createdAt: oldCreatedAt, data: {}, id: 'evt_admin_visibility_old', subscriptionId: 'wh_admin_visibility', type: 'token:transfer', }, error: 'HTTP 500', eventId: 'evt_admin_visibility_old', id: 'whd_admin_visibility_old', requestUrl: 'https://hooks.example.com/private/path', responseStatus: 500, status: 'failed', subscriptionId: 'wh_admin_visibility', }, new Date(Date.now() + 60_000).toISOString(), ) const response = await client.organizations[':orgId'].webhooks.$get({ param: { orgId: organization.id }, }) const body = await TestApp.json( response, AdminOrganizations.schema.getOrganizationWebhooks.Response, ) expect(body.subscriptions[0]?.destination).toBe('https://hooks.example.com/…') expect(body.failureCount).toBe(26) expect(body.failures).toHaveLength(25) expect(body.failures[0]).toMatchObject({ error: 'HTTP 500', responseStatus: 500 }) expect(body.failuresTruncated).toBe(true) }) }) const usageAnalytics: Analytics.Analytics = { async insert() {}, async migrate() {}, async query(sql) { if (sql.includes('GROUP BY code')) return [{ code: 'upstream_error', requests: 2 }] as never[] if (sql.includes('GROUP BY route')) return [{ averageDurationMs: 12.5, errors: 2, requests: 20, route: '/v1/tokens' }] as never[] if (sql.includes('GROUP BY status')) return [{ requests: 2, status: 500 }] as never[] if (sql.includes('GROUP BY key_id') || sql.includes('GROUP BY toStartOf')) return [] return [{ averageDurationMs: 10.5, errors: 2, requests: 25 }] as never[] }, }