tapimo 0.19.0 → 0.20.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/README.md +13 -5
- package/dist/ApiKey.d.ts +2 -2
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +2 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +85 -11
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +218 -56
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +12543 -13912
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +4 -5
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +12 -20
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +20 -36
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +871 -828
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +14 -26
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +93 -186
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +3 -5
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/audit-logs.d.ts +18 -18
- package/dist/admin/apps/audit-logs.js +1 -1
- package/dist/admin/apps/audit-logs.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +27 -27
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +11 -5
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +17 -17
- package/dist/admin/apps/prop-amms.d.ts +4 -4
- package/dist/admin/apps/routes-support.js +1 -38
- package/dist/admin/apps/routes-support.js.map +1 -1
- package/dist/admin/apps/routes.d.ts +153 -153
- package/dist/admin/apps/sentinel.d.ts +4 -4
- package/dist/admin/apps/verified-tokens.d.ts +24 -24
- package/dist/admin/apps/zone-delegation-requests.d.ts +332 -0
- package/dist/admin/apps/zone-delegation-requests.d.ts.map +1 -0
- package/dist/admin/apps/zone-delegation-requests.js +200 -0
- package/dist/admin/apps/zone-delegation-requests.js.map +1 -0
- package/dist/admin/apps/zone-delegations.d.ts +512 -52
- package/dist/admin/apps/zone-delegations.d.ts.map +1 -1
- package/dist/admin/apps/zone-delegations.js +134 -44
- package/dist/admin/apps/zone-delegations.js.map +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.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 +341 -397
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +4 -2
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +11932 -13214
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +32 -13
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/ZoneSelection.d.ts +1 -1
- package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
- package/dist/apps/data/ZoneSelection.js +2 -2
- package/dist/apps/data/ZoneSelection.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +60 -27
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +91 -16
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +893 -875
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +36 -36
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +3 -1
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +40 -40
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +3 -7
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +236 -236
- package/dist/apps/data/routes/earn-transactions.d.ts +14 -14
- package/dist/apps/data/routes/earn.d.ts +261 -1445
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +64 -490
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +144 -144
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +5 -15
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +3 -9
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +13 -13
- package/dist/apps/data/routes/receipts.d.ts +53 -53
- package/dist/apps/data/routes/receipts.js +1 -1
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +52 -0
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +19 -18
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +14 -14
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +1 -3
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +7 -5
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +281 -281
- package/dist/apps/data/routes/transactions.js +3 -3
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +12 -12
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +1 -3
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +30 -30
- package/dist/apps/data/routes/valuation.d.ts.map +1 -1
- package/dist/apps/data/routes/valuation.js +1 -3
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
- package/dist/apps/data/routes/webhooks.d.ts +102 -102
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +9 -23
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zone-deposits.d.ts +16 -16
- package/dist/apps/data/routes/zone-withdrawals.d.ts +31 -31
- package/dist/apps/data/routes/zones.d.ts +28 -28
- package/dist/apps/management/App.d.ts +18 -102
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +1 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +253 -339
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +25 -11
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +92 -92
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +5 -13
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/cli.d.ts.map +1 -1
- package/dist/apps/management/routes/cli.js +3 -9
- package/dist/apps/management/routes/cli.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +16 -16
- package/dist/apps/management/routes/fee-payer-usage.d.ts +38 -38
- package/dist/apps/management/routes/fee-payer-usage.d.ts.map +1 -1
- package/dist/apps/management/routes/fee-payer-usage.js +2 -4
- package/dist/apps/management/routes/fee-payer-usage.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +52 -52
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +4 -12
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +6 -14
- 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/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +3 -7
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +84 -84
- package/dist/apps/management/routes/members.d.ts.map +1 -1
- package/dist/apps/management/routes/members.js +2 -4
- package/dist/apps/management/routes/members.js.map +1 -1
- package/dist/apps/management/routes/orgs.d.ts +44 -44
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +2 -6
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts.map +1 -1
- package/dist/apps/management/routes/projects.js +2 -6
- package/dist/apps/management/routes/projects.js.map +1 -1
- package/dist/apps/management/routes/route-usage.d.ts +34 -34
- package/dist/apps/management/routes/route-usage.d.ts.map +1 -1
- package/dist/apps/management/routes/route-usage.js +2 -4
- package/dist/apps/management/routes/route-usage.js.map +1 -1
- package/dist/apps/management/routes/routes-access-requests.d.ts +120 -91
- package/dist/apps/management/routes/routes-access-requests.d.ts.map +1 -1
- package/dist/apps/management/routes/routes-access-requests.js +49 -9
- package/dist/apps/management/routes/routes-access-requests.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +8 -16
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +39 -39
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.js +3 -7
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
- package/dist/apps/management/routes/webhooks.d.ts +2089 -2089
- package/dist/apps/management/routes/zone-delegations.d.ts +14 -17
- package/dist/apps/management/routes/zone-delegations.d.ts.map +1 -1
- package/dist/apps/management/routes/zone-delegations.js +1 -6
- package/dist/apps/management/routes/zone-delegations.js.map +1 -1
- package/dist/apps/mpp/App.d.ts +44 -44
- package/dist/apps/mpp/App.js +3 -3
- package/dist/apps/mpp/App.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.js +1 -1
- package/dist/apps/mpp/internal/Adapter.js.map +1 -1
- package/dist/apps/mpp/internal/Error.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Error.js +1 -0
- package/dist/apps/mpp/internal/Error.js.map +1 -1
- package/dist/apps/mpp/internal/Policy.d.ts +5 -1
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Policy.js +35 -13
- package/dist/apps/mpp/internal/Policy.js.map +1 -1
- package/dist/apps/relay/App.d.ts +2 -2
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +25 -16
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/routes/App.d.ts +311 -311
- package/dist/apps/routes/routes/deposit-addresses.d.ts +1099 -1099
- package/dist/apps/routes/routes/list.d.ts +74 -74
- package/dist/apps/routes/routes/transfers.d.ts +94 -94
- package/dist/cli/ApiKeys.d.ts +19 -26
- package/dist/cli/ApiKeys.d.ts.map +1 -1
- package/dist/db/Db.d.ts +3 -3
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +27 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +28 -62
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +18 -18
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/rewardRuns.d.ts +21 -0
- package/dist/db/tables/rewardRuns.d.ts.map +1 -1
- package/dist/db/tables/rewardRuns.js +19 -0
- package/dist/db/tables/rewardRuns.js.map +1 -1
- package/dist/db/tables/routesAccessRequests.d.ts +13 -0
- package/dist/db/tables/routesAccessRequests.d.ts.map +1 -1
- package/dist/db/tables/routesAccessRequests.js +12 -0
- package/dist/db/tables/routesAccessRequests.js.map +1 -1
- package/dist/db/tables/zoneDelegationRequests.d.ts +165 -0
- package/dist/db/tables/zoneDelegationRequests.d.ts.map +1 -0
- package/dist/db/tables/{zoneKeyRequests.js → zoneDelegationRequests.js} +43 -42
- package/dist/db/tables/zoneDelegationRequests.js.map +1 -0
- package/dist/db/tables/zoneDelegations.d.ts +11 -5
- package/dist/db/tables/zoneDelegations.d.ts.map +1 -1
- package/dist/db/tables/zoneDelegations.js +21 -3
- package/dist/db/tables/zoneDelegations.js.map +1 -1
- package/dist/handlers/internal/accounts.d.ts +7 -0
- package/dist/handlers/internal/accounts.d.ts.map +1 -0
- package/dist/handlers/internal/{multisig.js → accounts.js} +10 -10
- package/dist/handlers/internal/{multisig.js.map → accounts.js.map} +1 -1
- package/dist/handlers/internal/sponsorship.js +17 -17
- package/dist/handlers/internal/sponsorship.js.map +1 -1
- package/dist/handlers/relay.d.ts +6 -6
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +15 -15
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +4 -8
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EarnRates.d.ts.map +1 -1
- package/dist/internal/EarnRates.js +1 -3
- package/dist/internal/EarnRates.js.map +1 -1
- package/dist/internal/EarnVaults.js +2 -2
- package/dist/internal/Log.d.ts +2 -4
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +0 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/Response.d.ts +1 -1
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +0 -3
- package/dist/internal/Response.js.map +1 -1
- package/dist/internal/Schema.d.ts +11 -0
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +24 -1
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/ZoneAccess.d.ts +70 -35
- package/dist/internal/ZoneAccess.d.ts.map +1 -1
- package/dist/internal/ZoneAccess.js +312 -131
- package/dist/internal/ZoneAccess.js.map +1 -1
- package/dist/internal/ZoneDelegation.d.ts +7 -19
- package/dist/internal/ZoneDelegation.d.ts.map +1 -1
- package/dist/internal/ZoneDelegation.js +8 -29
- package/dist/internal/ZoneDelegation.js.map +1 -1
- package/dist/internal/{ZoneKeyApproval.d.ts → ZoneDelegationApproval.d.ts} +3 -5
- package/dist/internal/ZoneDelegationApproval.d.ts.map +1 -0
- package/dist/internal/ZoneDelegationApproval.js +16 -0
- package/dist/internal/ZoneDelegationApproval.js.map +1 -0
- package/dist/internal/ZoneKeyRewrite.d.ts +98 -0
- package/dist/internal/ZoneKeyRewrite.d.ts.map +1 -0
- package/dist/internal/ZoneKeyRewrite.js +151 -0
- package/dist/internal/ZoneKeyRewrite.js.map +1 -0
- package/dist/internal/rewards/Campaigns.d.ts +2 -0
- package/dist/internal/rewards/Campaigns.d.ts.map +1 -1
- package/dist/internal/rewards/Campaigns.js.map +1 -1
- package/dist/internal/rewards/Distributions.d.ts.map +1 -1
- package/dist/internal/rewards/Distributions.js +2 -6
- package/dist/internal/rewards/Distributions.js.map +1 -1
- package/dist/internal/rewards/Monitor.d.ts +4 -1
- package/dist/internal/rewards/Monitor.d.ts.map +1 -1
- package/dist/internal/rewards/Monitor.js +19 -2
- package/dist/internal/rewards/Monitor.js.map +1 -1
- package/dist/internal/rewards/Runner.d.ts.map +1 -1
- package/dist/internal/rewards/Runner.js +9 -1
- package/dist/internal/rewards/Runner.js.map +1 -1
- package/dist/internal/routes/Action.d.ts.map +1 -1
- package/dist/internal/routes/Action.js +2 -3
- package/dist/internal/routes/Action.js.map +1 -1
- package/dist/internal/routes/Deposit.d.ts.map +1 -1
- package/dist/internal/routes/Deposit.js +2 -6
- package/dist/internal/routes/Deposit.js.map +1 -1
- package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
- package/dist/internal/routes/DepositAddress.js +4 -10
- package/dist/internal/routes/DepositAddress.js.map +1 -1
- package/dist/internal/routes/Policy.d.ts.map +1 -1
- package/dist/internal/routes/Policy.js +2 -1
- package/dist/internal/routes/Policy.js.map +1 -1
- package/dist/internal/routes/Provider.js +8 -8
- package/dist/internal/routes/Provider.js.map +1 -1
- package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
- package/dist/internal/routes/Reconciliation.js +3 -2
- package/dist/internal/routes/Reconciliation.js.map +1 -1
- package/dist/internal/routes/Transfer.d.ts.map +1 -1
- package/dist/internal/routes/Transfer.js +4 -12
- package/dist/internal/routes/Transfer.js.map +1 -1
- package/dist/internal/routes/UniversalDepositAddress.d.ts.map +1 -1
- package/dist/internal/routes/UniversalDepositAddress.js +3 -6
- package/dist/internal/routes/UniversalDepositAddress.js.map +1 -1
- package/dist/internal/routes/providers/SquidOrder.d.ts.map +1 -1
- package/dist/internal/routes/providers/SquidOrder.js +3 -2
- package/dist/internal/routes/providers/SquidOrder.js.map +1 -1
- package/dist/internal/routes/providers/relay.d.ts.map +1 -1
- package/dist/internal/routes/providers/relay.js +4 -3
- package/dist/internal/routes/providers/relay.js.map +1 -1
- package/package.json +20 -5
- package/src/ApiKey.ts +2 -2
- package/src/ApiKeys.test.ts +284 -51
- package/src/ApiKeys.ts +297 -64
- package/src/App.ts +4 -5
- package/src/Client.test-d.ts +33 -126
- package/src/Scope.test.ts +26 -45
- package/src/Scope.ts +24 -37
- package/src/admin/App.test.ts +51 -4
- package/src/admin/App.ts +25 -33
- package/src/admin/Mcp.test.ts +2 -1
- package/src/admin/apps/api-keys.test.ts +90 -20
- package/src/admin/apps/api-keys.ts +5 -8
- package/src/admin/apps/audit-logs.ts +1 -1
- package/src/admin/apps/earn-vaults.test.ts +19 -19
- package/src/admin/apps/earn-vaults.ts +11 -5
- package/src/admin/apps/routes-support.test.ts +254 -3
- package/src/admin/apps/routes-support.ts +1 -44
- package/src/admin/apps/scopes.test.ts +3 -3
- package/src/admin/apps/zone-delegation-requests.test.ts +246 -0
- package/src/admin/apps/zone-delegation-requests.ts +240 -0
- package/src/admin/apps/zone-delegations.test.ts +218 -58
- package/src/admin/apps/zone-delegations.ts +146 -46
- package/src/admin/index.ts +1 -1
- package/src/admin/ui/src/components/ApiKeyForm.tsx +4 -3
- package/src/admin/ui/src/lib/config.ts +3 -3
- package/src/admin/ui/src/lib/query-client.ts +1 -1
- package/src/admin/ui/src/lib/review-queues.ts +10 -10
- package/src/admin/ui/src/lib/routes-setup.test.ts +1 -2
- package/src/admin/ui/src/lib/routes-setup.ts +3 -5
- package/src/admin/ui/src/lib/scopes.test.ts +3 -6
- package/src/admin/ui/src/lib/scopes.ts +2 -9
- package/src/admin/ui/src/lib/{zone-key-requests.ts → zone-delegation-requests.ts} +27 -31
- package/src/admin/ui/src/routeTree.gen.ts +17 -17
- package/src/admin/ui/src/routes/__root.tsx +1 -1
- package/src/admin/ui/src/routes/api-keys.tsx +2 -15
- package/src/admin/ui/src/routes/audit-logs.tsx +2 -2
- package/src/admin/ui/src/routes/index.tsx +11 -11
- package/src/admin/ui/src/routes/organizations.tsx +3 -1
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +3 -1
- package/src/admin/ui/src/routes/organizations_.$orgId_.setup.tsx +1 -3
- package/src/admin/ui/src/routes/{zone-key-requests.tsx → zone-delegation-requests.tsx} +228 -172
- package/src/admin/ui/vite.config.ts +14 -1
- package/src/admin/ui.generated.ts +412 -583
- package/src/analytics/tables/requestEvents.test.ts +13 -3
- package/src/analytics/tables/requestEvents.ts +4 -3
- package/src/apps/data/App.test.ts +72 -35
- package/src/apps/data/App.ts +29 -13
- package/src/apps/data/ZoneSelection.test.ts +53 -70
- package/src/apps/data/ZoneSelection.ts +2 -2
- package/src/apps/data/routes/activities.test.ts +140 -6
- package/src/apps/data/routes/activities.ts +124 -18
- package/src/apps/data/routes/balances.ts +5 -1
- package/src/apps/data/routes/blocks.ts +9 -13
- package/src/apps/data/routes/earn-transactions.local.test.ts +6 -1
- package/src/apps/data/routes/earn-transactions.test.ts +7 -3
- package/src/apps/data/routes/earn.bench.ts +0 -14
- package/src/apps/data/routes/earn.discovery.test.ts +4 -39
- package/src/apps/data/routes/earn.local.test.ts +27 -34
- package/src/apps/data/routes/earn.test.ts +172 -490
- package/src/apps/data/routes/earn.ts +103 -652
- package/src/apps/data/routes/exchanges.ts +20 -30
- package/src/apps/data/routes/fee-amm.ts +12 -18
- package/src/apps/data/routes/indexer.test.ts +14 -12
- package/src/apps/data/routes/receipts.ts +1 -1
- package/src/apps/data/routes/rpc.test.ts +23 -18
- package/src/apps/data/routes/rpc.ts +21 -21
- package/src/apps/data/routes/rpc.zone.test.ts +60 -6
- package/src/apps/data/routes/tokenlist.ts +4 -6
- package/src/apps/data/routes/tokens.test.ts +20 -0
- package/src/apps/data/routes/tokens.ts +10 -5
- package/src/apps/data/routes/transactions.ts +3 -3
- package/src/apps/data/routes/transfers.ts +4 -6
- package/src/apps/data/routes/valuation.test.ts +2 -4
- package/src/apps/data/routes/valuation.ts +4 -6
- package/src/apps/data/routes/webhooks.test.ts +1 -5
- package/src/apps/data/routes/webhooks.ts +30 -44
- package/src/apps/data/routes/zones.test.ts +35 -19
- package/src/apps/management/App.ts +3 -1
- package/src/apps/management/routes/api-keys.test.ts +112 -22
- package/src/apps/management/routes/api-keys.ts +30 -15
- package/src/apps/management/routes/billing.ts +17 -25
- package/src/apps/management/routes/cli.ts +12 -18
- package/src/apps/management/routes/fee-payer-usage.ts +5 -4
- package/src/apps/management/routes/invitations.ts +16 -21
- package/src/apps/management/routes/invite-links.ts +18 -26
- package/src/apps/management/routes/me.ts +9 -13
- package/src/apps/management/routes/members.ts +5 -7
- package/src/apps/management/routes/orgs.ts +8 -12
- package/src/apps/management/routes/projects.ts +8 -12
- package/src/apps/management/routes/route-usage.ts +5 -4
- package/src/apps/management/routes/routes-access-requests.test.ts +64 -2
- package/src/apps/management/routes/routes-access-requests.ts +99 -15
- package/src/apps/management/routes/scopes.test.ts +3 -3
- package/src/apps/management/routes/usage.ts +20 -28
- package/src/apps/management/routes/verified-token-requests.ts +9 -13
- package/src/apps/management/routes/zone-delegations.test.ts +3 -5
- package/src/apps/management/routes/zone-delegations.ts +4 -9
- package/src/apps/mpp/App.ts +3 -3
- package/src/apps/mpp/Mpp.zone.test.ts +49 -18
- package/src/apps/mpp/internal/Adapter.ts +1 -1
- package/src/apps/mpp/internal/Error.test.ts +3 -0
- package/src/apps/mpp/internal/Error.ts +1 -0
- package/src/apps/mpp/internal/Policy.test.ts +9 -8
- package/src/apps/mpp/internal/Policy.ts +37 -14
- package/src/apps/relay/App.sandbox.test.ts +15 -14
- package/src/apps/relay/App.test.ts +120 -61
- package/src/apps/relay/App.ts +28 -18
- package/src/apps/relay/App.zone-billing.test.ts +9 -4
- package/src/apps/routes/App.test.ts +21 -22
- package/src/db/Db.ts +34 -3
- package/src/db/Schema.ts +26 -26
- package/src/db/tables/rewardRuns.ts +39 -0
- package/src/db/tables/routesAccessRequests.test.ts +65 -0
- package/src/db/tables/routesAccessRequests.ts +25 -0
- package/src/db/tables/{zoneKeyRequests.test.ts → zoneDelegationRequests.test.ts} +36 -77
- package/src/db/tables/{zoneKeyRequests.ts → zoneDelegationRequests.ts} +69 -52
- package/src/db/tables/zoneDelegations.test.ts +5 -6
- package/src/db/tables/zoneDelegations.ts +25 -8
- package/src/handlers/internal/{multisig.store.test.ts → accounts.store.test.ts} +16 -16
- package/src/handlers/internal/{multisig.test.ts → accounts.test.ts} +85 -82
- package/src/handlers/internal/{multisig.ts → accounts.ts} +9 -9
- package/src/handlers/internal/sponsorship.ts +20 -20
- package/src/handlers/relay.test.ts +48 -46
- package/src/handlers/relay.ts +26 -26
- package/src/internal/Auth.test.ts +6 -2
- package/src/internal/Auth.ts +4 -10
- package/src/internal/EarnRates.ts +4 -6
- package/src/internal/EarnVaults.ts +2 -2
- package/src/internal/Log.test-d.ts +1 -0
- package/src/internal/Log.test.ts +4 -6
- package/src/internal/Log.ts +2 -6
- package/src/internal/Response.ts +0 -3
- package/src/internal/Schema.test.ts +42 -0
- package/src/internal/Schema.ts +36 -1
- package/src/internal/ZoneAccess.test.ts +515 -312
- package/src/internal/ZoneAccess.ts +410 -158
- package/src/internal/ZoneDelegation.test.ts +1 -41
- package/src/internal/ZoneDelegation.ts +10 -48
- package/src/internal/ZoneDelegationApproval.test.ts +22 -0
- package/src/internal/{ZoneKeyApproval.ts → ZoneDelegationApproval.ts} +4 -11
- package/src/internal/ZoneKeyRewrite.ts +231 -0
- package/src/internal/rewards/Campaigns.ts +2 -0
- package/src/internal/rewards/Distributions.ts +8 -12
- package/src/internal/rewards/Monitor.test.ts +64 -0
- package/src/internal/rewards/Monitor.ts +27 -4
- package/src/internal/rewards/Runner.ts +9 -1
- package/src/internal/routes/Action.ts +5 -6
- package/src/internal/routes/Deposit.ts +8 -12
- package/src/internal/routes/DepositAddress.ts +13 -19
- package/src/internal/routes/Policy.ts +2 -1
- package/src/internal/routes/Provider.ts +8 -8
- package/src/internal/routes/Reconciliation.ts +3 -2
- package/src/internal/routes/Transfer.ts +16 -24
- package/src/internal/routes/UniversalDepositAddress.ts +9 -12
- package/src/internal/routes/providers/SquidOrder.ts +3 -2
- package/src/internal/routes/providers/relay.ts +4 -3
- package/dist/admin/apps/zone-key-requests.d.ts +0 -406
- package/dist/admin/apps/zone-key-requests.d.ts.map +0 -1
- package/dist/admin/apps/zone-key-requests.js +0 -183
- package/dist/admin/apps/zone-key-requests.js.map +0 -1
- package/dist/db/tables/zoneKeyRequests.d.ts +0 -289
- package/dist/db/tables/zoneKeyRequests.d.ts.map +0 -1
- package/dist/db/tables/zoneKeyRequests.js.map +0 -1
- package/dist/handlers/internal/multisig.d.ts +0 -7
- package/dist/handlers/internal/multisig.d.ts.map +0 -1
- package/dist/internal/ZoneKeyApproval.d.ts.map +0 -1
- package/dist/internal/ZoneKeyApproval.js +0 -21
- package/dist/internal/ZoneKeyApproval.js.map +0 -1
- package/src/admin/apps/zone-key-requests.test.ts +0 -272
- package/src/admin/apps/zone-key-requests.ts +0 -231
- package/src/internal/ZoneKeyApproval.test.ts +0 -46
package/src/ApiKeys.test.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { sql } from 'kysely'
|
|
2
2
|
|
|
3
|
+
import * as ApiKey from './ApiKey.js'
|
|
3
4
|
import * as ApiKeys from './ApiKeys.js'
|
|
4
5
|
import * as ApiKeyAdmissions from './db/tables/apiKeyAdmissions.js'
|
|
5
6
|
import * as ApiKeyOwnerTombstones from './db/tables/apiKeyOwnerTombstones.js'
|
|
6
7
|
import * as ApiKeyRevocations from './db/tables/apiKeyRevocations.js'
|
|
7
8
|
import * as Organizations from './db/tables/organizations.js'
|
|
9
|
+
import * as ZoneDelegations from './db/tables/zoneDelegations.js'
|
|
8
10
|
import * as Projects from './db/tables/projects.js'
|
|
9
11
|
import * as RoutesPolicies from './db/tables/routesPolicies.js'
|
|
10
12
|
import * as Store from './internal/Store.js'
|
|
11
|
-
import * as ZoneKeyApproval from './internal/ZoneKeyApproval.js'
|
|
12
13
|
import * as Scope from './Scope.js'
|
|
13
14
|
import * as TestApp from '../test/App.js'
|
|
14
15
|
|
|
@@ -188,14 +189,25 @@ describe('mint', () => {
|
|
|
188
189
|
).rejects.toThrowError(/invalid API key input/)
|
|
189
190
|
})
|
|
190
191
|
|
|
191
|
-
test('
|
|
192
|
+
test('refuses fresh per-zone write scopes while stored ones still resolve and rotate', async () => {
|
|
192
193
|
const state = Store.memory()
|
|
193
|
-
|
|
194
|
-
orgId: 'org_a',
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
await expect(
|
|
195
|
+
ApiKeys.mint(state, { orgId: 'org_a', scopes: ['zone:read', 'zone:421700001:write'] }),
|
|
196
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
197
|
+
`[ApiKeys.InvalidInputError: invalid API key input: per-Zone scopes are retired; grant zone:read or zone:write with zoneTags]`,
|
|
198
|
+
)
|
|
199
|
+
const token = 'secret_legacy_writer'
|
|
200
|
+
await state.put(
|
|
201
|
+
ApiKey.keyFor(token),
|
|
202
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_writer', orgId: 'org_a', scopes: ['zone:421700001:write'], tokenLast4: 'iter' }), // prettier-ignore
|
|
203
|
+
)
|
|
204
|
+
await state.put('apikey_id:key_writer', ApiKey.keyFor(token))
|
|
205
|
+
expect((await ApiKeys.resolve(state, token))?.scopes).toEqual(['zone:421700001:write'])
|
|
206
|
+
// A stored scope may be republished unchanged, never granted anew.
|
|
207
|
+
expect((await ApiKeys.update(state, 'key_writer', { scopes: ['zone:421700001:write'] }))?.scopes).toEqual(['zone:421700001:write']) // prettier-ignore
|
|
208
|
+
await expect(
|
|
209
|
+
ApiKeys.update(state, 'key_writer', { scopes: ['zone:421700001:write', 'zone:421700002:write'] }), // prettier-ignore
|
|
210
|
+
).rejects.toBeInstanceOf(ApiKeys.InvalidInputError)
|
|
199
211
|
})
|
|
200
212
|
|
|
201
213
|
test('rejects malformed zone scopes', async () => {
|
|
@@ -999,6 +1011,27 @@ describe('mintBounded', () => {
|
|
|
999
1011
|
})
|
|
1000
1012
|
|
|
1001
1013
|
describe('mint', () => {
|
|
1014
|
+
test('refuses retired per-Zone read scopes on fresh grants while stored ones republish', async () => {
|
|
1015
|
+
const state = Store.memory()
|
|
1016
|
+
await expect(
|
|
1017
|
+
ApiKeys.mint(state, { scopes: ['data:read', 'zone:421700001:read'] }),
|
|
1018
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
1019
|
+
`[ApiKeys.InvalidInputError: invalid API key input: per-Zone scopes are retired; grant zone:read or zone:write with zoneTags]`,
|
|
1020
|
+
)
|
|
1021
|
+
const token = 'secret_legacy_reader'
|
|
1022
|
+
await state.put(
|
|
1023
|
+
ApiKey.keyFor(token),
|
|
1024
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_legacy', orgId: 'org_legacy', scopes: ['zone:421700001:read', 'zone:read'], tokenLast4: 'ader', zoneTags: [421700001] }), // prettier-ignore
|
|
1025
|
+
)
|
|
1026
|
+
await ApiKeys.backfill(state)
|
|
1027
|
+
// Scopes the record already holds republish; a new retired scope is refused.
|
|
1028
|
+
expect((await ApiKeys.update(state, 'key_legacy', { name: 'Renamed', scopes: ['zone:421700001:read', 'zone:read'] }))?.scopes).toEqual(['zone:421700001:read', 'zone:read']) // prettier-ignore
|
|
1029
|
+
await expect(ApiKeys.update(state, 'key_legacy', { scopes: ['zone:421700001:read', 'zone:421700002:read', 'zone:read'] })).rejects.toThrow(ApiKeys.InvalidInputError) // prettier-ignore
|
|
1030
|
+
// The plain update republishes the record; the bounded reassignment drops the inert scope (admin api-keys test).
|
|
1031
|
+
expect((await ApiKeys.update(state, 'key_legacy', { orgId: 'org_next' }))?.scopes).toEqual(['zone:421700001:read', 'zone:read']) // prettier-ignore
|
|
1032
|
+
expect(await ApiKeys.resolve(state, token)).toMatchObject({ orgId: 'org_next', zoneTags: [421700001] }) // prettier-ignore
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1002
1035
|
test('stores deduplicated Zone tags', async () => {
|
|
1003
1036
|
const state = Store.memory()
|
|
1004
1037
|
const { record, token } = await ApiKeys.mint(state, {
|
|
@@ -1031,17 +1064,37 @@ describe('rotateBounded', () => {
|
|
|
1031
1064
|
expect(record).toMatchObject({ allowedIps: ['203.0.113.0/24'], zoneTags: [421700001] })
|
|
1032
1065
|
})
|
|
1033
1066
|
|
|
1034
|
-
test('
|
|
1067
|
+
test('narrows a broadcasting copy to the tags still delegated instead of refusing the rotation', async () => {
|
|
1068
|
+
const db = TestApp.database()
|
|
1069
|
+
const state = Store.memory()
|
|
1070
|
+
const org = await Organizations.create(db, { name: 'Zone revoke' })
|
|
1071
|
+
await TestApp.delegateZone(db, { chainIds: [421700001, 421700002], orgId: org.id })
|
|
1072
|
+
const { record: source } = await ApiKeys.mintBounded(db, state, {
|
|
1073
|
+
orgId: org.id,
|
|
1074
|
+
scopes: ['zone:write'],
|
|
1075
|
+
zoneTags: [421700001, 421700002],
|
|
1076
|
+
})
|
|
1077
|
+
const [revoked] = (await ZoneDelegations.listActive(db, { environment: 'production', orgId: org.id })).filter((row) => row.chainId === 421700002) // prettier-ignore
|
|
1078
|
+
await ZoneDelegations.revoke(db, revoked!.id)
|
|
1079
|
+
// One revoked Zone drops out of the copy; the other keeps broadcasting.
|
|
1080
|
+
const { record } = await ApiKeys.rotateBounded(db, state, { orgId: org.id, scopes: source.scopes }, { policySourceApiKeyId: source.id }) // prettier-ignore
|
|
1081
|
+
expect(record).toMatchObject({ scopes: ['zone:write'], zoneTags: [421700001] })
|
|
1082
|
+
// With every delegation gone the copy carries no tags, so it broadcasts nowhere until retagged.
|
|
1083
|
+
for (const row of await ZoneDelegations.listActive(db, { environment: 'production', orgId: org.id })) await ZoneDelegations.revoke(db, row.id) // prettier-ignore
|
|
1084
|
+
const { record: bare } = await ApiKeys.rotateBounded(db, state, { orgId: org.id, scopes: record.scopes }, { policySourceApiKeyId: record.id }) // prettier-ignore
|
|
1085
|
+
expect(bare.scopes).toEqual(['zone:write'])
|
|
1086
|
+
expect(bare).not.toHaveProperty('zoneTags')
|
|
1087
|
+
})
|
|
1088
|
+
|
|
1089
|
+
test('replaces a Zone read key with the same scopes', async () => {
|
|
1035
1090
|
const db = TestApp.database()
|
|
1036
1091
|
const state = Store.memory()
|
|
1037
1092
|
const org = await Organizations.create(db, { name: 'Zone rotation' })
|
|
1038
1093
|
const { record: source } = await ApiKeys.mint(state, {
|
|
1039
1094
|
orgId: org.id,
|
|
1040
|
-
scopes: ['zone:
|
|
1095
|
+
scopes: ['zone:read', 'data:read'],
|
|
1096
|
+
zoneTags: [421700001],
|
|
1041
1097
|
})
|
|
1042
|
-
await expect(
|
|
1043
|
-
ApiKeys.mintBounded(db, state, { orgId: org.id, scopes: source.scopes }),
|
|
1044
|
-
).rejects.toBeInstanceOf(ZoneKeyApproval.RequiredError)
|
|
1045
1098
|
|
|
1046
1099
|
const { record } = await ApiKeys.rotateBounded(
|
|
1047
1100
|
db,
|
|
@@ -1062,13 +1115,14 @@ describe('rotateBounded', () => {
|
|
|
1062
1115
|
const org = await Organizations.create(db, { name: 'Zone widening' })
|
|
1063
1116
|
const { record: source } = await ApiKeys.mint(state, {
|
|
1064
1117
|
orgId: org.id,
|
|
1065
|
-
scopes: ['zone:
|
|
1118
|
+
scopes: ['zone:read'],
|
|
1119
|
+
zoneTags: [421700001],
|
|
1066
1120
|
})
|
|
1067
1121
|
await expect(
|
|
1068
1122
|
ApiKeys.rotateBounded(
|
|
1069
1123
|
db,
|
|
1070
1124
|
state,
|
|
1071
|
-
{ orgId: org.id, scopes: ['zone:
|
|
1125
|
+
{ orgId: org.id, scopes: ['zone:read', 'data:read'] },
|
|
1072
1126
|
{ policySourceApiKeyId: source.id },
|
|
1073
1127
|
),
|
|
1074
1128
|
).rejects.toBeInstanceOf(RoutesPolicies.InvalidScopeError)
|
|
@@ -1145,62 +1199,41 @@ describe('updateBounded', () => {
|
|
|
1145
1199
|
expect(await ApiKeys.get(state, record.id)).not.toHaveProperty('expiresAt')
|
|
1146
1200
|
})
|
|
1147
1201
|
|
|
1148
|
-
test('lets
|
|
1202
|
+
test('lets owners retag and re-bound a Zone read key', async () => {
|
|
1149
1203
|
const db = TestApp.database()
|
|
1150
1204
|
const state = Store.memory()
|
|
1151
|
-
const org = await Organizations.create(db, { name: 'Zone
|
|
1205
|
+
const org = await Organizations.create(db, { name: 'Zone retag' })
|
|
1152
1206
|
const expiresAt = new Date(Date.now() + 86_400_000).toISOString()
|
|
1153
1207
|
const { record } = await ApiKeys.mint(state, {
|
|
1154
1208
|
expiresAt,
|
|
1155
1209
|
orgId: org.id,
|
|
1156
|
-
scopes: ['zone:
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
{ expiresAt: null },
|
|
1160
|
-
{ expiresAt: new Date(Date.now() + 2 * 86_400_000).toISOString() },
|
|
1161
|
-
{ zoneTags: [421700001] },
|
|
1162
|
-
{ zoneTags: null },
|
|
1163
|
-
{ allowedIps: [] },
|
|
1164
|
-
]
|
|
1165
|
-
for (const input of gated)
|
|
1166
|
-
await expect(ApiKeys.updateBounded(db, state, record.id, input)).rejects.toBeInstanceOf(
|
|
1167
|
-
ZoneKeyApproval.RequiredError,
|
|
1168
|
-
)
|
|
1210
|
+
scopes: ['zone:read'],
|
|
1211
|
+
zoneTags: [421700001],
|
|
1212
|
+
})
|
|
1169
1213
|
const sooner = new Date(Date.now() + 3_600_000).toISOString()
|
|
1170
1214
|
expect(
|
|
1171
|
-
|
|
1172
|
-
).
|
|
1215
|
+
await ApiKeys.updateBounded(db, state, record.id, { expiresAt: sooner, zoneTags: [421700002] }), // prettier-ignore
|
|
1216
|
+
).toMatchObject({ expiresAt: sooner, zoneTags: [421700002] })
|
|
1217
|
+
expect((await ApiKeys.updateBounded(db, state, record.id, { zoneTags: null }))?.zoneTags).toBeUndefined() // prettier-ignore
|
|
1173
1218
|
})
|
|
1174
1219
|
|
|
1175
|
-
test('gives a self-owned
|
|
1220
|
+
test('gives a self-owned key its organization, keeping its token and tags', async () => {
|
|
1176
1221
|
const db = TestApp.database()
|
|
1177
1222
|
const state = Store.memory()
|
|
1178
1223
|
const org = await Organizations.create(db, { name: 'Zone adopter' })
|
|
1179
|
-
const other = await Organizations.create(db, { name: 'Zone other' })
|
|
1180
1224
|
// Legacy keys minted before organizations existed own themselves.
|
|
1181
1225
|
const { record, token } = await ApiKeys.mint(state, {
|
|
1182
1226
|
name: 'legacy',
|
|
1183
|
-
scopes: ['zone:
|
|
1227
|
+
scopes: ['zone:read', 'data:read'],
|
|
1228
|
+
zoneTags: [421700001],
|
|
1184
1229
|
})
|
|
1185
1230
|
expect(record.orgId).toBe(record.id)
|
|
1186
|
-
for (const input of [
|
|
1187
|
-
{ orgId: org.id, zoneTags: [421700001] },
|
|
1188
|
-
{ orgId: org.id, name: 'x' },
|
|
1189
|
-
])
|
|
1190
|
-
await expect(ApiKeys.updateBounded(db, state, record.id, input)).rejects.toBeInstanceOf(
|
|
1191
|
-
ZoneKeyApproval.RequiredError,
|
|
1192
|
-
)
|
|
1193
1231
|
|
|
1194
1232
|
const adopted = await ApiKeys.updateBounded(db, state, record.id, { orgId: org.id })
|
|
1195
|
-
expect(adopted).toMatchObject({ id: record.id, orgId: org.id, scopes: record.scopes })
|
|
1233
|
+
expect(adopted).toMatchObject({ id: record.id, orgId: org.id, scopes: record.scopes, zoneTags: [421700001] }) // prettier-ignore
|
|
1196
1234
|
expect(await ApiKeys.resolve(state, token)).toMatchObject({ id: record.id, orgId: org.id })
|
|
1197
1235
|
expect((await ApiKeys.listByOrg(state, org.id)).map(({ id }) => id)).toEqual([record.id])
|
|
1198
1236
|
expect(await ApiKeyAdmissions.get(db, record.id)).toMatchObject({ orgId: org.id })
|
|
1199
|
-
|
|
1200
|
-
// Once owned, moving it again is a reviewed change like any other edit.
|
|
1201
|
-
await expect(
|
|
1202
|
-
ApiKeys.updateBounded(db, state, record.id, { orgId: other.id }),
|
|
1203
|
-
).rejects.toBeInstanceOf(ZoneKeyApproval.RequiredError)
|
|
1204
1237
|
})
|
|
1205
1238
|
|
|
1206
1239
|
test('rejects null for fields that cannot be cleared and sub-minute expiries', async () => {
|
|
@@ -2383,13 +2416,13 @@ describe('update', () => {
|
|
|
2383
2416
|
})
|
|
2384
2417
|
|
|
2385
2418
|
const updated = await ApiKeys.update(state, record.id, {
|
|
2386
|
-
scopes: ['management:read', '
|
|
2419
|
+
scopes: ['management:read', 'webhooks:write'],
|
|
2387
2420
|
})
|
|
2388
2421
|
|
|
2389
|
-
expect(updated?.scopes).toEqual(['management:read', '
|
|
2422
|
+
expect(updated?.scopes).toEqual(['management:read', 'webhooks:write'])
|
|
2390
2423
|
expect((await ApiKeys.resolve(state, token))?.scopes).toEqual([
|
|
2391
2424
|
'management:read',
|
|
2392
|
-
'
|
|
2425
|
+
'webhooks:write',
|
|
2393
2426
|
])
|
|
2394
2427
|
})
|
|
2395
2428
|
|
|
@@ -2633,3 +2666,203 @@ async function installDeferredAdmissionFailure(
|
|
|
2633
2666
|
`)
|
|
2634
2667
|
.execute(db.kysely)
|
|
2635
2668
|
}
|
|
2669
|
+
|
|
2670
|
+
describe('planZoneReadRewrite', () => {
|
|
2671
|
+
test('adds zone:read and merged, alias-resolved tags beside per-Zone read scopes; wildcard, mixed, and invalid keys are listed', async () => {
|
|
2672
|
+
const state = Store.memory()
|
|
2673
|
+
const stored = async (id: string, extra: Record<string, unknown>) => {
|
|
2674
|
+
const token = `secret_${id}`
|
|
2675
|
+
await state.put(
|
|
2676
|
+
ApiKey.keyFor(token),
|
|
2677
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id, orgId: 'org_rewrite', tokenLast4: token.slice(-4), ...extra }), // prettier-ignore
|
|
2678
|
+
)
|
|
2679
|
+
return token
|
|
2680
|
+
}
|
|
2681
|
+
const legacy = await stored('key_legacy', { scopes: ['data:read', 'zone:1424310001:read', 'zone:421700001:read'] }) // prettier-ignore
|
|
2682
|
+
// Writes to the same Zone as the reads share its tag.
|
|
2683
|
+
await stored('key_both', { scopes: ['zone:421700001:read', 'zone:421700001:write'] })
|
|
2684
|
+
// Tags already naming a scope's Zone merge without duplicates.
|
|
2685
|
+
await stored('key_tagged', { scopes: ['zone:421700002:read', 'zone:read'], zoneTags: [421700001] }) // prettier-ignore
|
|
2686
|
+
// Already in both formats: planned so its delegation is checked, never written.
|
|
2687
|
+
await stored('key_done', {
|
|
2688
|
+
scopes: ['zone:421700001:read', 'zone:read'],
|
|
2689
|
+
zoneTags: [421700001],
|
|
2690
|
+
})
|
|
2691
|
+
await stored('key_wild', { scopes: ['*', 'zone:421700001:read'] })
|
|
2692
|
+
await stored('key_plain', { scopes: ['data:read'] })
|
|
2693
|
+
// Writes to another Zone than the reads cannot share one tag list.
|
|
2694
|
+
await stored('key_mixed', { scopes: ['zone:421700001:read', 'zone:421700002:write'] })
|
|
2695
|
+
// Fifty tags plus one more Zone exceeds the tag limit, so the record is reported, not rewritten.
|
|
2696
|
+
await stored('key_full', { scopes: ['zone:read', 'zone:421700001:read'], zoneTags: Array.from({ length: 50 }, (_, index) => 421700100 + index) }) // prettier-ignore
|
|
2697
|
+
await stored('key_revoked', { scopes: ['zone:421700003:read'] })
|
|
2698
|
+
await state.put('apikey_revoked:key_revoked', '1')
|
|
2699
|
+
// KV refuses a TTL under a minute; the record lapses on its own.
|
|
2700
|
+
await stored('key_soon', { expiresAt: new Date(Date.now() + 30_000).toISOString(), scopes: ['zone:421700003:read'] }) // prettier-ignore
|
|
2701
|
+
await stored('key_expired', { expiresAt: '2000-01-01T00:00:00.000Z', scopes: ['zone:421700003:read'] }) // prettier-ignore
|
|
2702
|
+
|
|
2703
|
+
const plan = await ApiKeys.planZoneReadRewrite(state)
|
|
2704
|
+
expect({
|
|
2705
|
+
...plan,
|
|
2706
|
+
changes: plan.changes.map(({ chainIds, complete, record, rewritten }) => ({ chainIds, complete, id: record.id, scopes: rewritten.scopes, zoneTags: rewritten.zoneTags })), // prettier-ignore
|
|
2707
|
+
expiring: plan.expiring.map(({ id }) => id),
|
|
2708
|
+
invalid: plan.invalid.map(({ id }) => id),
|
|
2709
|
+
mixed: plan.mixed.map(({ id }) => id),
|
|
2710
|
+
wildcard: plan.wildcard.map(({ id }) => id),
|
|
2711
|
+
}).toMatchInlineSnapshot(`
|
|
2712
|
+
{
|
|
2713
|
+
"changes": [
|
|
2714
|
+
{
|
|
2715
|
+
"chainIds": [
|
|
2716
|
+
421700001,
|
|
2717
|
+
],
|
|
2718
|
+
"complete": false,
|
|
2719
|
+
"id": "key_both",
|
|
2720
|
+
"scopes": [
|
|
2721
|
+
"zone:421700001:read",
|
|
2722
|
+
"zone:421700001:write",
|
|
2723
|
+
"zone:read",
|
|
2724
|
+
"zone:write",
|
|
2725
|
+
],
|
|
2726
|
+
"zoneTags": [
|
|
2727
|
+
421700001,
|
|
2728
|
+
],
|
|
2729
|
+
},
|
|
2730
|
+
{
|
|
2731
|
+
"chainIds": [
|
|
2732
|
+
421700001,
|
|
2733
|
+
],
|
|
2734
|
+
"complete": true,
|
|
2735
|
+
"id": "key_done",
|
|
2736
|
+
"scopes": [
|
|
2737
|
+
"zone:421700001:read",
|
|
2738
|
+
"zone:read",
|
|
2739
|
+
],
|
|
2740
|
+
"zoneTags": [
|
|
2741
|
+
421700001,
|
|
2742
|
+
],
|
|
2743
|
+
},
|
|
2744
|
+
{
|
|
2745
|
+
"chainIds": [
|
|
2746
|
+
421700001,
|
|
2747
|
+
1424310003,
|
|
2748
|
+
],
|
|
2749
|
+
"complete": false,
|
|
2750
|
+
"id": "key_legacy",
|
|
2751
|
+
"scopes": [
|
|
2752
|
+
"data:read",
|
|
2753
|
+
"zone:1424310001:read",
|
|
2754
|
+
"zone:421700001:read",
|
|
2755
|
+
"zone:read",
|
|
2756
|
+
],
|
|
2757
|
+
"zoneTags": [
|
|
2758
|
+
421700001,
|
|
2759
|
+
1424310003,
|
|
2760
|
+
],
|
|
2761
|
+
},
|
|
2762
|
+
{
|
|
2763
|
+
"chainIds": [
|
|
2764
|
+
421700002,
|
|
2765
|
+
],
|
|
2766
|
+
"complete": false,
|
|
2767
|
+
"id": "key_tagged",
|
|
2768
|
+
"scopes": [
|
|
2769
|
+
"zone:421700002:read",
|
|
2770
|
+
"zone:read",
|
|
2771
|
+
],
|
|
2772
|
+
"zoneTags": [
|
|
2773
|
+
421700001,
|
|
2774
|
+
421700002,
|
|
2775
|
+
],
|
|
2776
|
+
},
|
|
2777
|
+
],
|
|
2778
|
+
"expiring": [
|
|
2779
|
+
"key_soon",
|
|
2780
|
+
],
|
|
2781
|
+
"invalid": [
|
|
2782
|
+
"key_full",
|
|
2783
|
+
],
|
|
2784
|
+
"keys": 9,
|
|
2785
|
+
"mixed": [
|
|
2786
|
+
"key_mixed",
|
|
2787
|
+
],
|
|
2788
|
+
"tagless": [],
|
|
2789
|
+
"unreadableRecords": 1,
|
|
2790
|
+
"wildcard": [
|
|
2791
|
+
"key_wild",
|
|
2792
|
+
],
|
|
2793
|
+
}
|
|
2794
|
+
`)
|
|
2795
|
+
|
|
2796
|
+
// key_tagged already holds zone:read; only its tag list grows.
|
|
2797
|
+
expect(await ApiKeys.applyZoneReadRewrite(state, plan.changes)).toBe(3)
|
|
2798
|
+
expect(await ApiKeys.resolve(state, legacy)).toMatchObject({
|
|
2799
|
+
scopes: ['data:read', 'zone:1424310001:read', 'zone:421700001:read', 'zone:read'],
|
|
2800
|
+
zoneTags: [421700001, 1424310003],
|
|
2801
|
+
})
|
|
2802
|
+
expect(await ApiKeys.resolve(state, 'secret_key_both')).toMatchObject({ scopes: ['zone:421700001:read', 'zone:421700001:write', 'zone:read', 'zone:write'], zoneTags: [421700001] }) // prettier-ignore
|
|
2803
|
+
expect(await ApiKeys.resolve(state, 'secret_key_tagged')).toMatchObject({ scopes: ['zone:421700002:read', 'zone:read'], zoneTags: [421700001, 421700002] }) // prettier-ignore
|
|
2804
|
+
// A rerun plans only complete records, for their delegations, and writes nothing.
|
|
2805
|
+
const again = await ApiKeys.planZoneReadRewrite(state)
|
|
2806
|
+
expect(again.changes.map(({ complete, record }) => [record.id, complete]).sort()).toEqual([['key_both', true], ['key_done', true], ['key_legacy', true], ['key_tagged', true]]) // prettier-ignore
|
|
2807
|
+
expect(await ApiKeys.applyZoneReadRewrite(state, again.changes)).toBe(0)
|
|
2808
|
+
})
|
|
2809
|
+
|
|
2810
|
+
test('keeps a key that reads nothing yet holds zone:read out of the write mapping', async () => {
|
|
2811
|
+
const state = Store.memory()
|
|
2812
|
+
// Tags would serve both verbs, so a reader with no Zones yet cannot silently gain reads from its write scope.
|
|
2813
|
+
await state.put(
|
|
2814
|
+
ApiKey.keyFor('secret_reader_writer'),
|
|
2815
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_reader_writer', orgId: 'org_rewrite', scopes: ['data:read', 'zone:read', 'zone:421700005:write'], tokenLast4: 'iter' }), // prettier-ignore
|
|
2816
|
+
)
|
|
2817
|
+
// A pure writer has no read scope to widen, so its Zone becomes a tag beside `zone:write`.
|
|
2818
|
+
await state.put(
|
|
2819
|
+
ApiKey.keyFor('secret_writer'),
|
|
2820
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_writer', orgId: 'org_rewrite', scopes: ['mpp:write', 'zone:421700005:write'], tokenLast4: 'iter' }), // prettier-ignore
|
|
2821
|
+
)
|
|
2822
|
+
// A writer with leftover tags for other Zones would broadcast to them once tagged for `zone:write`.
|
|
2823
|
+
await state.put(
|
|
2824
|
+
ApiKey.keyFor('secret_tagged_writer'),
|
|
2825
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_tagged_writer', orgId: 'org_rewrite', scopes: ['mpp:write', 'zone:421700005:write'], tokenLast4: 'iter', zoneTags: [421700007] }), // prettier-ignore
|
|
2826
|
+
)
|
|
2827
|
+
// A key already broadcasting through `zone:write` writes exactly its tags, so a retired read Zone must not join them.
|
|
2828
|
+
await state.put(
|
|
2829
|
+
ApiKey.keyFor('secret_generic_writer'),
|
|
2830
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_generic_writer', orgId: 'org_rewrite', scopes: ['zone:write', 'zone:421700005:read'], tokenLast4: 'iter', zoneTags: [421700007] }), // prettier-ignore
|
|
2831
|
+
)
|
|
2832
|
+
const plan = await ApiKeys.planZoneReadRewrite(state)
|
|
2833
|
+
expect(plan.mixed.map(({ id }) => id).sort()).toEqual([
|
|
2834
|
+
'key_generic_writer',
|
|
2835
|
+
'key_reader_writer',
|
|
2836
|
+
'key_tagged_writer',
|
|
2837
|
+
])
|
|
2838
|
+
expect(plan.changes.map(({ chainIds, record, writeChainIds }) => [record.id, chainIds, writeChainIds])).toEqual([['key_writer', [], [421700005]]]) // prettier-ignore
|
|
2839
|
+
expect(await ApiKeys.applyZoneReadRewrite(state, plan.changes)).toBe(1)
|
|
2840
|
+
expect(await ApiKeys.resolve(state, 'secret_writer')).toMatchObject({ scopes: ['mpp:write', 'zone:421700005:write', 'zone:write'], zoneTags: [421700005] }) // prettier-ignore
|
|
2841
|
+
})
|
|
2842
|
+
|
|
2843
|
+
test('earns no tag for Zones the deployment does not serve, and drops the tags it finds', async () => {
|
|
2844
|
+
const state = Store.memory()
|
|
2845
|
+
await state.put(
|
|
2846
|
+
ApiKey.keyFor('secret_stale'),
|
|
2847
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_stale', orgId: 'org_rewrite', scopes: ['zone:421700001:read', 'zone:421700009:read'], tokenLast4: 'tale', zoneTags: [421700009] }), // prettier-ignore
|
|
2848
|
+
)
|
|
2849
|
+
// A stale tag beside matching read and write scopes is dropped before the verbs are compared, so the key is not mixed.
|
|
2850
|
+
// Unserved Zones are dropped from tags and scopes alike before the verbs are compared, so neither key is mixed.
|
|
2851
|
+
await state.put(
|
|
2852
|
+
ApiKey.keyFor('secret_both_unserved'),
|
|
2853
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_both_unserved', orgId: 'org_rewrite', scopes: ['zone:421700001:read', 'zone:421700001:write', 'zone:421700009:write'], tokenLast4: 'tale' }), // prettier-ignore
|
|
2854
|
+
)
|
|
2855
|
+
await state.put(
|
|
2856
|
+
ApiKey.keyFor('secret_both_stale'),
|
|
2857
|
+
JSON.stringify({ createdAt: '2026-01-01T00:00:00.000Z', environment: 'production', id: 'key_both_stale', orgId: 'org_rewrite', scopes: ['zone:421700001:read', 'zone:421700001:write'], tokenLast4: 'tale', zoneTags: [421700009] }), // prettier-ignore
|
|
2858
|
+
)
|
|
2859
|
+
const zones = new Set([421700001])
|
|
2860
|
+
const plan = await ApiKeys.planZoneReadRewrite(state, { zones })
|
|
2861
|
+
expect(plan.mixed).toEqual([])
|
|
2862
|
+
expect(plan.changes.map(({ chainIds, record, unconfigured }) => [record.id, chainIds, unconfigured] as const).sort(([a], [b]) => a.localeCompare(b))).toEqual([['key_both_stale', [421700001], []], ['key_both_unserved', [421700001], [421700009]], ['key_stale', [421700001], [421700009]]]) // prettier-ignore
|
|
2863
|
+
expect(await ApiKeys.applyZoneReadRewrite(state, plan.changes, { zones })).toBe(3)
|
|
2864
|
+
expect(await ApiKeys.resolve(state, 'secret_both_unserved')).toMatchObject({ scopes: ['zone:421700001:read', 'zone:421700001:write', 'zone:421700009:write', 'zone:read', 'zone:write'], zoneTags: [421700001] }) // prettier-ignore
|
|
2865
|
+
expect(await ApiKeys.resolve(state, 'secret_stale')).toMatchObject({ scopes: ['zone:421700001:read', 'zone:421700009:read', 'zone:read'], zoneTags: [421700001] }) // prettier-ignore
|
|
2866
|
+
expect(await ApiKeys.resolve(state, 'secret_both_stale')).toMatchObject({ scopes: ['zone:421700001:read', 'zone:421700001:write', 'zone:read', 'zone:write'], zoneTags: [421700001] }) // prettier-ignore
|
|
2867
|
+
})
|
|
2868
|
+
})
|