tapimo 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ApiKey.d.ts +2 -1
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKeys.d.ts +4 -2
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +26 -1
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +6007 -5003
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +1 -0
- package/dist/App.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +6 -6
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +91 -84
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +22 -13
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +6 -0
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +4 -2
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +69 -69
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +232 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +4 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +2 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/Zones.d.ts +4266 -82
- package/dist/apps/Zones.d.ts.map +1 -1
- package/dist/apps/Zones.js +27 -8
- package/dist/apps/Zones.js.map +1 -1
- package/dist/apps/data/App.d.ts +3467 -2696
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +2 -0
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +2999 -100
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +340 -2
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +514 -0
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +26 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +7 -3
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +4 -4
- package/dist/apps/data/routes/earn.d.ts +75 -75
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +65 -36
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +124 -120
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +115 -77
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +24 -24
- package/dist/apps/data/routes/indexer.d.ts +2 -1
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +3 -2
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +4 -3
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +15 -14
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +5 -1
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/tokens.d.ts +1 -1
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +4 -3
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +25 -7
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +37 -37
- package/dist/apps/data/routes/webhooks.d.ts +71 -1
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +177 -23
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.js +1 -1
- package/dist/apps/data/routes/zones.js.map +1 -1
- package/dist/apps/funding/App.d.ts +322 -89
- package/dist/apps/funding/App.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts +375 -45
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +208 -12
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/funding/routes/transfers.d.ts +32 -32
- package/dist/apps/funding/routes/transfers.js +1 -1
- package/dist/apps/funding/routes/transfers.js.map +1 -1
- package/dist/apps/management/App.d.ts +418 -418
- package/dist/apps/management/routes/api-keys.d.ts +50 -50
- package/dist/apps/management/routes/billing.d.ts +72 -72
- package/dist/apps/management/routes/billing.js +1 -1
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +8 -8
- package/dist/apps/management/routes/faucet.js +2 -2
- package/dist/apps/management/routes/faucet.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +42 -42
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +14 -14
- package/dist/apps/management/routes/projects.d.ts +40 -40
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/webhooks.d.ts +49 -49
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +4 -1
- package/dist/apps/mcp.js.map +1 -1
- package/dist/db/Db.d.ts +2 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +90 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +19 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +24 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/fundingDepositAddresses.d.ts +20 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
- package/dist/db/tables/fundingDepositAddresses.js +17 -0
- package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
- package/dist/db/tables/fundingDeposits.d.ts +41 -0
- package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
- package/dist/db/tables/fundingDeposits.js +69 -0
- package/dist/db/tables/fundingDeposits.js.map +1 -1
- package/dist/db/tables/webhookQueueEvents.d.ts +122 -0
- package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -0
- package/dist/db/tables/webhookQueueEvents.js +160 -0
- package/dist/db/tables/webhookQueueEvents.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +2 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +10 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/Auth.d.ts +3 -26
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +6 -37
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Credential.d.ts +27 -0
- package/dist/internal/Credential.d.ts.map +1 -0
- package/dist/internal/Credential.js +34 -0
- package/dist/internal/Credential.js.map +1 -0
- package/dist/internal/EarnRates.js +11 -7
- package/dist/internal/EarnRates.js.map +1 -1
- package/dist/internal/Log.d.ts +8 -0
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +4 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +51 -0
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +54 -2
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +4 -6
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +15 -14
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Store.d.ts +2 -1
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +57 -18
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +4 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +2 -2
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Value.d.ts +2 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +25 -0
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/Viem.d.ts +4 -3
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +3 -2
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookTransfer.d.ts +20 -0
- package/dist/internal/WebhookTransfer.d.ts.map +1 -1
- package/dist/internal/WebhookTransfer.js +7 -4
- package/dist/internal/WebhookTransfer.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +141 -0
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +139 -10
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/funding/providers/relay.d.ts +3 -4
- package/dist/internal/funding/providers/relay.d.ts.map +1 -1
- package/dist/internal/funding/providers/relay.js +59 -8
- package/dist/internal/funding/providers/relay.js.map +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -0
- package/dist/internal/index.js.map +1 -1
- package/package.json +3 -3
- package/src/ApiKeys.test.ts +20 -0
- package/src/ApiKeys.ts +28 -1
- package/src/App.test.ts +40 -8
- package/src/App.ts +1 -0
- package/src/Client.test-d.ts +34 -1
- package/src/Webhooks.ts +20 -18
- package/src/admin/apps/api-keys.test.ts +9 -0
- package/src/admin/apps/api-keys.ts +15 -0
- package/src/admin/ui/src/lib/query-client.ts +3 -2
- package/src/admin/ui/src/routes/api-keys.tsx +31 -9
- package/src/admin/ui.generated.ts +69 -69
- package/src/analytics/Analytics.test.ts +42 -0
- package/src/analytics/Analytics.ts +232 -0
- package/src/analytics/tables/requestEvents.ts +6 -0
- package/src/apps/Zones.test.ts +20 -3
- package/src/apps/Zones.ts +28 -8
- package/src/apps/composition.test.ts +2 -0
- package/src/apps/data/App.test.ts +2 -2
- package/src/apps/data/App.ts +2 -0
- package/src/apps/data/routes/activities.bench.ts +41 -0
- package/src/apps/data/routes/activities.test.ts +103 -2
- package/src/apps/data/routes/activities.ts +401 -2
- package/src/apps/data/routes/balances.bench.ts +21 -0
- package/src/apps/data/routes/balances.ts +7 -3
- package/src/apps/data/routes/blocks.bench.ts +34 -0
- package/src/apps/data/routes/coingecko.bench.ts +53 -0
- package/src/apps/data/routes/earn.bench.ts +71 -0
- package/src/apps/data/routes/earn.ts +66 -36
- package/src/apps/data/routes/exchanges.bench.ts +85 -0
- package/src/apps/data/routes/exchanges.test.ts +8 -3
- package/src/apps/data/routes/exchanges.ts +134 -82
- package/src/apps/data/routes/fee-amm.bench.ts +13 -0
- package/src/apps/data/routes/indexer.bench.ts +8 -0
- package/src/apps/data/routes/indexer.test.ts +2 -1
- package/src/apps/data/routes/indexer.ts +3 -2
- package/src/apps/data/routes/receipts.bench.ts +39 -0
- package/src/apps/data/routes/receipts.ts +16 -14
- package/src/apps/data/routes/rpc.bench.ts +14 -0
- package/src/apps/data/routes/rpc.test.ts +27 -0
- package/src/apps/data/routes/rpc.ts +5 -1
- package/src/apps/data/routes/tokenlist.bench.ts +3 -0
- package/src/apps/data/routes/tokens.bench.ts +76 -0
- package/src/apps/data/routes/tokens.ts +3 -2
- package/src/apps/data/routes/transactions.bench.ts +48 -0
- package/src/apps/data/routes/transfers.bench.ts +28 -0
- package/src/apps/data/routes/transfers.ts +36 -10
- package/src/apps/data/routes/valuation.bench.ts +14 -0
- package/src/apps/data/routes/verified-tokens.bench.ts +8 -0
- package/src/apps/data/routes/webhooks.bench.ts +26 -0
- package/src/apps/data/routes/webhooks.scan.test.ts +326 -0
- package/src/apps/data/routes/webhooks.test.ts +53 -6
- package/src/apps/data/routes/webhooks.ts +252 -24
- package/src/apps/data/routes/zones.bench.ts +32 -0
- package/src/apps/data/routes/zones.test.ts +1 -1
- package/src/apps/data/routes/zones.ts +1 -1
- package/src/apps/funding/routes/chains.test.ts +1 -1
- package/src/apps/funding/routes/deposit-addresses.test.ts +217 -3
- package/src/apps/funding/routes/deposit-addresses.ts +255 -19
- package/src/apps/funding/routes/providers.test.ts +1 -1
- package/src/apps/funding/routes/quotes.test.ts +1 -1
- package/src/apps/funding/routes/transfers.test.ts +20 -8
- package/src/apps/funding/routes/transfers.ts +1 -1
- package/src/apps/management/routes/billing.ts +1 -1
- package/src/apps/management/routes/faucet.ts +2 -2
- package/src/apps/management/routes/me.test.ts +31 -0
- package/src/apps/mcp.ts +4 -1
- package/src/db/Db.ts +117 -0
- package/src/db/Schema.ts +32 -0
- package/src/db/tables/fundingDepositAddresses.test.ts +28 -0
- package/src/db/tables/fundingDepositAddresses.ts +39 -0
- package/src/db/tables/fundingDeposits.test.ts +82 -0
- package/src/db/tables/fundingDeposits.ts +130 -0
- package/src/db/tables/webhookQueueEvents.ts +285 -0
- package/src/db/tables/webhookSubscriptions.ts +15 -0
- package/src/internal/Auth.test.ts +61 -98
- package/src/internal/Auth.ts +9 -63
- package/src/internal/Credential.test.ts +51 -0
- package/src/internal/Credential.ts +58 -0
- package/src/internal/EarnRates.ts +13 -7
- package/src/internal/EarnVaults.test.ts +2 -2
- package/src/internal/Log.test.ts +3 -1
- package/src/internal/Log.ts +14 -0
- package/src/internal/MetricSink.test.ts +108 -2
- package/src/internal/MetricSink.ts +112 -2
- package/src/internal/RateLimit.test.ts +23 -18
- package/src/internal/RateLimit.ts +23 -15
- package/src/internal/Store.test.ts +99 -13
- package/src/internal/Store.ts +52 -17
- package/src/internal/Tidx.test.ts +4 -4
- package/src/internal/Tidx.ts +5 -4
- package/src/internal/Value.test.ts +25 -0
- package/src/internal/Value.ts +29 -0
- package/src/internal/Viem.test.ts +4 -0
- package/src/internal/Viem.ts +6 -4
- package/src/internal/WebhookTransfer.test.ts +89 -0
- package/src/internal/WebhookTransfer.ts +11 -7
- package/src/internal/Webhooks.test.ts +488 -0
- package/src/internal/Webhooks.ts +291 -10
- package/src/internal/funding/Provider.test.ts +1 -1
- package/src/internal/funding/providers/index.test.ts +73 -3
- package/src/internal/funding/providers/relay.test.ts +1 -5
- package/src/internal/funding/providers/relay.ts +56 -12
- package/src/internal/index.test.ts +1 -0
- package/src/internal/index.ts +1 -0
|
@@ -155,7 +155,7 @@ describe('require', () => {
|
|
|
155
155
|
const app = createApp({
|
|
156
156
|
policy: {
|
|
157
157
|
apiKey: { scopes: ['data:read'] },
|
|
158
|
-
public: { rateLimit: {
|
|
158
|
+
public: { rateLimit: { limit: 60, period: 'minute' } },
|
|
159
159
|
},
|
|
160
160
|
})
|
|
161
161
|
const response = await app.request('/protected', {
|
|
@@ -180,7 +180,7 @@ describe('require', () => {
|
|
|
180
180
|
logger: (entry) => void entries.push(entry),
|
|
181
181
|
policy: {
|
|
182
182
|
apiKey: { scopes: ['data:read'] },
|
|
183
|
-
public: { rateLimit: {
|
|
183
|
+
public: { rateLimit: { limit: 60, period: 'minute' } },
|
|
184
184
|
},
|
|
185
185
|
})
|
|
186
186
|
const response = await app.request('/protected', {
|
|
@@ -723,7 +723,9 @@ describe('require', () => {
|
|
|
723
723
|
}
|
|
724
724
|
const policy: Auth.require.Policy = {
|
|
725
725
|
apiKey: { scopes: [Scope.wildcard] },
|
|
726
|
-
...(options.public === false
|
|
726
|
+
...(options.public === false
|
|
727
|
+
? {}
|
|
728
|
+
: { public: { rateLimit: { limit: 60, period: 'minute' } } }),
|
|
727
729
|
...(options.mpp ? { mpp: { session: { amount: '1' } } } : {}),
|
|
728
730
|
}
|
|
729
731
|
const app = new Hono<Auth.Environment>()
|
|
@@ -825,7 +827,7 @@ describe('require', () => {
|
|
|
825
827
|
|
|
826
828
|
test('throttles a sandbox key to the public quota when billing is inactive', async () => {
|
|
827
829
|
const app = createChainApp({
|
|
828
|
-
public: true, // policy.public.rateLimit is {
|
|
830
|
+
public: true, // policy.public.rateLimit is { limit: 60, period: 'minute' }
|
|
829
831
|
sandboxBillingActive: false,
|
|
830
832
|
})
|
|
831
833
|
const response = await app.request('/protected?chainId=42431', {
|
|
@@ -863,7 +865,7 @@ describe('require', () => {
|
|
|
863
865
|
test('throttles to the configured public default on API-key-only routes', async () => {
|
|
864
866
|
const app = createChainApp({
|
|
865
867
|
public: false, // no per-route public lane
|
|
866
|
-
publicRateLimit: {
|
|
868
|
+
publicRateLimit: { limit: 7, period: 'minute' },
|
|
867
869
|
sandboxBillingActive: false,
|
|
868
870
|
})
|
|
869
871
|
const response = await app.request('/protected?chainId=42431', {
|
|
@@ -927,7 +929,7 @@ describe('require', () => {
|
|
|
927
929
|
expect(response.headers.get('RateLimit-Scope')).toBe('mpp')
|
|
928
930
|
expect(consume).toHaveBeenCalledWith({
|
|
929
931
|
key: 'mpp:public:2001:db8:abcd:12',
|
|
930
|
-
limit: {
|
|
932
|
+
limit: { limit: 100, period: 'minute' },
|
|
931
933
|
})
|
|
932
934
|
})
|
|
933
935
|
|
|
@@ -954,7 +956,7 @@ describe('require', () => {
|
|
|
954
956
|
expect(response.status).toBe(200)
|
|
955
957
|
expect(consume).toHaveBeenCalledWith({
|
|
956
958
|
key: 'mpp:public:anonymous',
|
|
957
|
-
limit: {
|
|
959
|
+
limit: { limit: 100, period: 'minute' },
|
|
958
960
|
})
|
|
959
961
|
})
|
|
960
962
|
|
|
@@ -980,7 +982,7 @@ describe('require', () => {
|
|
|
980
982
|
expect(response.status).toBe(200)
|
|
981
983
|
expect(consume).toHaveBeenCalledWith({
|
|
982
984
|
key: 'mpp:public:2001:db8:abcd:12',
|
|
983
|
-
limit: {
|
|
985
|
+
limit: { limit: 100, period: 'minute' },
|
|
984
986
|
})
|
|
985
987
|
})
|
|
986
988
|
|
|
@@ -1009,7 +1011,7 @@ describe('require', () => {
|
|
|
1009
1011
|
expect(response.status).toBe(200)
|
|
1010
1012
|
expect(consume).toHaveBeenCalledWith({
|
|
1011
1013
|
key: 'mpp:api_key:key_test',
|
|
1012
|
-
limit: {
|
|
1014
|
+
limit: { limit: 100, period: 'minute' },
|
|
1013
1015
|
})
|
|
1014
1016
|
})
|
|
1015
1017
|
|
|
@@ -1017,7 +1019,7 @@ describe('require', () => {
|
|
|
1017
1019
|
const app = createApp({
|
|
1018
1020
|
auth: {
|
|
1019
1021
|
apiKey: { resolve: TestApp.resolver({ keys: [{ ...key, token }] }) },
|
|
1020
|
-
mpp: createMppHandler({ rateLimit: {
|
|
1022
|
+
mpp: createMppHandler({ rateLimit: { limit: 25, period: 'minute' } }),
|
|
1021
1023
|
rateLimit: underQuota(),
|
|
1022
1024
|
},
|
|
1023
1025
|
policy: { mpp: { session: { amount: '1' } } },
|
|
@@ -1034,12 +1036,12 @@ describe('require', () => {
|
|
|
1034
1036
|
const app = createApp({
|
|
1035
1037
|
auth: {
|
|
1036
1038
|
apiKey: { resolve: TestApp.resolver({ keys: [{ ...key, token }] }) },
|
|
1037
|
-
mpp: createMppHandler({ rateLimit: {
|
|
1039
|
+
mpp: createMppHandler({ rateLimit: { limit: 25, period: 'minute' } }),
|
|
1038
1040
|
rateLimit: underQuota(),
|
|
1039
1041
|
},
|
|
1040
1042
|
policy: {
|
|
1041
1043
|
mpp: {
|
|
1042
|
-
rateLimit: {
|
|
1044
|
+
rateLimit: { limit: 5, period: 'minute' },
|
|
1043
1045
|
session: { amount: '1' },
|
|
1044
1046
|
},
|
|
1045
1047
|
},
|
|
@@ -1082,7 +1084,7 @@ describe('require', () => {
|
|
|
1082
1084
|
},
|
|
1083
1085
|
policy: {
|
|
1084
1086
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
1085
|
-
public: { rateLimit: {
|
|
1087
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1086
1088
|
},
|
|
1087
1089
|
})
|
|
1088
1090
|
const response = await app.request('/protected')
|
|
@@ -1103,7 +1105,7 @@ describe('require', () => {
|
|
|
1103
1105
|
},
|
|
1104
1106
|
policy: {
|
|
1105
1107
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
1106
|
-
public: { rateLimit: {
|
|
1108
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1107
1109
|
},
|
|
1108
1110
|
})
|
|
1109
1111
|
const response = await createMppClient(app).fetch('http://tempo-api.test/protected')
|
|
@@ -1134,7 +1136,7 @@ describe('require', () => {
|
|
|
1134
1136
|
},
|
|
1135
1137
|
policy: {
|
|
1136
1138
|
apiKey: {
|
|
1137
|
-
rateLimit: {
|
|
1139
|
+
rateLimit: { limit: 1, period: 'minute' },
|
|
1138
1140
|
scopes: ['data:read'],
|
|
1139
1141
|
},
|
|
1140
1142
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
@@ -1160,7 +1162,7 @@ describe('require', () => {
|
|
|
1160
1162
|
},
|
|
1161
1163
|
policy: {
|
|
1162
1164
|
apiKey: {
|
|
1163
|
-
rateLimit: {
|
|
1165
|
+
rateLimit: { limit: 1, period: 'minute' },
|
|
1164
1166
|
scopes: ['data:read'],
|
|
1165
1167
|
},
|
|
1166
1168
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
@@ -1199,7 +1201,7 @@ describe('require', () => {
|
|
|
1199
1201
|
},
|
|
1200
1202
|
policy: {
|
|
1201
1203
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
1202
|
-
public: { rateLimit: {
|
|
1204
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1203
1205
|
},
|
|
1204
1206
|
})
|
|
1205
1207
|
const response = await app.request('/protected')
|
|
@@ -1237,7 +1239,7 @@ describe('require', () => {
|
|
|
1237
1239
|
},
|
|
1238
1240
|
policy: {
|
|
1239
1241
|
mpp: { session: { amount: '1' } },
|
|
1240
|
-
public: { rateLimit: {
|
|
1242
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1241
1243
|
},
|
|
1242
1244
|
})
|
|
1243
1245
|
|
|
@@ -1272,7 +1274,7 @@ describe('require', () => {
|
|
|
1272
1274
|
},
|
|
1273
1275
|
policy: {
|
|
1274
1276
|
mpp: { session: { amount: '1' } },
|
|
1275
|
-
public: { rateLimit: {
|
|
1277
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1276
1278
|
},
|
|
1277
1279
|
})
|
|
1278
1280
|
|
|
@@ -1294,7 +1296,7 @@ describe('require', () => {
|
|
|
1294
1296
|
},
|
|
1295
1297
|
policy: {
|
|
1296
1298
|
mpp: { session: { amount: '2.5', suggestedDeposit: '10' } },
|
|
1297
|
-
public: { rateLimit: {
|
|
1299
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1298
1300
|
},
|
|
1299
1301
|
})
|
|
1300
1302
|
const response = await app.request('/protected')
|
|
@@ -1318,7 +1320,7 @@ describe('require', () => {
|
|
|
1318
1320
|
},
|
|
1319
1321
|
policy: {
|
|
1320
1322
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
1321
|
-
public: { rateLimit: {
|
|
1323
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1322
1324
|
},
|
|
1323
1325
|
})
|
|
1324
1326
|
const response = await createMppClient(app).fetch('http://tempo-api.test/protected')
|
|
@@ -1354,7 +1356,7 @@ describe('require', () => {
|
|
|
1354
1356
|
policy: {
|
|
1355
1357
|
// The suggested deposit pre-funds the channel for both requests.
|
|
1356
1358
|
mpp: { session: { amount: '1', suggestedDeposit: '2' } },
|
|
1357
|
-
public: { rateLimit: {
|
|
1359
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1358
1360
|
},
|
|
1359
1361
|
})
|
|
1360
1362
|
const client = createMppClient(app)
|
|
@@ -1390,7 +1392,7 @@ describe('require', () => {
|
|
|
1390
1392
|
},
|
|
1391
1393
|
policy: {
|
|
1392
1394
|
mpp: { session: { amount: '1', suggestedDeposit: '2' } },
|
|
1393
|
-
public: { rateLimit: {
|
|
1395
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1394
1396
|
},
|
|
1395
1397
|
})
|
|
1396
1398
|
const client = createMppClient({ fetch: (request) => app.fetch(request) })
|
|
@@ -1404,7 +1406,7 @@ describe('require', () => {
|
|
|
1404
1406
|
},
|
|
1405
1407
|
policy: {
|
|
1406
1408
|
mpp: { session: { amount: '1', suggestedDeposit: '2' } },
|
|
1407
|
-
public: { rateLimit: {
|
|
1409
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1408
1410
|
},
|
|
1409
1411
|
})
|
|
1410
1412
|
const second = await client.fetch('http://tempo-api.test/protected')
|
|
@@ -1427,7 +1429,7 @@ describe('require', () => {
|
|
|
1427
1429
|
},
|
|
1428
1430
|
policy: {
|
|
1429
1431
|
mpp: { session: { amount: '1' } },
|
|
1430
|
-
public: { rateLimit: {
|
|
1432
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1431
1433
|
},
|
|
1432
1434
|
})
|
|
1433
1435
|
const client = createMppClient(app)
|
|
@@ -1463,7 +1465,7 @@ describe('require', () => {
|
|
|
1463
1465
|
},
|
|
1464
1466
|
policy: {
|
|
1465
1467
|
mpp: { session: { amount: '1' } },
|
|
1466
|
-
public: { rateLimit: {
|
|
1468
|
+
public: { rateLimit: { limit: 1, period: 'minute' } },
|
|
1467
1469
|
},
|
|
1468
1470
|
})
|
|
1469
1471
|
const response = await app.request('/protected', {
|
|
@@ -1478,7 +1480,7 @@ describe('require', () => {
|
|
|
1478
1480
|
describe('rateLimit', () => {
|
|
1479
1481
|
test('allows anonymous public requests under quota', async () => {
|
|
1480
1482
|
const app = createApp({
|
|
1481
|
-
policy: { public: { rateLimit: {
|
|
1483
|
+
policy: { public: { rateLimit: { limit: 60, period: 'minute' } } },
|
|
1482
1484
|
})
|
|
1483
1485
|
const response = await app.request('/protected', {
|
|
1484
1486
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1502,7 +1504,7 @@ describe('require', () => {
|
|
|
1502
1504
|
apiKey: { resolve: TestApp.resolver({ keys: [{ ...key, token }] }) },
|
|
1503
1505
|
rateLimit: overQuota(),
|
|
1504
1506
|
},
|
|
1505
|
-
policy: { public: { rateLimit: {
|
|
1507
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1506
1508
|
})
|
|
1507
1509
|
const response = await app.request('/protected')
|
|
1508
1510
|
const body = await response.json()
|
|
@@ -1530,7 +1532,7 @@ describe('require', () => {
|
|
|
1530
1532
|
},
|
|
1531
1533
|
},
|
|
1532
1534
|
},
|
|
1533
|
-
policy: { public: { rateLimit: {
|
|
1535
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1534
1536
|
})
|
|
1535
1537
|
const response = await app.request('/protected', {
|
|
1536
1538
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1588,7 +1590,7 @@ describe('require', () => {
|
|
|
1588
1590
|
// the consume must not block the request indefinitely.
|
|
1589
1591
|
rateLimit: { consume: () => new Promise<never>(() => {}) },
|
|
1590
1592
|
},
|
|
1591
|
-
policy: { public: { rateLimit: {
|
|
1593
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1592
1594
|
})
|
|
1593
1595
|
const pending = app.request('/protected', {
|
|
1594
1596
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1632,7 +1634,7 @@ describe('require', () => {
|
|
|
1632
1634
|
},
|
|
1633
1635
|
},
|
|
1634
1636
|
},
|
|
1635
|
-
policy: { public: { rateLimit: {
|
|
1637
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1636
1638
|
})
|
|
1637
1639
|
const response = await app.request('/protected', {
|
|
1638
1640
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1669,7 +1671,7 @@ describe('require', () => {
|
|
|
1669
1671
|
},
|
|
1670
1672
|
},
|
|
1671
1673
|
},
|
|
1672
|
-
policy: { public: { rateLimit: {
|
|
1674
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1673
1675
|
})
|
|
1674
1676
|
const response = await app.request('/protected', {
|
|
1675
1677
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1698,7 +1700,7 @@ describe('require', () => {
|
|
|
1698
1700
|
},
|
|
1699
1701
|
},
|
|
1700
1702
|
},
|
|
1701
|
-
policy: { public: { rateLimit: {
|
|
1703
|
+
policy: { public: { rateLimit: { limit: 1, period: 'minute' } } },
|
|
1702
1704
|
})
|
|
1703
1705
|
const response = await app.request('/protected', {
|
|
1704
1706
|
headers: { 'cf-connecting-ip': '203.0.113.10' },
|
|
@@ -1731,7 +1733,10 @@ describe('require', () => {
|
|
|
1731
1733
|
test('does not share quota across scopes', async () => {
|
|
1732
1734
|
const auth = {
|
|
1733
1735
|
apiKey: {
|
|
1734
|
-
rateLimits: {
|
|
1736
|
+
rateLimits: {
|
|
1737
|
+
'data:read': { limit: 1, period: 'minute' },
|
|
1738
|
+
'webhooks:write': { limit: 1, period: 'minute' },
|
|
1739
|
+
},
|
|
1735
1740
|
resolve: TestApp.resolver({
|
|
1736
1741
|
keys: [{ ...key, scopes: [Scope.wildcard], token }],
|
|
1737
1742
|
}),
|
|
@@ -1785,7 +1790,7 @@ describe('require', () => {
|
|
|
1785
1790
|
test('route cap overrides the configured scope limit', async () => {
|
|
1786
1791
|
const auth = {
|
|
1787
1792
|
apiKey: {
|
|
1788
|
-
rateLimits: { 'data:read': {
|
|
1793
|
+
rateLimits: { 'data:read': { limit: 1_000, period: 'minute' } },
|
|
1789
1794
|
resolve: TestApp.resolver({
|
|
1790
1795
|
keys: [{ ...key, scopes: [Scope.wildcard], token }],
|
|
1791
1796
|
}),
|
|
@@ -1797,7 +1802,9 @@ describe('require', () => {
|
|
|
1797
1802
|
routes: [
|
|
1798
1803
|
{
|
|
1799
1804
|
path: '/protected',
|
|
1800
|
-
policy: {
|
|
1805
|
+
policy: {
|
|
1806
|
+
apiKey: { rateLimit: { limit: 5, period: 'minute' }, scopes: ['data:read'] },
|
|
1807
|
+
},
|
|
1801
1808
|
},
|
|
1802
1809
|
],
|
|
1803
1810
|
})
|
|
@@ -1814,7 +1821,7 @@ describe('require', () => {
|
|
|
1814
1821
|
keys: [
|
|
1815
1822
|
{
|
|
1816
1823
|
...key,
|
|
1817
|
-
rateLimits: { '*': {
|
|
1824
|
+
rateLimits: { '*': { limit: 7, period: 'minute' } },
|
|
1818
1825
|
scopes: [Scope.wildcard],
|
|
1819
1826
|
token,
|
|
1820
1827
|
},
|
|
@@ -1823,7 +1830,7 @@ describe('require', () => {
|
|
|
1823
1830
|
|
|
1824
1831
|
const open = createScopedApp({
|
|
1825
1832
|
auth: {
|
|
1826
|
-
apiKey: { rateLimits: { '*': {
|
|
1833
|
+
apiKey: { rateLimits: { '*': { limit: 1_000, period: 'minute' } }, resolve },
|
|
1827
1834
|
rateLimit: RateLimit.memory(),
|
|
1828
1835
|
},
|
|
1829
1836
|
routes: [{ path: '/protected', policy: { apiKey: { scopes: ['data:read'] } } }],
|
|
@@ -1834,13 +1841,15 @@ describe('require', () => {
|
|
|
1834
1841
|
|
|
1835
1842
|
const capped = createScopedApp({
|
|
1836
1843
|
auth: {
|
|
1837
|
-
apiKey: { rateLimits: { '*': {
|
|
1844
|
+
apiKey: { rateLimits: { '*': { limit: 1_000, period: 'minute' } }, resolve },
|
|
1838
1845
|
rateLimit: RateLimit.memory(),
|
|
1839
1846
|
},
|
|
1840
1847
|
routes: [
|
|
1841
1848
|
{
|
|
1842
1849
|
path: '/protected',
|
|
1843
|
-
policy: {
|
|
1850
|
+
policy: {
|
|
1851
|
+
apiKey: { rateLimit: { limit: 5, period: 'minute' }, scopes: ['data:read'] },
|
|
1852
|
+
},
|
|
1844
1853
|
},
|
|
1845
1854
|
],
|
|
1846
1855
|
})
|
|
@@ -1861,7 +1870,7 @@ describe('require', () => {
|
|
|
1861
1870
|
keys: [
|
|
1862
1871
|
{
|
|
1863
1872
|
...key,
|
|
1864
|
-
rateLimits: { 'data:read': {
|
|
1873
|
+
rateLimits: { 'data:read': { limit: 9, period: 'minute' } },
|
|
1865
1874
|
scopes: [Scope.wildcard],
|
|
1866
1875
|
token,
|
|
1867
1876
|
},
|
|
@@ -1875,7 +1884,9 @@ describe('require', () => {
|
|
|
1875
1884
|
routes: [
|
|
1876
1885
|
{
|
|
1877
1886
|
path: '/protected',
|
|
1878
|
-
policy: {
|
|
1887
|
+
policy: {
|
|
1888
|
+
apiKey: { rateLimit: { limit: 5, period: 'minute' }, scopes: ['data:read'] },
|
|
1889
|
+
},
|
|
1879
1890
|
},
|
|
1880
1891
|
],
|
|
1881
1892
|
})
|
|
@@ -1894,7 +1905,7 @@ describe('require', () => {
|
|
|
1894
1905
|
rateLimit: overQuota(),
|
|
1895
1906
|
},
|
|
1896
1907
|
logger: (entry) => void entries.push(entry),
|
|
1897
|
-
policy: { apiKey: { rateLimit: {
|
|
1908
|
+
policy: { apiKey: { rateLimit: { limit: 1, period: 'minute' }, scopes: ['data:read'] } },
|
|
1898
1909
|
})
|
|
1899
1910
|
const response = await app.request('/protected', {
|
|
1900
1911
|
headers: { 'tempo-api-key': token },
|
|
@@ -1923,7 +1934,7 @@ describe('require', () => {
|
|
|
1923
1934
|
rateLimit: overQuota(),
|
|
1924
1935
|
},
|
|
1925
1936
|
policy: {
|
|
1926
|
-
apiKey: { rateLimit: {
|
|
1937
|
+
apiKey: { rateLimit: { limit: 1, period: 'minute' }, scopes: ['data:read'] },
|
|
1927
1938
|
mpp: { session: { amount: '1', description: 'Protected data' } },
|
|
1928
1939
|
},
|
|
1929
1940
|
})
|
|
@@ -2089,54 +2100,6 @@ describe('ensureProject', () => {
|
|
|
2089
2100
|
})
|
|
2090
2101
|
})
|
|
2091
2102
|
|
|
2092
|
-
describe('parseCredential', () => {
|
|
2093
|
-
test('parses credentials keyed by chain id', () => {
|
|
2094
|
-
const credential = Auth.parseCredential(
|
|
2095
|
-
JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone:secret' }),
|
|
2096
|
-
)
|
|
2097
|
-
|
|
2098
|
-
expect(credential).toEqual({ 4217: 'mainnet:secret', 421700001: 'zone:secret' })
|
|
2099
|
-
})
|
|
2100
|
-
|
|
2101
|
-
test('supports a shared credential', () => {
|
|
2102
|
-
expect(Auth.parseCredential('shared:secret')).toBe('shared:secret')
|
|
2103
|
-
})
|
|
2104
|
-
|
|
2105
|
-
test('rejects malformed credential maps', () => {
|
|
2106
|
-
expect(() => Auth.parseCredential('{"4217":1}')).toThrowErrorMatchingInlineSnapshot(
|
|
2107
|
-
`[Error: Expected a credential or a chain-id-to-credential JSON object.]`,
|
|
2108
|
-
)
|
|
2109
|
-
})
|
|
2110
|
-
})
|
|
2111
|
-
|
|
2112
|
-
describe('resolveCredential', () => {
|
|
2113
|
-
test('infers Basic auth from a credential containing a colon', () => {
|
|
2114
|
-
expect(Auth.resolveCredential({ chainId: 4217, value: 'user:password' })).toEqual({
|
|
2115
|
-
basicAuth: 'user:password',
|
|
2116
|
-
})
|
|
2117
|
-
})
|
|
2118
|
-
|
|
2119
|
-
test('infers Bearer auth from a credential without a colon', () => {
|
|
2120
|
-
expect(Auth.resolveCredential({ chainId: 4217, value: 'bearer-token' })).toEqual({
|
|
2121
|
-
basicAuth: undefined,
|
|
2122
|
-
bearerAuth: 'bearer-token',
|
|
2123
|
-
})
|
|
2124
|
-
})
|
|
2125
|
-
|
|
2126
|
-
test('selects a credential by chain id', () => {
|
|
2127
|
-
const value = JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone-token' })
|
|
2128
|
-
|
|
2129
|
-
expect(Auth.resolveCredential({ chainId: 4217, value })).toEqual({
|
|
2130
|
-
basicAuth: 'mainnet:secret',
|
|
2131
|
-
})
|
|
2132
|
-
expect(Auth.resolveCredential({ chainId: 421700001, value })).toEqual({
|
|
2133
|
-
basicAuth: undefined,
|
|
2134
|
-
bearerAuth: 'zone-token',
|
|
2135
|
-
})
|
|
2136
|
-
expect(Auth.resolveCredential({ chainId: 42431, value })).toEqual({ basicAuth: undefined })
|
|
2137
|
-
})
|
|
2138
|
-
})
|
|
2139
|
-
|
|
2140
2103
|
function createScopedApp(options: {
|
|
2141
2104
|
auth?: Auth.Context | undefined
|
|
2142
2105
|
routes: readonly { path: string; policy: Auth.require.Policy }[]
|
|
@@ -2312,7 +2275,7 @@ function overQuota(): RateLimit.Store {
|
|
|
2312
2275
|
async consume(options) {
|
|
2313
2276
|
return {
|
|
2314
2277
|
allowed: false,
|
|
2315
|
-
limit: options.limit.
|
|
2278
|
+
limit: options.limit.limit,
|
|
2316
2279
|
remaining: 0,
|
|
2317
2280
|
reset: Math.ceil(Date.now() / 1_000) + 60,
|
|
2318
2281
|
}
|
|
@@ -2325,8 +2288,8 @@ function underQuota(): RateLimit.Store {
|
|
|
2325
2288
|
async consume(options) {
|
|
2326
2289
|
return {
|
|
2327
2290
|
allowed: true,
|
|
2328
|
-
limit: options.limit.
|
|
2329
|
-
remaining: Math.max(options.limit.
|
|
2291
|
+
limit: options.limit.limit,
|
|
2292
|
+
remaining: Math.max(options.limit.limit - 1, 0),
|
|
2330
2293
|
reset: Math.ceil(Date.now() / 1_000) + 60,
|
|
2331
2294
|
}
|
|
2332
2295
|
},
|
|
@@ -2339,13 +2302,13 @@ function overQuotaExceptMpp(): RateLimit.Store {
|
|
|
2339
2302
|
if (options.key.startsWith('mpp:'))
|
|
2340
2303
|
return {
|
|
2341
2304
|
allowed: true,
|
|
2342
|
-
limit: options.limit.
|
|
2343
|
-
remaining: Math.max(options.limit.
|
|
2305
|
+
limit: options.limit.limit,
|
|
2306
|
+
remaining: Math.max(options.limit.limit - 1, 0),
|
|
2344
2307
|
reset: Math.ceil(Date.now() / 1_000) + 60,
|
|
2345
2308
|
}
|
|
2346
2309
|
return {
|
|
2347
2310
|
allowed: false,
|
|
2348
|
-
limit: options.limit.
|
|
2311
|
+
limit: options.limit.limit,
|
|
2349
2312
|
remaining: 0,
|
|
2350
2313
|
reset: Math.ceil(Date.now() / 1_000) + 60,
|
|
2351
2314
|
}
|
package/src/internal/Auth.ts
CHANGED
|
@@ -28,11 +28,12 @@ import * as Response from './Response.js'
|
|
|
28
28
|
import * as Schema from './Schema.js'
|
|
29
29
|
import * as Scope from '../Scope.js'
|
|
30
30
|
import * as Users from '../db/tables/users.js'
|
|
31
|
+
import type * as Viem from './Viem.js'
|
|
31
32
|
|
|
32
33
|
const policySymbol = Symbol('tempo-api.auth.policy')
|
|
33
34
|
const mppManagementSymbol = Symbol('tempo-api.auth.mpp-management')
|
|
34
|
-
const defaultApiKeyRateLimit = {
|
|
35
|
-
const defaultMppRateLimit = {
|
|
35
|
+
const defaultApiKeyRateLimit = { limit: 10_000, period: 'minute' } satisfies RateLimit.Limit
|
|
36
|
+
const defaultMppRateLimit = { limit: 100, period: 'minute' } satisfies RateLimit.Limit
|
|
36
37
|
|
|
37
38
|
/** Auth context consumed by Tempo API handlers. */
|
|
38
39
|
export type Context = {
|
|
@@ -788,6 +789,7 @@ export function install(options: install.Options) {
|
|
|
788
789
|
(typeof options_session === 'object' ? options_session.wallet : undefined) ?? {}
|
|
789
790
|
|
|
790
791
|
const handler = Accounts.Handler.auth({
|
|
792
|
+
getClient: options.getClient,
|
|
791
793
|
...(issuer || requireEmail
|
|
792
794
|
? { identity: { ...(issuer ? { issuer } : {}), ...(requireEmail ? { required: true } : {}) } } // prettier-ignore
|
|
793
795
|
: {}),
|
|
@@ -912,6 +914,7 @@ export function install(options: install.Options) {
|
|
|
912
914
|
409: handlerError('Challenge nonce already used or unknown.'),
|
|
913
915
|
429: OpenApi.standardError(429, 'Rate limited.'),
|
|
914
916
|
500: OpenApi.standardError(500, 'Internal server error.'),
|
|
917
|
+
502: handlerError('The Tempo RPC could not verify the signature.'),
|
|
915
918
|
},
|
|
916
919
|
summary: 'Authenticate (SIWE)',
|
|
917
920
|
tags: ['Authentication'],
|
|
@@ -967,6 +970,8 @@ export declare namespace install {
|
|
|
967
970
|
| undefined
|
|
968
971
|
/** Authoritative database holding user rows. */
|
|
969
972
|
db: Db.Source
|
|
973
|
+
/** Resolves the configured Tempo RPC client used for SIWE signature verification. */
|
|
974
|
+
getClient: (chainId: number) => Viem.getClient.ReturnType
|
|
970
975
|
/** KV state store, or undefined when key auth is closed. */
|
|
971
976
|
kv: { store: Store.State } | undefined
|
|
972
977
|
/** Scope catalog accepted while resolving API-key records. */
|
|
@@ -1142,7 +1147,7 @@ function laneDefaults(options: middleware.Options): LaneDefaults {
|
|
|
1142
1147
|
scopes: apiKey?.scopes ?? [Scope.wildcard],
|
|
1143
1148
|
},
|
|
1144
1149
|
mpp: { session: {} },
|
|
1145
|
-
public: { rateLimit: public_?.rateLimit ?? {
|
|
1150
|
+
public: { rateLimit: public_?.rateLimit ?? { limit: 60, period: 'minute' } },
|
|
1146
1151
|
session: true,
|
|
1147
1152
|
}
|
|
1148
1153
|
}
|
|
@@ -1525,7 +1530,7 @@ export function require<environment extends Environment = Environment>(
|
|
|
1525
1530
|
// A throttled sandbox key shares the key's bucket but at the public
|
|
1526
1531
|
// ceiling, so activating billing lifts the limit on the same counter.
|
|
1527
1532
|
const limit = throttled
|
|
1528
|
-
? (policy.public?.rateLimit ?? auth.publicRateLimit ?? {
|
|
1533
|
+
? (policy.public?.rateLimit ?? auth.publicRateLimit ?? { limit: 60, period: 'minute' })
|
|
1529
1534
|
: resolveApiKeyLimit({ apiKey, auth, policy: policy.apiKey, scope })
|
|
1530
1535
|
const result = await consumeRateLimit(auth, {
|
|
1531
1536
|
key: `api_key:${apiKey.id}:scope:${scope}`,
|
|
@@ -1669,65 +1674,6 @@ type RateLimitAccess = PaymentAccess & {
|
|
|
1669
1674
|
rateLimit: RateLimit.Result
|
|
1670
1675
|
}
|
|
1671
1676
|
|
|
1672
|
-
/** Shared or per-chain credentials. */
|
|
1673
|
-
export type ChainCredential = string | Record<number, string>
|
|
1674
|
-
|
|
1675
|
-
/** Parses shared or per-chain credentials from an environment value. */
|
|
1676
|
-
export function parseCredential(value: ChainCredential | undefined): parseCredential.ReturnType {
|
|
1677
|
-
if (!value) return undefined
|
|
1678
|
-
if (typeof value !== 'string') return value
|
|
1679
|
-
const credentials = (() => {
|
|
1680
|
-
try {
|
|
1681
|
-
return JSON.parse(value) as unknown
|
|
1682
|
-
} catch {
|
|
1683
|
-
return value
|
|
1684
|
-
}
|
|
1685
|
-
})()
|
|
1686
|
-
if (typeof credentials === 'string') return credentials
|
|
1687
|
-
if (
|
|
1688
|
-
!credentials ||
|
|
1689
|
-
typeof credentials !== 'object' ||
|
|
1690
|
-
Array.isArray(credentials) ||
|
|
1691
|
-
Object.values(credentials).some((credential) => typeof credential !== 'string')
|
|
1692
|
-
)
|
|
1693
|
-
throw new Error('Expected a credential or a chain-id-to-credential JSON object.')
|
|
1694
|
-
return credentials as Record<number, string>
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
export declare namespace parseCredential {
|
|
1698
|
-
/** Parsed shared or per-chain credentials. */
|
|
1699
|
-
type ReturnType = ChainCredential | undefined
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
/** Resolves a chain credential and infers its HTTP authorization scheme. */
|
|
1703
|
-
export function resolveCredential(
|
|
1704
|
-
options: resolveCredential.Options,
|
|
1705
|
-
): resolveCredential.ReturnType {
|
|
1706
|
-
const credentials = parseCredential(options.value)
|
|
1707
|
-
const credential = typeof credentials === 'string' ? credentials : credentials?.[options.chainId]
|
|
1708
|
-
if (!credential) return { basicAuth: undefined }
|
|
1709
|
-
if (credential.includes(':')) return { basicAuth: credential }
|
|
1710
|
-
return { basicAuth: undefined, bearerAuth: credential }
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
export declare namespace resolveCredential {
|
|
1714
|
-
/** Options for resolving a chain credential. */
|
|
1715
|
-
type Options = {
|
|
1716
|
-
/** Chain id selecting a per-chain credential. */
|
|
1717
|
-
chainId: number
|
|
1718
|
-
/** Shared or per-chain credentials. */
|
|
1719
|
-
value?: ChainCredential | undefined
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
/** Resolved HTTP authorization credentials. */
|
|
1723
|
-
type ReturnType = {
|
|
1724
|
-
/** Basic credentials inferred from a value containing a colon. */
|
|
1725
|
-
basicAuth: string | undefined
|
|
1726
|
-
/** Bearer credential inferred from a value without a colon. */
|
|
1727
|
-
bearerAuth?: string | undefined
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
1677
|
/**
|
|
1732
1678
|
* How long to wait for the rate-limit counter before failing open. A hot
|
|
1733
1679
|
* counter backend (e.g. a single Durable Object serving one busy quota bucket)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as Credential from './Credential.js'
|
|
2
|
+
|
|
3
|
+
describe('parseCredential', () => {
|
|
4
|
+
test('parses credentials keyed by chain id', () => {
|
|
5
|
+
const credential = Credential.parseCredential(
|
|
6
|
+
JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone:secret' }),
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
expect(credential).toEqual({ 4217: 'mainnet:secret', 421700001: 'zone:secret' })
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('supports a shared credential', () => {
|
|
13
|
+
expect(Credential.parseCredential('shared:secret')).toBe('shared:secret')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('rejects malformed credential maps', () => {
|
|
17
|
+
expect(() => Credential.parseCredential('{"4217":1}')).toThrowErrorMatchingInlineSnapshot(
|
|
18
|
+
`[Error: Expected a credential or a chain-id-to-credential JSON object.]`,
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('resolveCredential', () => {
|
|
24
|
+
test('infers Basic auth from a credential containing a colon', () => {
|
|
25
|
+
expect(Credential.resolveCredential({ chainId: 4217, value: 'user:password' })).toEqual({
|
|
26
|
+
basicAuth: 'user:password',
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('infers Bearer auth from a credential without a colon', () => {
|
|
31
|
+
expect(Credential.resolveCredential({ chainId: 4217, value: 'bearer-token' })).toEqual({
|
|
32
|
+
basicAuth: undefined,
|
|
33
|
+
bearerAuth: 'bearer-token',
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('selects a credential by chain id', () => {
|
|
38
|
+
const value = JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone-token' })
|
|
39
|
+
|
|
40
|
+
expect(Credential.resolveCredential({ chainId: 4217, value })).toEqual({
|
|
41
|
+
basicAuth: 'mainnet:secret',
|
|
42
|
+
})
|
|
43
|
+
expect(Credential.resolveCredential({ chainId: 421700001, value })).toEqual({
|
|
44
|
+
basicAuth: undefined,
|
|
45
|
+
bearerAuth: 'zone-token',
|
|
46
|
+
})
|
|
47
|
+
expect(Credential.resolveCredential({ chainId: 42431, value })).toEqual({
|
|
48
|
+
basicAuth: undefined,
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|