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
|
@@ -6,7 +6,6 @@ const token = `0x${'cd'.repeat(20)}`
|
|
|
6
6
|
const delegation = {
|
|
7
7
|
accounts: 'all',
|
|
8
8
|
id: 'zd_read',
|
|
9
|
-
projects: 'all',
|
|
10
9
|
tokens: 'all',
|
|
11
10
|
} satisfies ZoneDelegation.Delegation
|
|
12
11
|
|
|
@@ -16,7 +15,6 @@ describe('decide', () => {
|
|
|
16
15
|
ZoneDelegation.decide({
|
|
17
16
|
accounts: [],
|
|
18
17
|
delegation: undefined,
|
|
19
|
-
grant: 'scope',
|
|
20
18
|
tokens: [],
|
|
21
19
|
}),
|
|
22
20
|
).toMatchInlineSnapshot(`
|
|
@@ -28,7 +26,6 @@ describe('decide', () => {
|
|
|
28
26
|
ZoneDelegation.decide({
|
|
29
27
|
accounts: [],
|
|
30
28
|
delegation: undefined,
|
|
31
|
-
grant: 'scope',
|
|
32
29
|
tokens: [],
|
|
33
30
|
}),
|
|
34
31
|
).toMatchInlineSnapshot(`
|
|
@@ -43,7 +40,6 @@ describe('decide', () => {
|
|
|
43
40
|
ZoneDelegation.decide({
|
|
44
41
|
accounts: [],
|
|
45
42
|
delegation,
|
|
46
|
-
grant: 'scope',
|
|
47
43
|
tokens: [],
|
|
48
44
|
}),
|
|
49
45
|
).toMatchInlineSnapshot(`
|
|
@@ -56,33 +52,17 @@ describe('decide', () => {
|
|
|
56
52
|
ZoneDelegation.decide({
|
|
57
53
|
accounts: [account],
|
|
58
54
|
delegation,
|
|
59
|
-
grant: 'wildcard',
|
|
60
55
|
tokens: [token],
|
|
61
56
|
}).decision,
|
|
62
57
|
).toBe('allow')
|
|
63
58
|
})
|
|
64
59
|
|
|
65
|
-
test('narrows by project, with organization-wide keys needing all projects', () => {
|
|
66
|
-
const narrowed = { ...delegation, projects: ['prj_a'] }
|
|
67
|
-
const decide = (projectId: string | undefined) =>
|
|
68
|
-
ZoneDelegation.decide({ accounts: [], delegation: narrowed, grant: 'scope', projectId, tokens: [] }) // prettier-ignore
|
|
69
|
-
.decision
|
|
70
|
-
expect([decide('prj_a'), decide('prj_b'), decide(undefined)]).toMatchInlineSnapshot(`
|
|
71
|
-
[
|
|
72
|
-
"allow",
|
|
73
|
-
"deny",
|
|
74
|
-
"deny",
|
|
75
|
-
]
|
|
76
|
-
`)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
60
|
test('narrows by account, with zone-wide requests needing all accounts', () => {
|
|
80
61
|
const narrowed = { ...delegation, accounts: [account] }
|
|
81
62
|
const decide = (accounts: readonly string[]) =>
|
|
82
63
|
ZoneDelegation.decide({
|
|
83
64
|
accounts,
|
|
84
65
|
delegation: narrowed,
|
|
85
|
-
grant: 'scope',
|
|
86
66
|
tokens: [],
|
|
87
67
|
}).decision
|
|
88
68
|
expect([decide([account]), decide([account, `0x${'ef'.repeat(20)}`]), decide([])])
|
|
@@ -101,7 +81,6 @@ describe('decide', () => {
|
|
|
101
81
|
ZoneDelegation.decide({
|
|
102
82
|
accounts: [],
|
|
103
83
|
delegation: narrowed,
|
|
104
|
-
grant: 'scope',
|
|
105
84
|
tokens,
|
|
106
85
|
}).decision
|
|
107
86
|
expect([decide([token]), decide([`0x${'ef'.repeat(20)}`]), decide([])]).toMatchInlineSnapshot(`
|
|
@@ -113,21 +92,11 @@ describe('decide', () => {
|
|
|
113
92
|
`)
|
|
114
93
|
})
|
|
115
94
|
|
|
116
|
-
test('denies a key whose own scopes refuse, naming the delegation it would have used', () => {
|
|
117
|
-
expect(ZoneDelegation.decide({ accounts: [], delegation, tokens: [] })).toMatchInlineSnapshot(`
|
|
118
|
-
{
|
|
119
|
-
"decision": "deny",
|
|
120
|
-
"id": "zd_read",
|
|
121
|
-
}
|
|
122
|
-
`)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
95
|
test('reports the delegation id even when its narrowing denies', () => {
|
|
126
96
|
expect(
|
|
127
97
|
ZoneDelegation.decide({
|
|
128
98
|
accounts: [],
|
|
129
99
|
delegation: { ...delegation, accounts: [account] },
|
|
130
|
-
grant: 'scope',
|
|
131
100
|
tokens: [],
|
|
132
101
|
}),
|
|
133
102
|
).toMatchInlineSnapshot(`
|
|
@@ -144,8 +113,6 @@ describe('schema', () => {
|
|
|
144
113
|
expect(ZoneDelegation.schema.AddressList.parse([`0x${'AB'.repeat(20)}`])).toEqual([account])
|
|
145
114
|
expect(ZoneDelegation.schema.AddressList.safeParse([]).success).toBe(false)
|
|
146
115
|
expect(ZoneDelegation.schema.AddressList.safeParse(['0xnope']).success).toBe(false)
|
|
147
|
-
expect(ZoneDelegation.schema.Projects.parse('all')).toBe('all')
|
|
148
|
-
expect(ZoneDelegation.schema.Projects.safeParse(['key_1']).success).toBe(false)
|
|
149
116
|
})
|
|
150
117
|
})
|
|
151
118
|
|
|
@@ -159,8 +126,7 @@ describe('fromKeys', () => {
|
|
|
159
126
|
{ ...base, environment: 'sandbox', id: 'key_3', scopes: ['zone:421700002:read'] },
|
|
160
127
|
{ ...base, id: 'key_4', name: 'Integration', orgId: 'org_b', scopes: ['*', 'zone:421700003:read'] }, // prettier-ignore
|
|
161
128
|
{ ...base, id: 'key_5', scopes: ['data:read'] },
|
|
162
|
-
{ ...base, id: 'key_6', orgId: 'org_c',
|
|
163
|
-
{ ...base, id: 'key_7', orgId: 'org_c', projectId: 'prj_b', scopes: ['zone:421700002:read'] }, // prettier-ignore
|
|
129
|
+
{ ...base, id: 'key_6', orgId: 'org_c', scopes: ['zone:421700002:read'] },
|
|
164
130
|
]),
|
|
165
131
|
).toMatchInlineSnapshot(`
|
|
166
132
|
{
|
|
@@ -170,7 +136,6 @@ describe('fromKeys', () => {
|
|
|
170
136
|
"chainId": 421700002,
|
|
171
137
|
"environment": "production",
|
|
172
138
|
"orgId": "org_a",
|
|
173
|
-
"projects": "all",
|
|
174
139
|
"tokensAll": true,
|
|
175
140
|
},
|
|
176
141
|
{
|
|
@@ -178,7 +143,6 @@ describe('fromKeys', () => {
|
|
|
178
143
|
"chainId": 421700002,
|
|
179
144
|
"environment": "sandbox",
|
|
180
145
|
"orgId": "org_a",
|
|
181
|
-
"projects": "all",
|
|
182
146
|
"tokensAll": true,
|
|
183
147
|
},
|
|
184
148
|
{
|
|
@@ -186,10 +150,6 @@ describe('fromKeys', () => {
|
|
|
186
150
|
"chainId": 421700002,
|
|
187
151
|
"environment": "production",
|
|
188
152
|
"orgId": "org_c",
|
|
189
|
-
"projects": [
|
|
190
|
-
"prj_a",
|
|
191
|
-
"prj_b",
|
|
192
|
-
],
|
|
193
153
|
"tokensAll": true,
|
|
194
154
|
},
|
|
195
155
|
],
|
|
@@ -3,7 +3,6 @@ import * as z from 'zod/mini'
|
|
|
3
3
|
import type * as ApiKey from '../ApiKey.js'
|
|
4
4
|
import * as Scope from '../Scope.js'
|
|
5
5
|
import * as Schema from './Schema.js'
|
|
6
|
-
import type * as ZoneAccess from './ZoneAccess.js'
|
|
7
6
|
|
|
8
7
|
/** Resources a delegation covers: every resource, or an explicit lowercase list. */
|
|
9
8
|
export type Selection = 'all' | readonly string[]
|
|
@@ -14,8 +13,6 @@ export type Delegation = {
|
|
|
14
13
|
accounts: Selection
|
|
15
14
|
/** Delegation id (`zd_…`). */
|
|
16
15
|
id: string
|
|
17
|
-
/** Project ids the delegation covers, or `all`. */
|
|
18
|
-
projects: Selection
|
|
19
16
|
/** Requested tokens the delegation lists, or `all`. */
|
|
20
17
|
tokens: Selection
|
|
21
18
|
}
|
|
@@ -25,7 +22,7 @@ export type Decision = 'allow' | 'deny'
|
|
|
25
22
|
|
|
26
23
|
/** Delegation decision for one request. */
|
|
27
24
|
export type Result = {
|
|
28
|
-
/** Whether
|
|
25
|
+
/** Whether the organization's delegation covers the request. */
|
|
29
26
|
decision: Decision
|
|
30
27
|
/** Active delegation for the Zone, when one exists; absent when the organization holds none. */
|
|
31
28
|
id?: string | undefined
|
|
@@ -39,18 +36,6 @@ export namespace schema {
|
|
|
39
36
|
z.describe('API-key environment the delegation applies to.'),
|
|
40
37
|
z.meta({ examples: ['production'] }),
|
|
41
38
|
)
|
|
42
|
-
export const Projects = z
|
|
43
|
-
.union([
|
|
44
|
-
z.literal('all'),
|
|
45
|
-
z.pipe(
|
|
46
|
-
z.array(z.string().check(z.regex(/^prj_[A-Za-z0-9_-]+$/))).check(z.maxLength(1_000)),
|
|
47
|
-
z.transform((ids) => [...new Set(ids)]),
|
|
48
|
-
),
|
|
49
|
-
])
|
|
50
|
-
.check(
|
|
51
|
-
z.describe('Project ids the delegation covers, or `all`.'),
|
|
52
|
-
z.meta({ examples: ['all'] }),
|
|
53
|
-
)
|
|
54
39
|
export const AddressList = z
|
|
55
40
|
.pipe(
|
|
56
41
|
z.array(Schema.Address).check(z.minLength(1), z.maxLength(1_000)),
|
|
@@ -63,16 +48,13 @@ export namespace schema {
|
|
|
63
48
|
}
|
|
64
49
|
|
|
65
50
|
/**
|
|
66
|
-
* Decides whether an organization's delegation
|
|
67
|
-
* whose own scopes allow it. The key's project must be covered, and every
|
|
51
|
+
* Decides whether an organization's delegation covers one Zone read: every
|
|
68
52
|
* requested account and token must be covered (a request naming none needs
|
|
69
|
-
* `all`).
|
|
53
|
+
* `all`). The key's own scope and tags are checked by the gate before this runs.
|
|
70
54
|
*/
|
|
71
55
|
export function decide(options: decide.Options): Result {
|
|
72
|
-
const { accounts, delegation,
|
|
56
|
+
const { accounts, delegation, tokens } = options
|
|
73
57
|
if (!delegation) return { decision: 'deny' }
|
|
74
|
-
// The key's own Zone scope stays its allowlist: a delegation grants nothing to a key without one.
|
|
75
|
-
if (grant === undefined) return { decision: 'deny', id: delegation.id }
|
|
76
58
|
// A request naming nothing from a list sees everything (raw RPC, unfiltered lists,
|
|
77
59
|
// balances across every token), so only an `all` selection covers it.
|
|
78
60
|
const covers = (selection: Selection, values: readonly string[]) => {
|
|
@@ -80,12 +62,7 @@ export function decide(options: decide.Options): Result {
|
|
|
80
62
|
const members = new Set(selection)
|
|
81
63
|
return values.length > 0 && values.every((value) => members.has(value))
|
|
82
64
|
}
|
|
83
|
-
|
|
84
|
-
const projectCovered =
|
|
85
|
-
delegation.projects === 'all' ||
|
|
86
|
-
(projectId !== undefined && delegation.projects.includes(projectId))
|
|
87
|
-
const allowed =
|
|
88
|
-
projectCovered && covers(delegation.accounts, accounts) && covers(delegation.tokens, tokens)
|
|
65
|
+
const allowed = covers(delegation.accounts, accounts) && covers(delegation.tokens, tokens)
|
|
89
66
|
return { decision: allowed ? 'allow' : 'deny', id: delegation.id }
|
|
90
67
|
}
|
|
91
68
|
|
|
@@ -96,10 +73,6 @@ export declare namespace decide {
|
|
|
96
73
|
accounts: readonly string[]
|
|
97
74
|
/** The organization's active delegation for the Zone, when one exists. */
|
|
98
75
|
delegation?: Delegation | undefined
|
|
99
|
-
/** Grant the key's own scopes produced for this request; absent when they refuse it. */
|
|
100
|
-
grant?: ZoneAccess.Grant | undefined
|
|
101
|
-
/** Project attributed to the API key, when any. */
|
|
102
|
-
projectId?: string | undefined
|
|
103
76
|
/** Lowercase token contracts the request is about; empty when not token-scoped. */
|
|
104
77
|
tokens: readonly string[]
|
|
105
78
|
}
|
|
@@ -107,10 +80,9 @@ export declare namespace decide {
|
|
|
107
80
|
|
|
108
81
|
/**
|
|
109
82
|
* Derives the whole-zone delegations that preserve each key's current Zone
|
|
110
|
-
* read scopes, one per organization, environment, and Zone
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* decision, not a backfill.
|
|
83
|
+
* read scopes, one per organization, environment, and Zone. Write scopes need
|
|
84
|
+
* no delegation. Wildcard keys are returned separately and derive nothing: a
|
|
85
|
+
* delegation for them is a decision, not a backfill.
|
|
114
86
|
*/
|
|
115
87
|
export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
|
|
116
88
|
const delegations = new Map<string, fromKeys.Input>()
|
|
@@ -124,19 +96,11 @@ export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
|
|
|
124
96
|
for (const scope of key.scopes) {
|
|
125
97
|
const chainId = Scope.zoneReadChainId(scope)
|
|
126
98
|
if (chainId === undefined) continue
|
|
127
|
-
|
|
128
|
-
const existing = delegations.get(id)
|
|
129
|
-
// Projects widen to the union of the source keys; an organization-wide key means every project.
|
|
130
|
-
const projects: Selection =
|
|
131
|
-
existing?.projects === 'all' || key.projectId === undefined
|
|
132
|
-
? 'all'
|
|
133
|
-
: [...new Set([...(existing?.projects ?? []), key.projectId])]
|
|
134
|
-
delegations.set(id, {
|
|
99
|
+
delegations.set(`${key.orgId}:${key.environment}:${chainId}`, {
|
|
135
100
|
accountsAll: true,
|
|
136
101
|
chainId,
|
|
137
102
|
environment: key.environment,
|
|
138
103
|
orgId: key.orgId,
|
|
139
|
-
projects,
|
|
140
104
|
tokensAll: true,
|
|
141
105
|
})
|
|
142
106
|
}
|
|
@@ -146,7 +110,7 @@ export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
|
|
|
146
110
|
|
|
147
111
|
export declare namespace fromKeys {
|
|
148
112
|
/** Key fields the derivation reads. */
|
|
149
|
-
type Key = Pick<ApiKey.ApiKey, 'environment' | 'id' | 'orgId' | '
|
|
113
|
+
type Key = Pick<ApiKey.ApiKey, 'environment' | 'id' | 'orgId' | 'scopes'> & {
|
|
150
114
|
/** Human-readable key name, when set. */
|
|
151
115
|
name?: string | undefined
|
|
152
116
|
}
|
|
@@ -161,8 +125,6 @@ export declare namespace fromKeys {
|
|
|
161
125
|
environment: ApiKey.ApiKey['environment']
|
|
162
126
|
/** Receiving organization id. */
|
|
163
127
|
orgId: string
|
|
164
|
-
/** Projects of the source keys, or `all` when any key is organization-wide. */
|
|
165
|
-
projects: Selection
|
|
166
128
|
/** Every token is covered. */
|
|
167
129
|
tokensAll: true
|
|
168
130
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as ZoneDelegationApproval from './ZoneDelegationApproval.js'
|
|
2
|
+
|
|
3
|
+
describe('active', () => {
|
|
4
|
+
test('rejects absent, expired, malformed, or incomplete session identities', () => {
|
|
5
|
+
const member = {
|
|
6
|
+
email: 'staff@tempo.xyz',
|
|
7
|
+
eligible: false,
|
|
8
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
9
|
+
id: 'employee_staff',
|
|
10
|
+
}
|
|
11
|
+
expect(ZoneDelegationApproval.active(member)).toBe(true)
|
|
12
|
+
for (const value of [
|
|
13
|
+
null,
|
|
14
|
+
undefined,
|
|
15
|
+
{ ...member, expiresAt: new Date().toISOString() },
|
|
16
|
+
{ ...member, expiresAt: 'invalid' },
|
|
17
|
+
{ ...member, id: '' },
|
|
18
|
+
{ ...member, email: '' },
|
|
19
|
+
])
|
|
20
|
+
expect(ZoneDelegationApproval.active(value)).toBe(false)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** Number of independent approvals required for Zone read credentials. */
|
|
1
|
+
/** Number of independent approvals required to create a Zone delegation. */
|
|
4
2
|
export const quorum = 2
|
|
5
3
|
|
|
6
4
|
/** Maximum lifetime of an approval, matching the request lifetime and bounded by its authenticated session. */
|
|
7
5
|
export const approvalLifetime = 24 * 60 * 60 * 1_000
|
|
8
6
|
|
|
9
|
-
/** Returns whether scopes grant access subject to Zone read approval. */
|
|
10
|
-
export function required(scopes: readonly string[]): boolean {
|
|
11
|
-
return scopes.some((scope) => scope === '*' || Scope.parseZone(scope)?.verb === 'read')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
7
|
/** An authenticated identity supplied by the host's verified identity integration. */
|
|
15
8
|
export type Member = {
|
|
16
9
|
/** Verified employee email, used for attribution only. */
|
|
@@ -41,11 +34,11 @@ export type Status = {
|
|
|
41
34
|
/** Looks up current account and group status, throwing when fresh results are unavailable. */
|
|
42
35
|
export type Lookup = (ids: readonly string[]) => Promise<readonly Status[]>
|
|
43
36
|
|
|
44
|
-
/** Expected rejection of a
|
|
37
|
+
/** Expected rejection of a delegation request, or of a direct write that widens Zone access. */
|
|
45
38
|
export class RequiredError extends Error {
|
|
46
|
-
override name = '
|
|
39
|
+
override name = 'ZoneDelegationApproval.RequiredError'
|
|
47
40
|
constructor(
|
|
48
|
-
message = 'Zone
|
|
41
|
+
message = 'Zone delegations require two independent group approvals through the admin delegation-request workflow.',
|
|
49
42
|
) {
|
|
50
43
|
super(message)
|
|
51
44
|
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type * as ApiKey from '../ApiKey.js'
|
|
2
|
+
import * as ApiKeys from '../ApiKeys.js'
|
|
3
|
+
import type * as Db from '../db/Db.js'
|
|
4
|
+
import * as ApiKeyAdmissions from '../db/tables/apiKeyAdmissions.js'
|
|
5
|
+
import * as Organizations from '../db/tables/organizations.js'
|
|
6
|
+
import * as ZoneDelegations from '../db/tables/zoneDelegations.js'
|
|
7
|
+
import type * as Store from './Store.js'
|
|
8
|
+
|
|
9
|
+
/** The additive rewrite adding `zone:read` plus tags beside stored per-Zone read scopes, and what it leaves out. */
|
|
10
|
+
export type Plan = {
|
|
11
|
+
/** Keys holding per-Zone read scopes, with the scopes and tags they end up holding; `complete` ones are only checked. */
|
|
12
|
+
changes: readonly Change[]
|
|
13
|
+
/** Keys expiring within a minute; KV refuses their TTL and they lapse on their own, so they are left unchanged. */
|
|
14
|
+
expiring: readonly Key[]
|
|
15
|
+
/** Keys whose rewritten record the schema refuses (say, past the tag limit); left unchanged for a manual fix. */
|
|
16
|
+
invalid: readonly Key[]
|
|
17
|
+
/** Live, unfenced key records read from the store. */
|
|
18
|
+
keys: number
|
|
19
|
+
/** Keys whose per-Zone write Zones differ from their read Zones; one tag list cannot express both, so they are re-minted by hand. */
|
|
20
|
+
mixed: readonly Key[]
|
|
21
|
+
/** Active delegations listing members for a planned Zone; apply refuses until they are whole-Zone. */
|
|
22
|
+
narrow: readonly ZoneDelegations.Record[]
|
|
23
|
+
/** Zone slots an admin revoked that a planned key still reads through its scope; the key stays unwritten until an admin delegates it again. */
|
|
24
|
+
revoked: readonly ZoneDelegations.Record[]
|
|
25
|
+
/** Keys owned by themselves (no organization row); left unchanged until `PUT /api-keys/{id}/organization` assigns one. */
|
|
26
|
+
orgless: readonly Key[]
|
|
27
|
+
/** Keys holding `zone:read` without tags or per-Zone scopes; they read no Zone and are listed, not changed. */
|
|
28
|
+
tagless: readonly Key[]
|
|
29
|
+
/** Zone chain ids named by per-Zone scopes that this deployment does not serve; no tag, delegations revoked. */
|
|
30
|
+
unconfigured: readonly number[]
|
|
31
|
+
/** Records the store could not read (expired, or scopes outside the catalog); left unchanged. */
|
|
32
|
+
unreadableRecords: number
|
|
33
|
+
/** Wildcard keys, listed for an explicit decision and left unchanged. */
|
|
34
|
+
wildcard: readonly Key[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A key named in a plan. */
|
|
38
|
+
export type Key = {
|
|
39
|
+
/** Key environment. */
|
|
40
|
+
environment: ApiKey.ApiKey['environment']
|
|
41
|
+
/** Key id. */
|
|
42
|
+
id: string
|
|
43
|
+
/** Human-readable key name, when set. */
|
|
44
|
+
name?: string | undefined
|
|
45
|
+
/** Owning organization id, or the key id for legacy keys minted without one. */
|
|
46
|
+
orgId: string
|
|
47
|
+
/** Attributed project id, when any. */
|
|
48
|
+
projectId?: string | undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** One key the rewrite changes or checks. */
|
|
52
|
+
export type Change = Key & {
|
|
53
|
+
/** Whether the record already holds `zone:read` and every tag; only its delegations are ensured, nothing is written. */
|
|
54
|
+
complete: boolean
|
|
55
|
+
/** Zones the per-Zone scopes grant whose delegation an admin revoked; the key is left unwritten while any remain. */
|
|
56
|
+
revoked: readonly number[]
|
|
57
|
+
/** Scopes the key holds after the rewrite. */
|
|
58
|
+
scopes: readonly string[]
|
|
59
|
+
/** Zones the per-Zone scopes grant that lack any delegation for the organization; applying ensures one for each. */
|
|
60
|
+
undelegated: readonly number[]
|
|
61
|
+
/** Zone chain ids the key reads after the rewrite. */
|
|
62
|
+
zoneTags: readonly number[]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** A plan after its changes were written. */
|
|
66
|
+
export type Applied = Plan & {
|
|
67
|
+
/** Whole-Zone delegations this run created so rewritten keys keep their reads. */
|
|
68
|
+
createdDelegations: number
|
|
69
|
+
/** Active delegations for unconfigured Zones this run revoked. */
|
|
70
|
+
revokedDelegations: number
|
|
71
|
+
/** Records this run rewrote. */
|
|
72
|
+
rewritten: number
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Derives the rewrite from the live key store without writing: every key
|
|
77
|
+
* holding a per-Zone read scope, the tags it would carry, and which of those
|
|
78
|
+
* Zones its organization is not yet delegated.
|
|
79
|
+
*/
|
|
80
|
+
export async function plan(options: Options): Promise<Plan> {
|
|
81
|
+
const { db, store, zones } = options
|
|
82
|
+
return summarize(db, await ApiKeys.planZoneReadRewrite(store, { zones }))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Rewrites every planned key so it keeps the reads it has today: ensures a
|
|
87
|
+
* whole-Zone delegation for each tagged Zone without one, then writes each
|
|
88
|
+
* record under its admission lock. Self-owned keys, and keys reading a Zone
|
|
89
|
+
* whose delegation an admin revoked, are skipped and reported. Throws
|
|
90
|
+
* {@link NarrowDelegationsError} before writing anything when an active
|
|
91
|
+
* delegation for a planned Zone lists members.
|
|
92
|
+
*/
|
|
93
|
+
export async function apply(options: Options): Promise<Applied> {
|
|
94
|
+
const { db, store, zones } = options
|
|
95
|
+
const planned = await ApiKeys.planZoneReadRewrite(store, { zones })
|
|
96
|
+
const summary = await summarize(db, planned)
|
|
97
|
+
if (summary.narrow.length) throw new NarrowDelegationsError(summary.narrow)
|
|
98
|
+
// A key reading a Zone an admin revoked keeps its scope untouched, so the gap stays in the plan.
|
|
99
|
+
const rewritable = summary.changes.filter(({ revoked }) => revoked.length === 0)
|
|
100
|
+
// Keys of one organization, environment, and Zone share a slot; one whole-Zone row covers them all.
|
|
101
|
+
const slots = new Map<string, ZoneDelegations.Scope>()
|
|
102
|
+
for (const change of rewritable)
|
|
103
|
+
for (const chainId of change.undelegated)
|
|
104
|
+
slots.set(`${change.orgId}:${change.environment}:${chainId}`, { chainId, environment: change.environment, orgId: change.orgId }) // prettier-ignore
|
|
105
|
+
let createdDelegations = 0
|
|
106
|
+
for (const slot of slots.values()) {
|
|
107
|
+
// Delegations grant reads only, so a whole-Zone row restores exactly what the scopes granted.
|
|
108
|
+
const result = await ZoneDelegations.ensure(db, { ...slot, accountsAll: true, tokensAll: true })
|
|
109
|
+
if (result.created) createdDelegations += 1
|
|
110
|
+
}
|
|
111
|
+
// Delegations for the unconfigured Zones an owner's own keys name grant nothing; they go with the tags.
|
|
112
|
+
let revokedDelegations = 0
|
|
113
|
+
const unconfiguredBy = new Map<string, Set<number>>()
|
|
114
|
+
for (const { record, unconfigured } of planned.changes) {
|
|
115
|
+
const owner = `${record.orgId}:${record.environment}`
|
|
116
|
+
unconfiguredBy.set(owner, new Set([...(unconfiguredBy.get(owner) ?? []), ...unconfigured]))
|
|
117
|
+
}
|
|
118
|
+
for (const [owner, chainIds] of unconfiguredBy) {
|
|
119
|
+
if (chainIds.size === 0) continue
|
|
120
|
+
const [orgId, environment] = owner.split(':') as [string, ZoneDelegations.Record['environment']]
|
|
121
|
+
for (const row of await ZoneDelegations.listActive(db, { environment, orgId }))
|
|
122
|
+
if (chainIds.has(row.chainId) && (await ZoneDelegations.revoke(db, row.id))) revokedDelegations += 1 // prettier-ignore
|
|
123
|
+
}
|
|
124
|
+
// Each record is written under the key's admission lock, re-read and re-planned there, so an owner edit committed meanwhile is never overwritten.
|
|
125
|
+
let rewritten = 0
|
|
126
|
+
const ids = new Set(rewritable.map(({ id }) => id))
|
|
127
|
+
for (const change of planned.changes.filter(({ record }) => ids.has(record.id)))
|
|
128
|
+
rewritten += await db.transaction(async (tx) => {
|
|
129
|
+
await ApiKeyAdmissions.lock(tx, change.record.id)
|
|
130
|
+
return ApiKeys.applyZoneReadRewrite(store, [change], { zones })
|
|
131
|
+
})
|
|
132
|
+
// The response describes the store as the run left it, not the snapshot it started from.
|
|
133
|
+
const final = await ApiKeys.planZoneReadRewrite(store, { zones })
|
|
134
|
+
return { ...(await summarize(db, final)), createdDelegations, revokedDelegations, rewritten }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Classifies planned changes by organization row and delegation coverage. */
|
|
138
|
+
async function summarize(db: Db.Db, planned: ApiKeys.planZoneReadRewrite.Result): Promise<Plan> {
|
|
139
|
+
const organizations = new Set(
|
|
140
|
+
(
|
|
141
|
+
await Organizations.listByIds(db, [
|
|
142
|
+
...new Set(planned.changes.map(({ record }) => record.orgId)),
|
|
143
|
+
])
|
|
144
|
+
).map(({ id }) => id),
|
|
145
|
+
)
|
|
146
|
+
// Self-owned keys cannot hold a delegation, so they are reported rather than rewritten.
|
|
147
|
+
const owned = planned.changes.filter(({ record }) => organizations.has(record.orgId))
|
|
148
|
+
// One listing per organization and environment, revoked rows included, shared by every key it owns.
|
|
149
|
+
const rows = new Map<string, readonly ZoneDelegations.Record[]>()
|
|
150
|
+
for (const { record } of owned) {
|
|
151
|
+
const owner = `${record.orgId}:${record.environment}`
|
|
152
|
+
if (!rows.has(owner)) rows.set(owner, await ZoneDelegations.list(db, { environment: record.environment, orgId: record.orgId })) // prettier-ignore
|
|
153
|
+
}
|
|
154
|
+
const narrow = new Map<string, ZoneDelegations.Record>()
|
|
155
|
+
const revokedSlots = new Map<string, ZoneDelegations.Record>()
|
|
156
|
+
const changes = owned.map(({ chainIds, complete, record, rewritten, writeChainIds }) => {
|
|
157
|
+
const listed = rows.get(`${record.orgId}:${record.environment}`) ?? []
|
|
158
|
+
const active = listed.filter((row) => row.revokedAt === undefined)
|
|
159
|
+
// Only Zones the per-Zone scopes grant are repaired; tags added by hand never earn a delegation.
|
|
160
|
+
// Any active row covers (projects are not part of the model); one listing members would narrow a
|
|
161
|
+
// whole-Zone reader, so it blocks the apply instead. Broadcasts never check members, so write
|
|
162
|
+
// Zones only need a row to exist.
|
|
163
|
+
for (const row of active)
|
|
164
|
+
if (chainIds.includes(row.chainId) && !(row.accountsAll && row.tokensAll)) narrow.set(row.id, row) // prettier-ignore
|
|
165
|
+
const undelegated = [...new Set([...chainIds, ...writeChainIds])]
|
|
166
|
+
.sort((a, b) => a - b)
|
|
167
|
+
.filter((chainId) => !active.some((row) => row.chainId === chainId))
|
|
168
|
+
// A slot an admin revoked is a decision the rewrite must not undo; the key is reported instead.
|
|
169
|
+
const revoked = undelegated.filter((chainId) => {
|
|
170
|
+
const row = listed.find((candidate) => candidate.chainId === chainId)
|
|
171
|
+
if (row) revokedSlots.set(row.id, row)
|
|
172
|
+
return row !== undefined
|
|
173
|
+
})
|
|
174
|
+
return {
|
|
175
|
+
...key(rewritten),
|
|
176
|
+
complete,
|
|
177
|
+
revoked,
|
|
178
|
+
scopes: rewritten.scopes,
|
|
179
|
+
undelegated,
|
|
180
|
+
zoneTags: rewritten.zoneTags ?? [],
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
return {
|
|
184
|
+
changes,
|
|
185
|
+
expiring: planned.expiring.map(key),
|
|
186
|
+
invalid: planned.invalid.map(key),
|
|
187
|
+
keys: planned.keys,
|
|
188
|
+
mixed: planned.mixed.map(key),
|
|
189
|
+
narrow: [...narrow.values()],
|
|
190
|
+
revoked: [...revokedSlots.values()],
|
|
191
|
+
orgless: planned.changes
|
|
192
|
+
.map(({ record }) => record)
|
|
193
|
+
.filter((record) => !organizations.has(record.orgId))
|
|
194
|
+
.map(key),
|
|
195
|
+
tagless: planned.tagless.map(key),
|
|
196
|
+
unconfigured: [...new Set(planned.changes.flatMap(({ unconfigured }) => unconfigured))].sort((a, b) => a - b), // prettier-ignore
|
|
197
|
+
unreadableRecords: planned.unreadableRecords,
|
|
198
|
+
wildcard: planned.wildcard.map(key),
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Stores the rewrite reads and writes, and the Zones this deployment serves. */
|
|
203
|
+
export type Options = {
|
|
204
|
+
/** Authoritative Postgres database holding organizations and delegations. */
|
|
205
|
+
db: Db.Db
|
|
206
|
+
/** KV state store holding API-key records and fences. */
|
|
207
|
+
store: Store.State
|
|
208
|
+
/** Chain ids of the hosted Zones; per-Zone scopes naming any other Zone earn no tag. */
|
|
209
|
+
zones: ReadonlySet<number>
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function key(record: ApiKeys.Record): Key {
|
|
213
|
+
return {
|
|
214
|
+
environment: record.environment,
|
|
215
|
+
id: record.id,
|
|
216
|
+
...(record.name === undefined ? {} : { name: record.name }),
|
|
217
|
+
orgId: record.orgId,
|
|
218
|
+
...(record.projectId === undefined ? {} : { projectId: record.projectId }),
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Thrown by {@link apply} when an active delegation for a planned Zone lists members; nothing was written. */
|
|
223
|
+
export class NarrowDelegationsError extends Error {
|
|
224
|
+
override readonly name = 'ZoneKeyRewrite.NarrowDelegationsError'
|
|
225
|
+
/** The delegations to widen to whole-Zone coverage (or revoke) before applying. */
|
|
226
|
+
readonly rows: readonly ZoneDelegations.Record[]
|
|
227
|
+
constructor(rows: readonly ZoneDelegations.Record[]) {
|
|
228
|
+
super(`${rows.length} active Zone delegation(s) list members; revoke them or request whole-Zone ones before rewriting keys.`) // prettier-ignore
|
|
229
|
+
this.rows = rows
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -811,6 +811,8 @@ export type RunEvidence = {
|
|
|
811
811
|
deferredRecipients?: number | undefined
|
|
812
812
|
/** Stable registration high-water mark consumed by the run. */
|
|
813
813
|
eligibilityCheckpoint?: string | undefined
|
|
814
|
+
/** When the run was delivered, in Unix seconds. */
|
|
815
|
+
deliveredAt?: number | undefined
|
|
814
816
|
/** Exact eligibility snapshot identity used by resumable calculation. */
|
|
815
817
|
eligibilityVersion?: Hex | undefined
|
|
816
818
|
/** Exact effective exclusion set identity used by resumable calculation. */
|
|
@@ -79,12 +79,10 @@ export namespace schema {
|
|
|
79
79
|
z.describe('Recipients skipped by the batch.'),
|
|
80
80
|
z.meta({ examples: [0] }),
|
|
81
81
|
),
|
|
82
|
-
timestamp:
|
|
83
|
-
.
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
|
|
87
|
-
),
|
|
82
|
+
timestamp: Schema.dateTime().check(
|
|
83
|
+
z.describe('Indexed block timestamp.'),
|
|
84
|
+
z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
|
|
85
|
+
),
|
|
88
86
|
transactionHash: Schema.Hash.check(
|
|
89
87
|
z.describe('Distribution transaction hash.'),
|
|
90
88
|
z.meta({ examples: [`0x${'11'.repeat(32)}`] }),
|
|
@@ -164,12 +162,10 @@ export namespace schema {
|
|
|
164
162
|
z.describe('Chain block number.'),
|
|
165
163
|
z.meta({ examples: [123456] }),
|
|
166
164
|
),
|
|
167
|
-
timestamp:
|
|
168
|
-
.
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
|
|
172
|
-
),
|
|
165
|
+
timestamp: Schema.dateTime().check(
|
|
166
|
+
z.describe('Chain block timestamp.'),
|
|
167
|
+
z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
|
|
168
|
+
),
|
|
173
169
|
})
|
|
174
170
|
.check(
|
|
175
171
|
z.describe('Chain block supporting the displayed evidence.'),
|