tapimo 0.5.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +15830 -7220
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +9 -1
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +4 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +1011 -412
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +4 -0
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +2 -1
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/early-access.d.ts +148 -0
- package/dist/admin/apps/early-access.d.ts.map +1 -0
- package/dist/admin/apps/early-access.js +133 -0
- package/dist/admin/apps/early-access.js.map +1 -0
- package/dist/admin/apps/organizations.d.ts +124 -1
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +97 -6
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +526 -1
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +214 -1
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +95 -75
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +20 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +18 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +36 -7
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +6260 -4924
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +11 -6
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +194 -16
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +71 -0
- package/dist/apps/data/FxOracle.d.ts.map +1 -0
- package/dist/apps/data/FxOracle.js +97 -0
- package/dist/apps/data/FxOracle.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -0
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +1 -0
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +3599 -1382
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +250 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +872 -251
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/addresses.js +11 -9
- package/dist/apps/data/routes/addresses.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +77 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +88 -45
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/exchanges.d.ts +856 -105
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +518 -76
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +81 -67
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +76 -91
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +80 -36
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +65 -31
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +392 -315
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +152 -77
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +167 -174
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +15 -13
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +277 -536
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +96 -77
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +157 -81
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +272 -130
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +307 -0
- package/dist/apps/data/routes/valuation.d.ts.map +1 -0
- package/dist/apps/data/routes/valuation.js +292 -0
- package/dist/apps/data/routes/valuation.js.map +1 -0
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +7 -5
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +103 -123
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -25
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +2 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +2 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8554 -1692
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +12 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +7 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +17 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +157 -162
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +31 -23
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +232 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +154 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +60 -60
- package/dist/apps/management/routes/invite-links.d.ts +49 -20
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +26 -1
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +6 -6
- package/dist/apps/management/routes/orgs.d.ts +42 -42
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +5 -0
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +44 -44
- package/dist/apps/management/routes/usage.d.ts +3 -0
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +4 -0
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
- package/dist/apps/management/routes/verified-token-requests.js +271 -0
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
- package/dist/apps/management/routes/webhooks.d.ts +6977 -0
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
- package/dist/apps/management/routes/webhooks.js +573 -0
- package/dist/apps/management/routes/webhooks.js.map +1 -0
- package/dist/apps/mpp/App.d.ts +363 -0
- package/dist/apps/mpp/App.d.ts.map +1 -0
- package/dist/apps/mpp/App.js +72 -0
- package/dist/apps/mpp/App.js.map +1 -0
- package/dist/apps/mpp/Mpp.d.ts +178 -0
- package/dist/apps/mpp/Mpp.d.ts.map +1 -0
- package/dist/apps/mpp/Mpp.js +183 -0
- package/dist/apps/mpp/Mpp.js.map +1 -0
- package/dist/apps/mpp/index.d.ts +3 -0
- package/dist/apps/mpp/index.d.ts.map +1 -0
- package/dist/apps/mpp/index.js +3 -0
- package/dist/apps/mpp/index.js.map +1 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +56 -9
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +6 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +110 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +53 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earlyAccess.d.ts +50 -0
- package/dist/db/tables/earlyAccess.d.ts.map +1 -0
- package/dist/db/tables/earlyAccess.js +63 -0
- package/dist/db/tables/earlyAccess.js.map +1 -0
- package/dist/db/tables/enabledBillingSources.d.ts +73 -0
- package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
- package/dist/db/tables/enabledBillingSources.js +69 -0
- package/dist/db/tables/enabledBillingSources.js.map +1 -0
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +3 -0
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +10 -2
- package/dist/db/tables/inviteLinks.d.ts.map +1 -1
- package/dist/db/tables/inviteLinks.js +10 -1
- package/dist/db/tables/inviteLinks.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +5 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +13 -2
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +2 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokenRequests.js +120 -0
- package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +16 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +1 -16
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +17 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +37 -5
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +11 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +14 -47
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +147 -47
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +119 -33
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +37 -5
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +52 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +24 -0
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +2 -2
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +3 -0
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Response.d.ts +2 -2
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +12 -4
- package/dist/internal/Response.js.map +1 -1
- package/dist/internal/Schema.d.ts +14 -5
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +23 -5
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Value.d.ts +18 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +11 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +10 -1
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +24 -3
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +34 -8
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +7 -2
- package/src/App.test.ts +9 -4
- package/src/App.ts +23 -3
- package/src/Client.test-d.ts +733 -20
- package/src/Scope.ts +5 -0
- package/src/admin/App.test.ts +4 -0
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +176 -0
- package/src/admin/apps/organizations.test.ts +86 -2
- package/src/admin/apps/organizations.ts +155 -31
- package/src/admin/apps/scopes.test.ts +5 -0
- package/src/admin/apps/verified-tokens.test.ts +201 -0
- package/src/admin/apps/verified-tokens.ts +532 -286
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/lib/early-access.ts +63 -0
- package/src/admin/ui/src/lib/organizations.test.ts +81 -1
- package/src/admin/ui/src/lib/organizations.ts +92 -0
- package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
- package/src/admin/ui/src/routeTree.gen.ts +33 -2
- package/src/admin/ui/src/routes/__root.tsx +2 -1
- package/src/admin/ui/src/routes/api-keys.tsx +1 -1
- package/src/admin/ui/src/routes/early-access.tsx +162 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +95 -94
- package/src/analytics/Analytics.test.ts +83 -0
- package/src/analytics/Analytics.ts +20 -0
- package/src/analytics/tables/requestEvents.ts +60 -7
- package/src/apps/composition.test.ts +11 -2
- package/src/apps/data/App.test.ts +1 -1
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
- package/src/apps/data/FundingQuoteProviders.ts +255 -29
- package/src/apps/data/FxOracle.test.ts +118 -0
- package/src/apps/data/FxOracle.ts +153 -0
- package/src/apps/data/index.ts +1 -0
- package/src/apps/data/routes/activities.test.ts +177 -3
- package/src/apps/data/routes/activities.ts +441 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +148 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +544 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/fee-amm.test.ts +47 -23
- package/src/apps/data/routes/fee-amm.ts +98 -119
- package/src/apps/data/routes/funding.test.ts +113 -8
- package/src/apps/data/routes/funding.ts +77 -51
- package/src/apps/data/routes/receipts.test.ts +129 -23
- package/src/apps/data/routes/receipts.ts +205 -100
- package/src/apps/data/routes/tokens.test.ts +43 -0
- package/src/apps/data/routes/tokens.ts +28 -13
- package/src/apps/data/routes/transactions.test.ts +72 -19
- package/src/apps/data/routes/transactions.ts +162 -92
- package/src/apps/data/routes/transfers.test.ts +341 -31
- package/src/apps/data/routes/transfers.ts +358 -158
- package/src/apps/data/routes/valuation.test.ts +437 -0
- package/src/apps/data/routes/valuation.ts +423 -0
- package/src/apps/data/routes/verified-tokens.ts +14 -2
- package/src/apps/data/routes/webhooks.test.ts +56 -8
- package/src/apps/data/routes/webhooks.ts +144 -27
- package/src/apps/index.ts +2 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +14 -0
- package/src/apps/management/routes/api-keys.ts +27 -3
- package/src/apps/management/routes/billing.test.ts +152 -20
- package/src/apps/management/routes/billing.ts +34 -18
- package/src/apps/management/routes/faucet.test.ts +87 -0
- package/src/apps/management/routes/faucet.ts +201 -0
- package/src/apps/management/routes/invite-links.test.ts +117 -0
- package/src/apps/management/routes/invite-links.ts +43 -1
- package/src/apps/management/routes/me.test.ts +9 -99
- package/src/apps/management/routes/orgs.test.ts +45 -2
- package/src/apps/management/routes/orgs.ts +6 -0
- package/src/apps/management/routes/scopes.test.ts +1 -0
- package/src/apps/management/routes/usage.test.ts +6 -0
- package/src/apps/management/routes/usage.ts +7 -0
- package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
- package/src/apps/management/routes/verified-token-requests.ts +397 -0
- package/src/apps/management/routes/webhooks.test.ts +426 -0
- package/src/apps/management/routes/webhooks.ts +672 -0
- package/src/apps/mpp/App.ts +86 -0
- package/src/apps/mpp/Mpp.test.ts +193 -0
- package/src/apps/mpp/Mpp.ts +353 -0
- package/src/apps/mpp/index.ts +2 -0
- package/src/apps/mpp/internal/Adapter.ts +11 -0
- package/src/apps/mpp/internal/Error.ts +9 -0
- package/src/apps/mpp/internal/Idempotency.ts +7 -0
- package/src/apps/mpp/internal/Screening.ts +10 -0
- package/src/apps/relay/App.test.ts +88 -6
- package/src/apps/relay/App.ts +61 -9
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +125 -0
- package/src/db/Schema.ts +68 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/enabledBillingSources.test.ts +303 -0
- package/src/db/tables/enabledBillingSources.ts +118 -0
- package/src/db/tables/invitations.ts +3 -0
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/organizations.test.ts +103 -0
- package/src/db/tables/organizations.ts +18 -2
- package/src/db/tables/sponsoredTransactions.ts +4 -0
- package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
- package/src/db/tables/verifiedTokenRequests.ts +182 -0
- package/src/db/tables/webhookSubscriptions.ts +31 -0
- package/src/handlers/internal/utils.ts +22 -6
- package/src/handlers/relay.errors.test.ts +153 -0
- package/src/handlers/relay.ts +42 -7
- package/src/internal/Auth.test.ts +3 -3
- package/src/internal/Auth.ts +15 -47
- package/src/internal/FundingQuotes.test.ts +161 -6
- package/src/internal/FundingQuotes.ts +141 -39
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +141 -0
- package/src/internal/Log.ts +93 -6
- package/src/internal/MetricSink.test.ts +215 -0
- package/src/internal/MetricSink.ts +24 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Response.test.ts +28 -0
- package/src/internal/Response.ts +12 -4
- package/src/internal/Schema.ts +50 -5
- package/src/internal/Value.test.ts +20 -0
- package/src/internal/Value.ts +24 -1
- package/src/internal/VerifiedTokens.ts +9 -1
- package/src/internal/Webhooks.test.ts +140 -0
- package/src/internal/Webhooks.ts +53 -9
package/src/Scope.ts
CHANGED
|
@@ -49,6 +49,11 @@ export const catalog = [
|
|
|
49
49
|
scope: 'management:write',
|
|
50
50
|
selfServe: true,
|
|
51
51
|
},
|
|
52
|
+
{
|
|
53
|
+
description: 'Validate and broadcast MPP payment credentials through the Tempo relay.',
|
|
54
|
+
scope: 'mpp:write',
|
|
55
|
+
selfServe: true,
|
|
56
|
+
},
|
|
52
57
|
{
|
|
53
58
|
description: 'Fill and submit transactions through the relay.',
|
|
54
59
|
scope: 'rpc-relay:read',
|
package/src/admin/App.test.ts
CHANGED
|
@@ -20,6 +20,10 @@ describe('create', () => {
|
|
|
20
20
|
new Request('http://admin/api-keys/key_x', { method: 'DELETE' }),
|
|
21
21
|
new Request('http://admin/organizations'),
|
|
22
22
|
new Request('http://admin/organizations/org_x'),
|
|
23
|
+
new Request('http://admin/organizations/org_x/billing-sources/stripe', { method: 'PUT' }),
|
|
24
|
+
new Request('http://admin/organizations/org_x/billing-sources/stripe', {
|
|
25
|
+
method: 'DELETE',
|
|
26
|
+
}),
|
|
23
27
|
new Request('http://admin/organizations/org_x/members'),
|
|
24
28
|
new Request('http://admin/organizations/org_x/projects'),
|
|
25
29
|
new Request('http://admin/verified-tokens?chainId=42431', {
|
package/src/admin/App.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type * as Store from '../internal/Store.js'
|
|
|
11
11
|
import * as Response from '../internal/Response.js'
|
|
12
12
|
|
|
13
13
|
import { apiKeys } from './apps/api-keys.js'
|
|
14
|
+
import { earlyAccess } from './apps/early-access.js'
|
|
14
15
|
import { organizations } from './apps/organizations.js'
|
|
15
16
|
import { scopes } from './apps/scopes.js'
|
|
16
17
|
import { verifiedTokens } from './apps/verified-tokens.js'
|
|
@@ -117,6 +118,8 @@ export function create(options: create.Options) {
|
|
|
117
118
|
'/config.json',
|
|
118
119
|
'/api-keys',
|
|
119
120
|
'/api-keys/*',
|
|
121
|
+
'/early-access',
|
|
122
|
+
'/early-access/*',
|
|
120
123
|
'/organizations',
|
|
121
124
|
'/organizations/*',
|
|
122
125
|
'/scopes',
|
|
@@ -152,6 +155,7 @@ export function create(options: create.Options) {
|
|
|
152
155
|
const routed = app
|
|
153
156
|
.get('/config.json', (c) => c.json(authConfig(c.get('identity')), 200))
|
|
154
157
|
.route('/api-keys', apiKeys())
|
|
158
|
+
.route('/early-access', earlyAccess())
|
|
155
159
|
.route('/organizations', organizations())
|
|
156
160
|
.route('/scopes', scopes())
|
|
157
161
|
.route('/verified-tokens', verifiedTokens())
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as TestAdmin from '../../../test/Admin.js'
|
|
2
|
+
import * as TestApp from '../../../test/App.js'
|
|
3
|
+
import * as EarlyAccessApp from './early-access.js'
|
|
4
|
+
|
|
5
|
+
/** Lists the table's entries. */
|
|
6
|
+
async function listAdded(client: ReturnType<typeof TestAdmin.setup>['client']) {
|
|
7
|
+
const response = await client['early-access'].$get()
|
|
8
|
+
const body = await TestApp.json(response, EarlyAccessApp.schema.listEarlyAccessEntries.Response)
|
|
9
|
+
return body.data
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('authentication', () => {
|
|
13
|
+
test('denied identity → 401 on every route', async () => {
|
|
14
|
+
const { app } = TestAdmin.setup({ identify: () => null })
|
|
15
|
+
const routes = [
|
|
16
|
+
new Request('http://admin/early-access'),
|
|
17
|
+
new Request('http://admin/early-access', {
|
|
18
|
+
body: JSON.stringify({ entry: 'example.org' }),
|
|
19
|
+
headers: { 'content-type': 'application/json' },
|
|
20
|
+
method: 'POST',
|
|
21
|
+
}),
|
|
22
|
+
new Request('http://admin/early-access', {
|
|
23
|
+
body: JSON.stringify({ entry: 'example.org' }),
|
|
24
|
+
headers: { 'content-type': 'application/json' },
|
|
25
|
+
method: 'DELETE',
|
|
26
|
+
}),
|
|
27
|
+
]
|
|
28
|
+
for (const request of routes) {
|
|
29
|
+
const response = await app.request(request)
|
|
30
|
+
expect(response.status).toBe(401)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('GET /early-access', () => {
|
|
36
|
+
test('starts empty; entries are seeded through the dash, never migrations', async () => {
|
|
37
|
+
const { client } = TestAdmin.setup()
|
|
38
|
+
const response = await client['early-access'].$get()
|
|
39
|
+
const body = await TestApp.json(response, EarlyAccessApp.schema.listEarlyAccessEntries.Response)
|
|
40
|
+
|
|
41
|
+
expect(response.status).toBe(200)
|
|
42
|
+
expect(body.data).toEqual([])
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('POST /early-access', () => {
|
|
47
|
+
test('add → list → remove round-trip', async () => {
|
|
48
|
+
const { client } = TestAdmin.setup()
|
|
49
|
+
|
|
50
|
+
const created = await client['early-access'].$post({ json: { entry: 'a/b@example.org' } })
|
|
51
|
+
expect(created.status).toBe(200)
|
|
52
|
+
const body = await TestApp.json(created, EarlyAccessApp.schema.createEarlyAccessEntry.Response)
|
|
53
|
+
expect(body.data.entry).toBe('a/b@example.org')
|
|
54
|
+
// createdBy is the verified admin email, never client-supplied.
|
|
55
|
+
expect(body.data.createdBy).toBe(TestAdmin.identity.email)
|
|
56
|
+
|
|
57
|
+
expect((await listAdded(client)).map((record) => record.entry)).toEqual(['a/b@example.org'])
|
|
58
|
+
|
|
59
|
+
// Reserved URL characters stay in the JSON body.
|
|
60
|
+
const removed = await client['early-access'].$delete({ json: { entry: 'a/b@example.org' } })
|
|
61
|
+
expect(removed.status).toBe(200)
|
|
62
|
+
expect(await listAdded(client)).toEqual([])
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('normalizes the entry lowercase and trimmed', async () => {
|
|
66
|
+
const { client } = TestAdmin.setup()
|
|
67
|
+
const response = await client['early-access'].$post({ json: { entry: ' User@Example.ORG ' } })
|
|
68
|
+
const body = await TestApp.json(response, EarlyAccessApp.schema.createEarlyAccessEntry.Response)
|
|
69
|
+
|
|
70
|
+
expect(response.status).toBe(200)
|
|
71
|
+
expect(body.data.entry).toBe('user@example.org')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('rejects an invalid entry with 400', async () => {
|
|
75
|
+
const { client } = TestAdmin.setup()
|
|
76
|
+
for (const entry of ['', ' ', 'no spaces.org x', 'not-a-domain', '@example.org', 'user@']) {
|
|
77
|
+
const response = await client['early-access'].$post({ json: { entry } })
|
|
78
|
+
const body = (await response.json()) as { error?: { code?: string } }
|
|
79
|
+
expect(response.status).toBe(400)
|
|
80
|
+
expect(body.error?.code).toBe('body_invalid')
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('rejects a duplicate entry with 409', async () => {
|
|
85
|
+
const { client } = TestAdmin.setup()
|
|
86
|
+
await client['early-access'].$post({ json: { entry: 'example.org' } })
|
|
87
|
+
const duplicate = await client['early-access'].$post({ json: { entry: 'Example.org' } })
|
|
88
|
+
const body = (await duplicate.json()) as { error?: { code?: string } }
|
|
89
|
+
|
|
90
|
+
expect(duplicate.status).toBe(409)
|
|
91
|
+
expect(body.error?.code).toBe('entry_exists')
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('DELETE /early-access', () => {
|
|
96
|
+
test('removing an unknown entry → 404', async () => {
|
|
97
|
+
const { client } = TestAdmin.setup()
|
|
98
|
+
const response = await client['early-access'].$delete({
|
|
99
|
+
json: { entry: 'missing.example.org' },
|
|
100
|
+
})
|
|
101
|
+
const body = (await response.json()) as { error?: { code?: string } }
|
|
102
|
+
|
|
103
|
+
expect(response.status).toBe(404)
|
|
104
|
+
expect(body.error?.code).toBe('entry_not_found')
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('audit logging', () => {
|
|
109
|
+
test('writes an audit row for allowlist mutations', async () => {
|
|
110
|
+
const { client, db } = TestAdmin.setup()
|
|
111
|
+
await client['early-access'].$post({ json: { entry: 'example.org' } })
|
|
112
|
+
const records = await db.kysely
|
|
113
|
+
.selectFrom('admin_audit_logs')
|
|
114
|
+
.selectAll()
|
|
115
|
+
.orderBy('createdAt', 'desc')
|
|
116
|
+
.execute()
|
|
117
|
+
|
|
118
|
+
expect(records[0]).toMatchObject({
|
|
119
|
+
actor: TestAdmin.identity.email,
|
|
120
|
+
method: 'POST',
|
|
121
|
+
path: '/early-access',
|
|
122
|
+
status: 200,
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
})
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Hono } from 'hono'
|
|
2
|
+
import * as z from 'zod/mini'
|
|
3
|
+
|
|
4
|
+
import * as Db from '../../db/Db.js'
|
|
5
|
+
import * as db_Schema from '../../db/Schema.js'
|
|
6
|
+
import * as EarlyAccess from '../../db/tables/earlyAccess.js'
|
|
7
|
+
import * as OpenApi from '../../internal/OpenApi.js'
|
|
8
|
+
import * as Response from '../../internal/Response.js'
|
|
9
|
+
import * as Schema from '../../internal/Schema.js'
|
|
10
|
+
import type * as App from '../App.js'
|
|
11
|
+
|
|
12
|
+
// A bare domain (`example.org`) or a full email (`user@example.org`), matched
|
|
13
|
+
// after the trim/lowercase transforms below.
|
|
14
|
+
const entryPattern =
|
|
15
|
+
/^(?:[^\s@]+@)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/
|
|
16
|
+
|
|
17
|
+
/** Zod schemas owned by the admin early-access handler. */
|
|
18
|
+
export namespace schema {
|
|
19
|
+
/** A stored early-access allowlist entry (the `early_access` row shape). */
|
|
20
|
+
export const Entry = Schema.describe(
|
|
21
|
+
db_Schema.EarlyAccessEntry,
|
|
22
|
+
'A stored early-access allowlist entry.',
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
/** Schemas for the listEarlyAccessEntries operation. */
|
|
26
|
+
export namespace listEarlyAccessEntries {
|
|
27
|
+
/** Response body: all allowlist entries. */
|
|
28
|
+
export const Response = Schema.describe(
|
|
29
|
+
z.object({
|
|
30
|
+
data: z.array(Entry).check(z.describe('Allowlist entries, ordered by entry.')),
|
|
31
|
+
}),
|
|
32
|
+
'Accounts whose new organizations receive early access features by default.',
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Schemas for the createEarlyAccessEntry operation. */
|
|
37
|
+
export namespace createEarlyAccessEntry {
|
|
38
|
+
/** Request body for adding an allowlist entry. */
|
|
39
|
+
export const Body = z
|
|
40
|
+
.object({
|
|
41
|
+
entry: z.string().check(
|
|
42
|
+
z.trim(),
|
|
43
|
+
z.toLowerCase(),
|
|
44
|
+
z.regex(entryPattern, 'Must be a bare domain (example.org) or a full email (user@example.org).'), // prettier-ignore
|
|
45
|
+
z.describe('Domain or exact email whose new organizations receive early access features; normalized lowercase.'), // prettier-ignore
|
|
46
|
+
),
|
|
47
|
+
})
|
|
48
|
+
.check(z.describe('Request body for adding an allowlist entry.'))
|
|
49
|
+
|
|
50
|
+
/** Response body: the stored entry. */
|
|
51
|
+
export const Response = Schema.describe(
|
|
52
|
+
z.object({ data: Entry }),
|
|
53
|
+
'The stored allowlist entry.',
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Schemas for the deleteEarlyAccessEntry operation. */
|
|
58
|
+
export namespace deleteEarlyAccessEntry {
|
|
59
|
+
/** Request body addressing one allowlist entry. */
|
|
60
|
+
export const Body = z
|
|
61
|
+
.object({
|
|
62
|
+
entry: z.string().check(
|
|
63
|
+
z.trim(),
|
|
64
|
+
z.toLowerCase(),
|
|
65
|
+
z.regex(entryPattern, 'Must be a bare domain (example.org) or a full email (user@example.org).'), // prettier-ignore
|
|
66
|
+
z.describe('The allowlist entry to remove; normalized lowercase.'),
|
|
67
|
+
),
|
|
68
|
+
})
|
|
69
|
+
.check(z.describe('Request body for removing an allowlist entry.'))
|
|
70
|
+
|
|
71
|
+
/** Response body: the removed entry. */
|
|
72
|
+
export const Response = Schema.describe(
|
|
73
|
+
z.object({ data: Entry }),
|
|
74
|
+
'The removed allowlist entry.',
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Management routes for the early-access allowlist (`early_access` table).
|
|
81
|
+
* Matching users receive Stripe by default when they create an organization.
|
|
82
|
+
*
|
|
83
|
+
* - `GET /` lists entries.
|
|
84
|
+
* - `POST /` adds an entry (`409` on a duplicate).
|
|
85
|
+
* - `DELETE /` removes an entry (`404` if absent).
|
|
86
|
+
*/
|
|
87
|
+
export function earlyAccess() {
|
|
88
|
+
return new Hono<App.Environment>()
|
|
89
|
+
.get(
|
|
90
|
+
'/',
|
|
91
|
+
OpenApi.describeRoute({
|
|
92
|
+
operationId: 'listEarlyAccessEntries',
|
|
93
|
+
responses: OpenApi.responses({
|
|
94
|
+
success: {
|
|
95
|
+
description:
|
|
96
|
+
'Accounts whose new organizations receive early access features by default.',
|
|
97
|
+
schema: schema.listEarlyAccessEntries.Response,
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
summary: 'List early access',
|
|
101
|
+
tags: ['Early Access'],
|
|
102
|
+
}),
|
|
103
|
+
async (c) => {
|
|
104
|
+
const db = Db.get(c.get('db'))
|
|
105
|
+
return c.json(
|
|
106
|
+
Response.validated(schema.listEarlyAccessEntries.Response, {
|
|
107
|
+
data: await EarlyAccess.list(db),
|
|
108
|
+
}),
|
|
109
|
+
)
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
.post(
|
|
113
|
+
'/',
|
|
114
|
+
OpenApi.validate('json', schema.createEarlyAccessEntry.Body, {
|
|
115
|
+
code: 'body_invalid',
|
|
116
|
+
message: 'Invalid request body',
|
|
117
|
+
}),
|
|
118
|
+
OpenApi.describeRoute({
|
|
119
|
+
operationId: 'createEarlyAccessEntry',
|
|
120
|
+
responses: OpenApi.responses({
|
|
121
|
+
errors: { 409: 'Entry already exists.' },
|
|
122
|
+
success: {
|
|
123
|
+
description: 'The stored allowlist entry.',
|
|
124
|
+
schema: schema.createEarlyAccessEntry.Response,
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
summary: 'Add early-access entry',
|
|
128
|
+
tags: ['Early Access'],
|
|
129
|
+
}),
|
|
130
|
+
async (c) => {
|
|
131
|
+
const db = Db.get(c.get('db'))
|
|
132
|
+
const { entry } = c.req.valid('json')
|
|
133
|
+
// `createdBy` is the verified admin email; `requireAuth` guarantees
|
|
134
|
+
// identity on this gated route.
|
|
135
|
+
const record = await EarlyAccess.add(db, { createdBy: c.get('identity')!.email, entry })
|
|
136
|
+
if (!record)
|
|
137
|
+
return Response.error(c, {
|
|
138
|
+
code: 'entry_exists',
|
|
139
|
+
message: 'Entry already exists.',
|
|
140
|
+
status: 409,
|
|
141
|
+
})
|
|
142
|
+
return c.json(Response.validated(schema.createEarlyAccessEntry.Response, { data: record }))
|
|
143
|
+
},
|
|
144
|
+
)
|
|
145
|
+
.delete(
|
|
146
|
+
'/',
|
|
147
|
+
OpenApi.validate('json', schema.deleteEarlyAccessEntry.Body, {
|
|
148
|
+
code: 'body_invalid',
|
|
149
|
+
message: 'Invalid request body',
|
|
150
|
+
}),
|
|
151
|
+
OpenApi.describeRoute({
|
|
152
|
+
operationId: 'deleteEarlyAccessEntry',
|
|
153
|
+
responses: OpenApi.responses({
|
|
154
|
+
errors: { 404: 'Entry not found.' },
|
|
155
|
+
success: {
|
|
156
|
+
description: 'The removed allowlist entry.',
|
|
157
|
+
schema: schema.deleteEarlyAccessEntry.Response,
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
summary: 'Remove early-access entry',
|
|
161
|
+
tags: ['Early Access'],
|
|
162
|
+
}),
|
|
163
|
+
async (c) => {
|
|
164
|
+
const db = Db.get(c.get('db'))
|
|
165
|
+
const { entry } = c.req.valid('json')
|
|
166
|
+
const record = await EarlyAccess.remove(db, entry)
|
|
167
|
+
if (!record)
|
|
168
|
+
return Response.error(c, {
|
|
169
|
+
code: 'entry_not_found',
|
|
170
|
+
message: 'Entry not found.',
|
|
171
|
+
status: 404,
|
|
172
|
+
})
|
|
173
|
+
return c.json(Response.validated(schema.deleteEarlyAccessEntry.Response, { data: record }))
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type * as Analytics from '../../analytics/Analytics.js'
|
|
2
2
|
import * as ApiKeys from '../../ApiKeys.js'
|
|
3
3
|
import * as BillingSettings from '../../db/tables/billingSettings.js'
|
|
4
|
+
import * as EnabledBillingSources from '../../db/tables/enabledBillingSources.js'
|
|
4
5
|
import * as Memberships from '../../db/tables/memberships.js'
|
|
5
6
|
import * as Organizations from '../../db/tables/organizations.js'
|
|
6
7
|
import * as Projects from '../../db/tables/projects.js'
|
|
@@ -134,6 +135,16 @@ describe('GET /organizations/:orgId', () => {
|
|
|
134
135
|
})
|
|
135
136
|
await Users.setEmail(db, user.id, 'owner@tempo.xyz')
|
|
136
137
|
const organization = await Organizations.createOwned(db, { name: 'Tempo', userId: user.id })
|
|
138
|
+
await EnabledBillingSources.add(db, {
|
|
139
|
+
createdBy: TestAdmin.identity.email,
|
|
140
|
+
orgId: organization.id,
|
|
141
|
+
source: 'stripe',
|
|
142
|
+
})
|
|
143
|
+
await EnabledBillingSources.add(db, {
|
|
144
|
+
createdBy: TestAdmin.identity.email,
|
|
145
|
+
orgId: organization.id,
|
|
146
|
+
source: 'tempo',
|
|
147
|
+
})
|
|
137
148
|
await Projects.create(db, { name: 'API', orgId: organization.id })
|
|
138
149
|
await BillingSettings.upsert(db, {
|
|
139
150
|
environment: 'production',
|
|
@@ -161,6 +172,7 @@ describe('GET /organizations/:orgId', () => {
|
|
|
161
172
|
expect(response.status).toBe(200)
|
|
162
173
|
expect(body.memberCount).toBe(1)
|
|
163
174
|
expect(body.projectCount).toBe(1)
|
|
175
|
+
expect(body.billing.enabledSources).toEqual(['stripe', 'tempo'])
|
|
164
176
|
expect(body.billing.production).toMatchObject({
|
|
165
177
|
settings: { spendLimit: '250', txFeeLimit: '0.50' },
|
|
166
178
|
source: { status: 'active', stripeCustomerId: 'cus_admin_lookup' },
|
|
@@ -182,6 +194,7 @@ describe('GET /organizations/:orgId', () => {
|
|
|
182
194
|
|
|
183
195
|
expect(body).toMatchObject({
|
|
184
196
|
billing: {
|
|
197
|
+
enabledSources: [],
|
|
185
198
|
production: { settings: null, source: null },
|
|
186
199
|
sandbox: { settings: null, source: null },
|
|
187
200
|
},
|
|
@@ -202,6 +215,78 @@ describe('GET /organizations/:orgId', () => {
|
|
|
202
215
|
})
|
|
203
216
|
})
|
|
204
217
|
|
|
218
|
+
describe('PUT/DELETE /organizations/:orgId/billing-sources/:source', () => {
|
|
219
|
+
test('enables and disables sources idempotently', async () => {
|
|
220
|
+
const { client, db } = TestAdmin.setup()
|
|
221
|
+
const organization = await Organizations.create(db, { name: 'Billing sources' })
|
|
222
|
+
|
|
223
|
+
for (const source of ['tempo', 'stripe', 'stripe'] as const) {
|
|
224
|
+
const response = await client.organizations[':orgId']['billing-sources'][':source'].$put({
|
|
225
|
+
param: { orgId: organization.id, source },
|
|
226
|
+
})
|
|
227
|
+
const body = await TestApp.json(response, AdminOrganizations.schema.setBillingSource.Response)
|
|
228
|
+
expect(response.status).toBe(200)
|
|
229
|
+
expect(body.data).toEqual(source === 'tempo' ? ['tempo'] : ['stripe', 'tempo'])
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
expect(await EnabledBillingSources.listByOrg(db, organization.id)).toMatchObject([
|
|
233
|
+
{ createdBy: TestAdmin.identity.email, source: 'stripe' },
|
|
234
|
+
{ createdBy: TestAdmin.identity.email, source: 'tempo' },
|
|
235
|
+
])
|
|
236
|
+
|
|
237
|
+
for (const source of ['stripe', 'stripe'] as const) {
|
|
238
|
+
const response = await client.organizations[':orgId']['billing-sources'][':source'].$delete({
|
|
239
|
+
param: { orgId: organization.id, source },
|
|
240
|
+
})
|
|
241
|
+
const body = await TestApp.json(response, AdminOrganizations.schema.setBillingSource.Response)
|
|
242
|
+
expect(response.status).toBe(200)
|
|
243
|
+
expect(body.data).toEqual(['tempo'])
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const detailResponse = await client.organizations[':orgId'].$get({
|
|
247
|
+
param: { orgId: organization.id },
|
|
248
|
+
})
|
|
249
|
+
const detail = await TestApp.json(
|
|
250
|
+
detailResponse,
|
|
251
|
+
AdminOrganizations.schema.getOrganization.Response,
|
|
252
|
+
)
|
|
253
|
+
expect(detail.billing.enabledSources).toEqual(['tempo'])
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('rejects unsupported sources and unknown organizations', async () => {
|
|
257
|
+
const { app, client } = TestAdmin.setup()
|
|
258
|
+
const invalid = await app.request('/organizations/org_example/billing-sources/card', {
|
|
259
|
+
method: 'PUT',
|
|
260
|
+
})
|
|
261
|
+
expect(invalid.status).toBe(400)
|
|
262
|
+
|
|
263
|
+
const missing = await client.organizations[':orgId']['billing-sources'][':source'].$put({
|
|
264
|
+
param: { orgId: 'org_missing', source: 'stripe' },
|
|
265
|
+
})
|
|
266
|
+
expect(missing.status).toBe(404)
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
test('records billing-source mutations in the admin audit log', async () => {
|
|
270
|
+
const { client, db } = TestAdmin.setup()
|
|
271
|
+
const organization = await Organizations.create(db, { name: 'Audited billing' })
|
|
272
|
+
await client.organizations[':orgId']['billing-sources'][':source'].$put({
|
|
273
|
+
param: { orgId: organization.id, source: 'tempo' },
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
const records = await db.kysely
|
|
277
|
+
.selectFrom('admin_audit_logs')
|
|
278
|
+
.selectAll()
|
|
279
|
+
.orderBy('createdAt', 'desc')
|
|
280
|
+
.execute()
|
|
281
|
+
expect(records[0]).toMatchObject({
|
|
282
|
+
actor: TestAdmin.identity.email,
|
|
283
|
+
method: 'PUT',
|
|
284
|
+
path: `/organizations/${organization.id}/billing-sources/tempo`,
|
|
285
|
+
status: 200,
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
})
|
|
289
|
+
|
|
205
290
|
describe('GET /organizations/:orgId/members', () => {
|
|
206
291
|
test('returns a bounded cursor page without duplicates', async () => {
|
|
207
292
|
const { client, db } = TestAdmin.setup()
|
|
@@ -444,8 +529,7 @@ const usageAnalytics: Analytics.Analytics = {
|
|
|
444
529
|
async insert() {},
|
|
445
530
|
async migrate() {},
|
|
446
531
|
async query(sql) {
|
|
447
|
-
if (sql.includes('GROUP BY
|
|
448
|
-
return [{ code: 'upstream_error', requests: 2 }] as never[]
|
|
532
|
+
if (sql.includes('GROUP BY code')) return [{ code: 'upstream_error', requests: 2 }] as never[]
|
|
449
533
|
if (sql.includes('GROUP BY route'))
|
|
450
534
|
return [{ averageDurationMs: 12.5, errors: 2, requests: 20, route: '/v1/tokens' }] as never[]
|
|
451
535
|
if (sql.includes('GROUP BY status')) return [{ requests: 2, status: 500 }] as never[]
|