tapimo 0.0.0 → 0.0.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/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/ApiKey.d.ts +65 -0
- package/dist/ApiKey.d.ts.map +1 -0
- package/dist/ApiKey.js +105 -0
- package/dist/ApiKey.js.map +1 -0
- package/dist/ApiKeySource.d.ts +166 -0
- package/dist/ApiKeySource.d.ts.map +1 -0
- package/dist/ApiKeySource.js +234 -0
- package/dist/ApiKeySource.js.map +1 -0
- package/dist/App.d.ts +19317 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +612 -0
- package/dist/App.js.map +1 -0
- package/dist/Assets.d.ts +44 -0
- package/dist/Assets.d.ts.map +1 -0
- package/dist/Assets.js +23 -0
- package/dist/Assets.js.map +1 -0
- package/dist/Auth.d.ts +2 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +2 -0
- package/dist/Auth.js.map +1 -0
- package/dist/Cli.d.ts +21 -0
- package/dist/Cli.d.ts.map +1 -0
- package/dist/Cli.js +13 -0
- package/dist/Cli.js.map +1 -0
- package/dist/Client.d.ts +20 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +24 -0
- package/dist/Client.js.map +1 -0
- package/dist/Metrics.d.ts +70 -0
- package/dist/Metrics.d.ts.map +1 -0
- package/dist/Metrics.js +91 -0
- package/dist/Metrics.js.map +1 -0
- package/dist/Scope.d.ts +35 -0
- package/dist/Scope.d.ts.map +1 -0
- package/dist/Scope.js +38 -0
- package/dist/Scope.js.map +1 -0
- package/dist/Webhooks.d.ts +79 -0
- package/dist/Webhooks.d.ts.map +1 -0
- package/dist/Webhooks.js +107 -0
- package/dist/Webhooks.js.map +1 -0
- package/dist/admin/Access.d.ts +41 -0
- package/dist/admin/Access.d.ts.map +1 -0
- package/dist/admin/Access.js +75 -0
- package/dist/admin/Access.js.map +1 -0
- package/dist/admin/App.d.ts +1221 -0
- package/dist/admin/App.d.ts.map +1 -0
- package/dist/admin/App.js +113 -0
- package/dist/admin/App.js.map +1 -0
- package/dist/admin/apps/api-keys.d.ts +209 -0
- package/dist/admin/apps/api-keys.d.ts.map +1 -0
- package/dist/admin/apps/api-keys.js +129 -0
- package/dist/admin/apps/api-keys.js.map +1 -0
- package/dist/admin/apps/scopes.d.ts +46 -0
- package/dist/admin/apps/scopes.d.ts.map +1 -0
- package/dist/admin/apps/scopes.js +41 -0
- package/dist/admin/apps/scopes.js.map +1 -0
- package/dist/admin/apps/verified-tokens.d.ts +1206 -0
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -0
- package/dist/admin/apps/verified-tokens.js +485 -0
- package/dist/admin/apps/verified-tokens.js.map +1 -0
- package/dist/admin/index.d.ts +3 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/ui.generated.d.ts +11 -0
- package/dist/admin/ui.generated.d.ts.map +1 -0
- package/dist/admin/ui.generated.js +43 -0
- package/dist/admin/ui.generated.js.map +1 -0
- package/dist/apps/activities.d.ts +18725 -0
- package/dist/apps/activities.d.ts.map +1 -0
- package/dist/apps/activities.js +3138 -0
- package/dist/apps/activities.js.map +1 -0
- package/dist/apps/addresses.d.ts +3662 -0
- package/dist/apps/addresses.d.ts.map +1 -0
- package/dist/apps/addresses.js +22 -0
- package/dist/apps/addresses.js.map +1 -0
- package/dist/apps/balances.d.ts +342 -0
- package/dist/apps/balances.d.ts.map +1 -0
- package/dist/apps/balances.js +393 -0
- package/dist/apps/balances.js.map +1 -0
- package/dist/apps/blocks.d.ts +931 -0
- package/dist/apps/blocks.d.ts.map +1 -0
- package/dist/apps/blocks.js +689 -0
- package/dist/apps/blocks.js.map +1 -0
- package/dist/apps/coingecko.d.ts +1053 -0
- package/dist/apps/coingecko.d.ts.map +1 -0
- package/dist/apps/coingecko.js +1015 -0
- package/dist/apps/coingecko.js.map +1 -0
- package/dist/apps/exchanges.d.ts +3000 -0
- package/dist/apps/exchanges.d.ts.map +1 -0
- package/dist/apps/exchanges.js +3570 -0
- package/dist/apps/exchanges.js.map +1 -0
- package/dist/apps/fee-amm.d.ts +640 -0
- package/dist/apps/fee-amm.d.ts.map +1 -0
- package/dist/apps/fee-amm.js +815 -0
- package/dist/apps/fee-amm.js.map +1 -0
- package/dist/apps/indexer.d.ts +116 -0
- package/dist/apps/indexer.d.ts.map +1 -0
- package/dist/apps/indexer.js +270 -0
- package/dist/apps/indexer.js.map +1 -0
- package/dist/apps/receipts.d.ts +1438 -0
- package/dist/apps/receipts.d.ts.map +1 -0
- package/dist/apps/receipts.js +874 -0
- package/dist/apps/receipts.js.map +1 -0
- package/dist/apps/rpc.d.ts +173 -0
- package/dist/apps/rpc.d.ts.map +1 -0
- package/dist/apps/rpc.js +191 -0
- package/dist/apps/rpc.js.map +1 -0
- package/dist/apps/tokenlist.d.ts +192 -0
- package/dist/apps/tokenlist.d.ts.map +1 -0
- package/dist/apps/tokenlist.js +153 -0
- package/dist/apps/tokenlist.js.map +1 -0
- package/dist/apps/tokens.d.ts +2246 -0
- package/dist/apps/tokens.d.ts.map +1 -0
- package/dist/apps/tokens.js +1789 -0
- package/dist/apps/tokens.js.map +1 -0
- package/dist/apps/transactions.d.ts +2327 -0
- package/dist/apps/transactions.d.ts.map +1 -0
- package/dist/apps/transactions.js +975 -0
- package/dist/apps/transactions.js.map +1 -0
- package/dist/apps/transfers.d.ts +589 -0
- package/dist/apps/transfers.d.ts.map +1 -0
- package/dist/apps/transfers.js +769 -0
- package/dist/apps/transfers.js.map +1 -0
- package/dist/apps/verified-tokens.d.ts +544 -0
- package/dist/apps/verified-tokens.d.ts.map +1 -0
- package/dist/apps/verified-tokens.js +234 -0
- package/dist/apps/verified-tokens.js.map +1 -0
- package/dist/apps/webhooks.d.ts +7684 -0
- package/dist/apps/webhooks.d.ts.map +1 -0
- package/dist/apps/webhooks.js +2112 -0
- package/dist/apps/webhooks.js.map +1 -0
- package/dist/cloudflare.d.ts +32 -0
- package/dist/cloudflare.d.ts.map +1 -0
- package/dist/cloudflare.js +45 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/Auth.d.ts +298 -0
- package/dist/internal/Auth.d.ts.map +1 -0
- package/dist/internal/Auth.js +618 -0
- package/dist/internal/Auth.js.map +1 -0
- package/dist/internal/Cache.d.ts +74 -0
- package/dist/internal/Cache.d.ts.map +1 -0
- package/dist/internal/Cache.js +215 -0
- package/dist/internal/Cache.js.map +1 -0
- package/dist/internal/Cursor.d.ts +79 -0
- package/dist/internal/Cursor.d.ts.map +1 -0
- package/dist/internal/Cursor.js +116 -0
- package/dist/internal/Cursor.js.map +1 -0
- package/dist/internal/EdgeCache.d.ts +59 -0
- package/dist/internal/EdgeCache.d.ts.map +1 -0
- package/dist/internal/EdgeCache.js +174 -0
- package/dist/internal/EdgeCache.js.map +1 -0
- package/dist/internal/Log.d.ts +104 -0
- package/dist/internal/Log.d.ts.map +1 -0
- package/dist/internal/Log.js +118 -0
- package/dist/internal/Log.js.map +1 -0
- package/dist/internal/MetricSink.d.ts +65 -0
- package/dist/internal/MetricSink.d.ts.map +1 -0
- package/dist/internal/MetricSink.js +146 -0
- package/dist/internal/MetricSink.js.map +1 -0
- package/dist/internal/Mpp.d.ts +71 -0
- package/dist/internal/Mpp.d.ts.map +1 -0
- package/dist/internal/Mpp.js +105 -0
- package/dist/internal/Mpp.js.map +1 -0
- package/dist/internal/OpenApi.d.ts +313 -0
- package/dist/internal/OpenApi.d.ts.map +1 -0
- package/dist/internal/OpenApi.fonts.d.ts +2 -0
- package/dist/internal/OpenApi.fonts.d.ts.map +1 -0
- package/dist/internal/OpenApi.fonts.js +39 -0
- package/dist/internal/OpenApi.fonts.js.map +1 -0
- package/dist/internal/OpenApi.js +335 -0
- package/dist/internal/OpenApi.js.map +1 -0
- package/dist/internal/OpenApi.logo.d.ts +6 -0
- package/dist/internal/OpenApi.logo.d.ts.map +1 -0
- package/dist/internal/OpenApi.logo.js +19 -0
- package/dist/internal/OpenApi.logo.js.map +1 -0
- package/dist/internal/Path.d.ts +5 -0
- package/dist/internal/Path.d.ts.map +1 -0
- package/dist/internal/Path.js +16 -0
- package/dist/internal/Path.js.map +1 -0
- package/dist/internal/RateLimit.d.ts +60 -0
- package/dist/internal/RateLimit.d.ts.map +1 -0
- package/dist/internal/RateLimit.js +48 -0
- package/dist/internal/RateLimit.js.map +1 -0
- package/dist/internal/Response.d.ts +132 -0
- package/dist/internal/Response.d.ts.map +1 -0
- package/dist/internal/Response.js +72 -0
- package/dist/internal/Response.js.map +1 -0
- package/dist/internal/Schema.d.ts +257 -0
- package/dist/internal/Schema.d.ts.map +1 -0
- package/dist/internal/Schema.js +360 -0
- package/dist/internal/Schema.js.map +1 -0
- package/dist/internal/Store.d.ts +204 -0
- package/dist/internal/Store.d.ts.map +1 -0
- package/dist/internal/Store.js +291 -0
- package/dist/internal/Store.js.map +1 -0
- package/dist/internal/Tidx.d.ts +120 -0
- package/dist/internal/Tidx.d.ts.map +1 -0
- package/dist/internal/Tidx.js +156 -0
- package/dist/internal/Tidx.js.map +1 -0
- package/dist/internal/Timing.d.ts +22 -0
- package/dist/internal/Timing.d.ts.map +1 -0
- package/dist/internal/Timing.js +32 -0
- package/dist/internal/Timing.js.map +1 -0
- package/dist/internal/Ttl.d.ts +25 -0
- package/dist/internal/Ttl.d.ts.map +1 -0
- package/dist/internal/Ttl.js +49 -0
- package/dist/internal/Ttl.js.map +1 -0
- package/dist/internal/Value.d.ts +47 -0
- package/dist/internal/Value.d.ts.map +1 -0
- package/dist/internal/Value.js +122 -0
- package/dist/internal/Value.js.map +1 -0
- package/dist/internal/VerifiedTokens.d.ts +228 -0
- package/dist/internal/VerifiedTokens.d.ts.map +1 -0
- package/dist/internal/VerifiedTokens.js +450 -0
- package/dist/internal/VerifiedTokens.js.map +1 -0
- package/dist/internal/Viem.d.ts +2082 -0
- package/dist/internal/Viem.d.ts.map +1 -0
- package/dist/internal/Viem.js +63 -0
- package/dist/internal/Viem.js.map +1 -0
- package/dist/internal/WebhookDestination.d.ts +198 -0
- package/dist/internal/WebhookDestination.d.ts.map +1 -0
- package/dist/internal/WebhookDestination.js +170 -0
- package/dist/internal/WebhookDestination.js.map +1 -0
- package/dist/internal/Webhooks.d.ts +433 -0
- package/dist/internal/Webhooks.d.ts.map +1 -0
- package/dist/internal/Webhooks.js +489 -0
- package/dist/internal/Webhooks.js.map +1 -0
- package/dist/internal/webhookDestinations/betterStack.d.ts +26 -0
- package/dist/internal/webhookDestinations/betterStack.d.ts.map +1 -0
- package/dist/internal/webhookDestinations/betterStack.js +76 -0
- package/dist/internal/webhookDestinations/betterStack.js.map +1 -0
- package/dist/internal/webhookDestinations/slack.d.ts +59 -0
- package/dist/internal/webhookDestinations/slack.d.ts.map +1 -0
- package/dist/internal/webhookDestinations/slack.js +422 -0
- package/dist/internal/webhookDestinations/slack.js.map +1 -0
- package/dist/internal/webhookDestinations/url.d.ts +17 -0
- package/dist/internal/webhookDestinations/url.d.ts.map +1 -0
- package/dist/internal/webhookDestinations/url.js +130 -0
- package/dist/internal/webhookDestinations/url.js.map +1 -0
- package/dist/openrpc.json +5302 -0
- package/package.json +46 -4
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +1 -0
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
- package/seeds/31318/verified-tokens.json +30 -0
- package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
- package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +4 -0
- package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +30 -0
- package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +11 -0
- package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +1 -0
- package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
- package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
- package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +5 -0
- package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +1 -0
- package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +1 -0
- package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
- package/seeds/4217/verified-tokens.json +177 -0
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
- package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +1 -0
- package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +1 -0
- package/seeds/42431/verified-tokens.json +44 -0
- package/seeds/openrpc/README.md +27 -0
- package/seeds/openrpc/execution-apis.json +8989 -0
- package/src/ApiKey.test.ts +91 -0
- package/src/ApiKey.ts +122 -0
- package/src/ApiKeySource.test-d.ts +11 -0
- package/src/ApiKeySource.test.ts +295 -0
- package/src/ApiKeySource.ts +303 -0
- package/src/App.test-d.ts +38 -0
- package/src/App.test.ts +65927 -0
- package/src/App.ts +855 -0
- package/src/Assets.ts +58 -0
- package/src/Auth.ts +1 -0
- package/src/Cli.test.ts +81 -0
- package/src/Cli.ts +38 -0
- package/src/Client.test-d.ts +1438 -0
- package/src/Client.test.ts +134 -0
- package/src/Client.ts +45 -0
- package/src/Metrics.ts +154 -0
- package/src/Scope.ts +50 -0
- package/src/Webhooks.test.ts +49 -0
- package/src/Webhooks.ts +172 -0
- package/src/admin/Access.test.ts +130 -0
- package/src/admin/Access.ts +87 -0
- package/src/admin/App.test.ts +225 -0
- package/src/admin/App.ts +216 -0
- package/src/admin/apps/api-keys.test.ts +156 -0
- package/src/admin/apps/api-keys.ts +157 -0
- package/src/admin/apps/scopes.test.ts +52 -0
- package/src/admin/apps/scopes.ts +47 -0
- package/src/admin/apps/verified-tokens.test.ts +415 -0
- package/src/admin/apps/verified-tokens.ts +566 -0
- package/src/admin/index.ts +2 -0
- package/src/admin/ui/plugin.ts +135 -0
- package/src/admin/ui/src/components/Checkbox.tsx +22 -0
- package/src/admin/ui/src/components/Dialog.tsx +32 -0
- package/src/admin/ui/src/components/MobileProfile.tsx +31 -0
- package/src/admin/ui/src/components/Page.tsx +53 -0
- package/src/admin/ui/src/components/TempoLogo.tsx +37 -0
- package/src/admin/ui/src/fonts/Pilat-Demi.woff2 +0 -0
- package/src/admin/ui/src/fonts/Pilat-Regular.woff2 +0 -0
- package/src/admin/ui/src/lib/api-keys.ts +63 -0
- package/src/admin/ui/src/lib/client.ts +15 -0
- package/src/admin/ui/src/lib/config.ts +57 -0
- package/src/admin/ui/src/lib/query-client.ts +26 -0
- package/src/admin/ui/src/lib/scopes.ts +25 -0
- package/src/admin/ui/src/lib/verified-tokens.ts +89 -0
- package/src/admin/ui/src/lib/wagmi.ts +18 -0
- package/src/admin/ui/src/routeTree.gen.ts +104 -0
- package/src/admin/ui/src/router.tsx +25 -0
- package/src/admin/ui/src/routes/__root.tsx +219 -0
- package/src/admin/ui/src/routes/api-keys.tsx +329 -0
- package/src/admin/ui/src/routes/index.tsx +7 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +331 -0
- package/src/admin/ui/src/styles.css +20 -0
- package/src/admin/ui/tsconfig.json +16 -0
- package/src/admin/ui/vite.config.ts +29 -0
- package/src/admin/ui.generated.ts +60 -0
- package/src/apps/activities.test.ts +1020 -0
- package/src/apps/activities.ts +3934 -0
- package/src/apps/addresses.ts +24 -0
- package/src/apps/balances.test.ts +274 -0
- package/src/apps/balances.ts +533 -0
- package/src/apps/blocks.test.ts +385 -0
- package/src/apps/blocks.ts +896 -0
- package/src/apps/coingecko.test.ts +218 -0
- package/src/apps/coingecko.ts +1383 -0
- package/src/apps/exchanges.test.ts +958 -0
- package/src/apps/exchanges.ts +4773 -0
- package/src/apps/fee-amm.test.ts +321 -0
- package/src/apps/fee-amm.ts +1121 -0
- package/src/apps/indexer.test.ts +153 -0
- package/src/apps/indexer.ts +330 -0
- package/src/apps/receipts.test.ts +285 -0
- package/src/apps/receipts.ts +1193 -0
- package/src/apps/rpc.test.ts +302 -0
- package/src/apps/rpc.ts +222 -0
- package/src/apps/tokenlist.test.ts +80 -0
- package/src/apps/tokenlist.ts +207 -0
- package/src/apps/tokens.test.ts +1062 -0
- package/src/apps/tokens.ts +2292 -0
- package/src/apps/transactions.test.ts +408 -0
- package/src/apps/transactions.ts +1363 -0
- package/src/apps/transfers.test.ts +371 -0
- package/src/apps/transfers.ts +1116 -0
- package/src/apps/verified-tokens.test.ts +114 -0
- package/src/apps/verified-tokens.ts +295 -0
- package/src/apps/webhooks.test.ts +1937 -0
- package/src/apps/webhooks.ts +2926 -0
- package/src/cloudflare.ts +55 -0
- package/src/index.ts +15 -0
- package/src/internal/Auth.test.ts +980 -0
- package/src/internal/Auth.ts +1012 -0
- package/src/internal/Cache.test.ts +240 -0
- package/src/internal/Cache.ts +262 -0
- package/src/internal/Cursor.test.ts +100 -0
- package/src/internal/Cursor.ts +149 -0
- package/src/internal/EdgeCache.test.ts +234 -0
- package/src/internal/EdgeCache.ts +224 -0
- package/src/internal/Errors.ts +14 -0
- package/src/internal/Log.test.ts +244 -0
- package/src/internal/Log.ts +216 -0
- package/src/internal/MetricSink.ts +220 -0
- package/src/internal/Mpp.test.ts +64 -0
- package/src/internal/Mpp.ts +141 -0
- package/src/internal/OpenApi.fonts.ts +38 -0
- package/src/internal/OpenApi.logo.ts +18 -0
- package/src/internal/OpenApi.ts +488 -0
- package/src/internal/Path.test.ts +14 -0
- package/src/internal/Path.ts +15 -0
- package/src/internal/RateLimit.test.ts +93 -0
- package/src/internal/RateLimit.ts +93 -0
- package/src/internal/Response.ts +131 -0
- package/src/internal/Schema.test.ts +34 -0
- package/src/internal/Schema.ts +523 -0
- package/src/internal/Store.test.ts +545 -0
- package/src/internal/Store.ts +526 -0
- package/src/internal/Tidx.local.test.ts +33 -0
- package/src/internal/Tidx.test.ts +294 -0
- package/src/internal/Tidx.ts +238 -0
- package/src/internal/Timing.test.ts +22 -0
- package/src/internal/Timing.ts +62 -0
- package/src/internal/Ttl.test.ts +18 -0
- package/src/internal/Ttl.ts +59 -0
- package/src/internal/Value.ts +114 -0
- package/src/internal/VerifiedTokens.test.ts +333 -0
- package/src/internal/VerifiedTokens.ts +645 -0
- package/src/internal/Viem.test.ts +115 -0
- package/src/internal/Viem.ts +165 -0
- package/src/internal/WebhookDestination.test.ts +648 -0
- package/src/internal/WebhookDestination.ts +331 -0
- package/src/internal/Webhooks.test.ts +668 -0
- package/src/internal/Webhooks.ts +940 -0
- package/src/internal/webhookDestinations/betterStack.ts +91 -0
- package/src/internal/webhookDestinations/slack.ts +496 -0
- package/src/internal/webhookDestinations/url.ts +128 -0
- package/src/openrpc.json +5302 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Tempo API wordmark logos for the docs header, theme-aware. `dark` (white
|
|
2
|
+
// text) renders in dark mode, `light` (black text) in light mode. Inlined as
|
|
3
|
+
// SVG data URIs so the standalone reference needs no external asset hosting.
|
|
4
|
+
//
|
|
5
|
+
// THIS FILE IS GENERATED (extracted from the Website 2.0 assets).
|
|
6
|
+
const dark = `<svg width="626" height="181" viewBox="0 0 626 181" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M45.4158 136H18.9697L43.4807 61.1767H12.1324L18.9697 39.2458H106.306L99.4692 61.1767H69.7979L45.4158 136ZM143.83 136H81.1333L112.611 39.2458H175.049L169.115 57.6936H132.865L126.285 78.4635H161.375L155.44 96.6533H120.222L113.643 117.552H149.635L143.83 136ZM172.207 136H151.179L182.786 39.2458H217.875L216.714 91.4931L250.901 39.2458H289.344L257.867 136H231.55L252.449 70.9812H252.062L209.103 136H193.493L194.138 70.2071H193.88L172.207 136ZM318.946 57.1776L308.755 88.3969H311.593C318.043 88.3969 323.418 86.8919 327.718 83.8817C332.019 80.7856 334.814 76.3994 336.104 70.7231C337.222 65.8209 336.62 62.3378 334.298 60.2737C331.976 58.2096 328.105 57.1776 322.687 57.1776H318.946ZM293.403 136H266.957L298.434 39.2458H330.557C337.953 39.2458 344.317 40.4498 349.649 42.8579C355.068 45.18 359.024 48.5342 361.518 52.9204C364.098 57.2206 364.958 62.2518 364.098 68.014C362.98 75.5824 360.056 82.2477 355.326 88.0099C350.595 93.7722 344.446 98.2444 336.878 101.426C329.396 104.523 321.01 106.071 311.722 106.071H303.078L293.403 136ZM427.133 129.808C418.361 134.968 409.03 137.548 399.139 137.548H398.881C390.109 137.548 382.712 135.613 376.692 131.743C370.758 127.787 366.501 122.454 363.921 115.746C361.427 109.038 360.825 101.685 362.115 93.6862C363.749 83.6237 367.49 74.3353 373.338 65.8209C379.186 57.3066 386.497 50.5123 395.269 45.438C404.041 40.3638 413.416 37.8267 423.392 37.8267H423.65C432.767 37.8267 440.292 39.7618 446.226 43.632C452.247 47.5021 456.418 52.7914 458.74 59.4997C461.148 66.1219 461.664 73.5613 460.288 81.8176C458.654 91.5361 454.913 100.695 449.064 109.296C443.216 117.81 435.906 124.648 427.133 129.808ZM390.625 113.166C392.947 117.552 396.989 119.745 402.751 119.745H403.009C407.74 119.745 412.126 117.982 416.168 114.456C420.296 110.844 423.779 106.028 426.617 100.007C429.542 93.9872 431.692 87.2789 433.068 79.8825C434.358 72.6582 433.842 66.853 431.52 62.4668C429.198 57.9946 425.198 55.7585 419.522 55.7585H419.264C414.878 55.7585 410.621 57.5646 406.493 61.1767C402.45 64.7889 398.924 69.6481 395.914 75.7544C392.904 81.8606 390.711 88.4829 389.335 95.6212C387.959 102.846 388.389 108.694 390.625 113.166Z" fill="white"/>
|
|
8
|
+
<rect x="498" y="51" width="128" height="78" fill="#2B2B2B"/>
|
|
9
|
+
<path d="M509.595 111L522.555 68.4H529.515L542.475 111H536.955L526.035 73.08L515.115 111H509.595ZM516.135 98.88L517.935 93.84H534.135L535.935 98.88H516.135ZM549.412 111V68.4H562.372C565.332 68.4 567.912 68.92 570.112 69.96C572.312 71 574.012 72.5 575.212 74.46C576.412 76.38 577.012 78.7 577.012 81.42C577.012 84.14 576.412 86.48 575.212 88.44C574.012 90.36 572.312 91.84 570.112 92.88C567.912 93.92 565.332 94.44 562.372 94.44H554.572V111H549.412ZM554.572 89.4H561.772C565.132 89.4 567.612 88.72 569.212 87.36C570.812 85.96 571.612 83.98 571.612 81.42C571.612 78.82 570.812 76.84 569.212 75.48C567.612 74.12 565.132 73.44 561.772 73.44H554.572V89.4ZM584.788 111V105.96H595.408V73.44H584.788V68.4H611.188V73.44H600.568V105.96H611.188V111H584.788Z" fill="#B2B2B2"/>
|
|
10
|
+
</svg>`
|
|
11
|
+
const light = `<svg width="626" height="181" viewBox="0 0 626 181" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
12
|
+
<path d="M45.4158 136H18.9697L43.4807 61.1767H12.1324L18.9697 39.2458H106.306L99.4692 61.1767H69.7979L45.4158 136ZM143.83 136H81.1333L112.611 39.2458H175.049L169.115 57.6936H132.865L126.285 78.4635H161.375L155.44 96.6533H120.222L113.643 117.552H149.635L143.83 136ZM172.207 136H151.179L182.786 39.2458H217.875L216.714 91.4931L250.901 39.2458H289.344L257.867 136H231.55L252.449 70.9812H252.062L209.103 136H193.493L194.138 70.2071H193.88L172.207 136ZM318.946 57.1776L308.755 88.3969H311.593C318.043 88.3969 323.418 86.8919 327.718 83.8817C332.019 80.7856 334.814 76.3994 336.104 70.7231C337.222 65.8209 336.62 62.3378 334.298 60.2737C331.976 58.2096 328.105 57.1776 322.687 57.1776H318.946ZM293.403 136H266.957L298.434 39.2458H330.557C337.953 39.2458 344.317 40.4498 349.649 42.8579C355.068 45.18 359.024 48.5342 361.518 52.9204C364.098 57.2206 364.958 62.2518 364.098 68.014C362.98 75.5824 360.056 82.2477 355.326 88.0099C350.595 93.7722 344.446 98.2444 336.878 101.426C329.396 104.523 321.01 106.071 311.722 106.071H303.078L293.403 136ZM427.133 129.808C418.361 134.968 409.03 137.548 399.139 137.548H398.881C390.109 137.548 382.712 135.613 376.692 131.743C370.758 127.787 366.501 122.454 363.921 115.746C361.427 109.038 360.825 101.685 362.115 93.6862C363.749 83.6237 367.49 74.3353 373.338 65.8209C379.186 57.3066 386.497 50.5123 395.269 45.438C404.041 40.3638 413.416 37.8267 423.392 37.8267H423.65C432.767 37.8267 440.292 39.7618 446.226 43.632C452.247 47.5021 456.418 52.7914 458.74 59.4997C461.148 66.1219 461.664 73.5613 460.288 81.8176C458.654 91.5361 454.913 100.695 449.064 109.296C443.216 117.81 435.906 124.648 427.133 129.808ZM390.625 113.166C392.947 117.552 396.989 119.745 402.751 119.745H403.009C407.74 119.745 412.126 117.982 416.168 114.456C420.296 110.844 423.779 106.028 426.617 100.007C429.542 93.9872 431.692 87.2789 433.068 79.8825C434.358 72.6582 433.842 66.853 431.52 62.4668C429.198 57.9946 425.198 55.7585 419.522 55.7585H419.264C414.878 55.7585 410.621 57.5646 406.493 61.1767C402.45 64.7889 398.924 69.6481 395.914 75.7544C392.904 81.8606 390.711 88.4829 389.335 95.6212C387.959 102.846 388.389 108.694 390.625 113.166Z" fill="black"/>
|
|
13
|
+
<rect x="498" y="51" width="128" height="78" fill="#EDEDED"/>
|
|
14
|
+
<path d="M509.595 111L522.555 68.4H529.515L542.475 111H536.955L526.035 73.08L515.115 111H509.595ZM516.135 98.88L517.935 93.84H534.135L535.935 98.88H516.135ZM549.412 111V68.4H562.372C565.332 68.4 567.912 68.92 570.112 69.96C572.312 71 574.012 72.5 575.212 74.46C576.412 76.38 577.012 78.7 577.012 81.42C577.012 84.14 576.412 86.48 575.212 88.44C574.012 90.36 572.312 91.84 570.112 92.88C567.912 93.92 565.332 94.44 562.372 94.44H554.572V111H549.412ZM554.572 89.4H561.772C565.132 89.4 567.612 88.72 569.212 87.36C570.812 85.96 571.612 83.98 571.612 81.42C571.612 78.82 570.812 76.84 569.212 75.48C567.612 74.12 565.132 73.44 561.772 73.44H554.572V89.4ZM584.788 111V105.96H595.408V73.44H584.788V68.4H611.188V73.44H600.568V105.96H611.188V111H584.788Z" fill="#707070"/>
|
|
15
|
+
</svg>`
|
|
16
|
+
const dataUri = (svg: string) => `data:image/svg+xml,${encodeURIComponent(svg)}`
|
|
17
|
+
/** Theme-aware Tempo API wordmark for the docs header (`vocs.logoUrl`). */
|
|
18
|
+
export const logoUrl = { dark: dataUri(dark), light: dataUri(light) }
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import type { Context, Env, MiddlewareHandler, ValidationTargets } from 'hono'
|
|
2
|
+
import type { HasRequiredKeys } from 'hono/utils/types'
|
|
3
|
+
import { resolver, type ResponsesWithResolver, validator } from 'hono-openapi'
|
|
4
|
+
import * as z from 'zod/mini'
|
|
5
|
+
import { pilatFontFaces } from './OpenApi.fonts.js'
|
|
6
|
+
import * as Response from './Response.js'
|
|
7
|
+
import * as Schema from './Schema.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `toJSONSchema` override that re-applies `examples` zod strips from
|
|
11
|
+
* pipe/default schemas in `io: 'input'` mode. zod intentionally drops
|
|
12
|
+
* `examples` (and `default`) from the input JSON Schema of a `ZodPipe`
|
|
13
|
+
* (e.g. `chainId`, `include`, boolean queries) and a `ZodDefault`, so an
|
|
14
|
+
* `examples` attached via `z.meta(...)` on those wrappers never reaches the
|
|
15
|
+
* generated parameter. This override runs after conversion and copies the
|
|
16
|
+
* registered `examples` back onto the node's JSON Schema, so every parameter
|
|
17
|
+
* surfaces its example regardless of the underlying schema shape.
|
|
18
|
+
*/
|
|
19
|
+
function recoverExamples(ctx: { jsonSchema: { examples?: unknown }; zodSchema: unknown }) {
|
|
20
|
+
if (ctx.jsonSchema.examples !== undefined) return
|
|
21
|
+
const meta = z.globalRegistry.get(ctx.zodSchema as never) as { examples?: unknown } | undefined
|
|
22
|
+
if (meta?.examples === undefined) return
|
|
23
|
+
ctx.jsonSchema.examples = Array.isArray(meta.examples)
|
|
24
|
+
? meta.examples
|
|
25
|
+
: Object.values(meta.examples as Record<string, { value: unknown }>).map((e) => e.value)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Shared zod→JSON-Schema conversion options applied to every parameter and
|
|
30
|
+
* response schema. {@link recoverExamples} re-attaches `examples` that zod
|
|
31
|
+
* strips from pipe/default schemas (e.g. `Schema.Hex`, `Schema.Quantity`), so a
|
|
32
|
+
* field's `z.meta({ examples })` survives even on a branded pipe output — no
|
|
33
|
+
* per-field non-pipe schema is needed. Supplying our own `override` opts out of
|
|
34
|
+
* hono-openapi's default zod date override, so re-add its `unrepresentable:
|
|
35
|
+
* 'any'` to keep transform/pipe nodes (which have no JSON-Schema form) emitting
|
|
36
|
+
* `{}` instead of throwing.
|
|
37
|
+
*/
|
|
38
|
+
const schemaOptions = { options: { override: recoverExamples, unrepresentable: 'any' } } as const
|
|
39
|
+
|
|
40
|
+
// Re-export the upstream `hono-openapi` API surface used by the app so all
|
|
41
|
+
// callers go through this local `OpenApi` module. Forwarded as direct named
|
|
42
|
+
// re-exports because `uniqueSymbol` is a `unique symbol` whose identity is
|
|
43
|
+
// lost when copied through a `const` declaration.
|
|
44
|
+
export {
|
|
45
|
+
describeRoute,
|
|
46
|
+
type HandlerUniqueProperty,
|
|
47
|
+
resolver,
|
|
48
|
+
type ResponsesWithResolver,
|
|
49
|
+
uniqueSymbol,
|
|
50
|
+
validator,
|
|
51
|
+
} from 'hono-openapi'
|
|
52
|
+
|
|
53
|
+
// Theme-aware Tempo API wordmark for the docs header (`vocs.logoUrl`), inlined
|
|
54
|
+
// as SVG data URIs. See {@link file://./OpenApi.logo.ts}.
|
|
55
|
+
export { logoUrl } from './OpenApi.logo.js'
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Custom CSS injected into the standalone reference's shell `<head>` (via
|
|
59
|
+
* `Handler.openApi(_, { css })`), after the Vocs design-system styles so it
|
|
60
|
+
* overrides them:
|
|
61
|
+
*
|
|
62
|
+
* - Page/surface backgrounds use Tempo's near-black dark palette and pure-white
|
|
63
|
+
* light palette via `light-dark(<light>, <dark>)`.
|
|
64
|
+
* - The dark border color is darkened (the light theme keeps its default).
|
|
65
|
+
* - Every corner is squared. The universal `!important` rule beats hard-coded
|
|
66
|
+
* `border-radius` values and inline styles (e.g. the Scalar playground), which
|
|
67
|
+
* overriding the radius scale variables alone would miss.
|
|
68
|
+
* - The default sans/body font is Pilat (Vocs reads `--vocs-font-family`); the
|
|
69
|
+
* webfont is embedded via {@link pilatFontFaces}. Body stays at the default
|
|
70
|
+
* weight (400); headings are pinned to 500, which renders Pilat Demi (the
|
|
71
|
+
* family has no 500 cut, so Demi covers the 500-600 range — see
|
|
72
|
+
* {@link pilatFontFaces}).
|
|
73
|
+
*/
|
|
74
|
+
export const css = `${pilatFontFaces}
|
|
75
|
+
|
|
76
|
+
:root {
|
|
77
|
+
--vocs-font-family: "Pilat", Arial, Helvetica, sans-serif;
|
|
78
|
+
--vocs-background-color-primary: light-dark(#fafafa, #0a0a0a);
|
|
79
|
+
--vocs-background-color-surface: light-dark(#fff, #121212);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
:is(h1, h2, h3, h4, h5, h6)[data-v] {
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Nudge the header logo a touch larger than the default max-h-7 (1.75rem). */
|
|
87
|
+
[data-v-logo-image] {
|
|
88
|
+
max-height: 2rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Sidebar leaf items render Regular (the nav's 450 default otherwise resolves to
|
|
92
|
+
* Demi via the 500-600 range). Group labels ([data-v-sidebar-section-header])
|
|
93
|
+
* keep their heavier weight. */
|
|
94
|
+
[data-v-sidebar-item] {
|
|
95
|
+
font-weight: 400;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
[data-vocs-theme='dark'] {
|
|
99
|
+
--vocs-color-gray4: oklch(20% 0 0);
|
|
100
|
+
--vocs-color-gray5: oklch(0.23 0 0);
|
|
101
|
+
--vocs-border-color-primary: oklch(0.25 0 0);
|
|
102
|
+
--vocs-border-color-secondary: oklch(0.25 0 0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
*,
|
|
106
|
+
*::before,
|
|
107
|
+
*::after {
|
|
108
|
+
border-radius: 0 !important;
|
|
109
|
+
}`
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Standard machine-readable `error.code` values per status, shared API-wide.
|
|
113
|
+
* The reference enumerates `error.code` to these so generated clients narrow it
|
|
114
|
+
* to a literal union instead of an open `string`. 400 and 404 vary per
|
|
115
|
+
* operation; the values here are the API-wide supersets, narrowable per route
|
|
116
|
+
* via the `codes` override in {@link responses.Options}.
|
|
117
|
+
*/
|
|
118
|
+
export const errorCodes = {
|
|
119
|
+
400: [
|
|
120
|
+
'query_invalid',
|
|
121
|
+
'param_invalid',
|
|
122
|
+
'body_invalid',
|
|
123
|
+
'address_invalid',
|
|
124
|
+
'token_invalid',
|
|
125
|
+
'symbol_invalid',
|
|
126
|
+
'pair_invalid',
|
|
127
|
+
'pair_id_invalid',
|
|
128
|
+
'transaction_invalid',
|
|
129
|
+
'order_invalid',
|
|
130
|
+
'block_invalid',
|
|
131
|
+
'chain_id_invalid',
|
|
132
|
+
'chain_id_unsupported',
|
|
133
|
+
'url_invalid',
|
|
134
|
+
'api_key_malformed',
|
|
135
|
+
],
|
|
136
|
+
401: ['api_key_missing', 'api_key_invalid', 'unauthorized'],
|
|
137
|
+
403: ['api_key_forbidden', 'limit_exceeded'],
|
|
138
|
+
404: [
|
|
139
|
+
'not_found',
|
|
140
|
+
'token_not_found',
|
|
141
|
+
'token_logo_not_found',
|
|
142
|
+
'block_not_found',
|
|
143
|
+
'transaction_not_found',
|
|
144
|
+
'receipt_not_found',
|
|
145
|
+
'order_not_found',
|
|
146
|
+
'pair_not_found',
|
|
147
|
+
'verified_token_not_found',
|
|
148
|
+
'webhook_not_found',
|
|
149
|
+
'delivery_not_found',
|
|
150
|
+
'webhooks_not_enabled',
|
|
151
|
+
],
|
|
152
|
+
429: ['rate_limit_exceeded', 'payment_required'],
|
|
153
|
+
500: ['internal_error'],
|
|
154
|
+
502: ['upstream_error'],
|
|
155
|
+
} as const satisfies Record<number, readonly [string, ...string[]]>
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Reusable response-header definitions, registered under `components.headers`
|
|
159
|
+
* (see `App.ts`) and `$ref`-erenced from 200/429 responses. The rate-limit
|
|
160
|
+
* headers reflect the quota the request consumed; they are absent on edge-cache
|
|
161
|
+
* hits (served before metering) and on `402` payment challenges (owned by mppx,
|
|
162
|
+
* which sets `WWW-Authenticate`/`Payment-Receipt` instead).
|
|
163
|
+
*/
|
|
164
|
+
export const headerComponents = {
|
|
165
|
+
RateLimitLimit: {
|
|
166
|
+
description: 'How many requests you may make in the current time window. Not sent on cached responses or `402` payment challenges.', // prettier-ignore
|
|
167
|
+
schema: { type: 'integer' },
|
|
168
|
+
},
|
|
169
|
+
RateLimitRemaining: {
|
|
170
|
+
description: 'How many requests you have left in the current window before you are rate-limited. Not sent on cached responses or `402` payment challenges.', // prettier-ignore
|
|
171
|
+
schema: { type: 'integer' },
|
|
172
|
+
},
|
|
173
|
+
RateLimitReset: {
|
|
174
|
+
description: 'When the current window resets, as a Unix timestamp in seconds. Not sent on cached responses or `402` payment challenges.', // prettier-ignore
|
|
175
|
+
schema: { type: 'integer' },
|
|
176
|
+
},
|
|
177
|
+
RateLimitScope: {
|
|
178
|
+
description: 'Which quota this request counted against (e.g. `data:read`). Not sent on cached responses or `402` payment challenges.', // prettier-ignore
|
|
179
|
+
schema: { type: 'string' },
|
|
180
|
+
},
|
|
181
|
+
RetryAfter: {
|
|
182
|
+
description:
|
|
183
|
+
'How many seconds to wait before trying again. Sent with `429` (rate-limited) responses.',
|
|
184
|
+
schema: { type: 'integer' },
|
|
185
|
+
},
|
|
186
|
+
TempoRequestId: {
|
|
187
|
+
description: 'A unique id for this request, returned on every response (and as `requestId` in error bodies). Include it when contacting support so we can find your request.', // prettier-ignore
|
|
188
|
+
schema: { type: 'string' },
|
|
189
|
+
},
|
|
190
|
+
WwwAuthenticate: {
|
|
191
|
+
description: 'On a `402` response, the payment challenge to satisfy. Use it to build the `Authorization: Payment` credential and retry the request.', // prettier-ignore
|
|
192
|
+
schema: { type: 'string' },
|
|
193
|
+
},
|
|
194
|
+
} as const
|
|
195
|
+
|
|
196
|
+
const headerRef = (name: keyof typeof headerComponents) => ({
|
|
197
|
+
$ref: `#/components/headers/${name}`,
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
/** Response headers attached to metered success (2xx) responses. */
|
|
201
|
+
export const successHeaders = {
|
|
202
|
+
'RateLimit-Limit': headerRef('RateLimitLimit'),
|
|
203
|
+
'RateLimit-Remaining': headerRef('RateLimitRemaining'),
|
|
204
|
+
'RateLimit-Reset': headerRef('RateLimitReset'),
|
|
205
|
+
'RateLimit-Scope': headerRef('RateLimitScope'),
|
|
206
|
+
'tempo-request-id': headerRef('TempoRequestId'),
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Response headers attached to `429` rate-limit responses. */
|
|
210
|
+
export const rateLimitHeaders = {
|
|
211
|
+
...successHeaders,
|
|
212
|
+
'Retry-After': headerRef('RetryAfter'),
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Representative `requestId` used in error-body examples. */
|
|
216
|
+
const exampleRequestId = '0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9'
|
|
217
|
+
|
|
218
|
+
/** Builds the `application/json` content for a standard error response: the enumerated-code envelope plus an example body. */
|
|
219
|
+
function errorContent(codes: readonly [string, ...string[]] | undefined, message: string) {
|
|
220
|
+
return {
|
|
221
|
+
'application/json': {
|
|
222
|
+
schema: resolver(Schema.errorResponse(codes), schemaOptions),
|
|
223
|
+
example: { error: { code: codes?.[0] ?? 'error', message }, requestId: exampleRequestId },
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* `402` payment-challenge response, injected per operation for MPP-enabled
|
|
230
|
+
* routes during spec generation (see `App.create`). The challenge is
|
|
231
|
+
* protocol-native (owned by mppx) rather than the JSON error envelope, so it
|
|
232
|
+
* declares no JSON body — only the `WWW-Authenticate` header.
|
|
233
|
+
*/
|
|
234
|
+
export const paymentChallenge = {
|
|
235
|
+
description:
|
|
236
|
+
'Payment required. This endpoint accepts MPP payment, and the request either exceeded free quota or needs a paid request credential. The challenge is protocol-native (handled by mppx), not the JSON error envelope: read the `WWW-Authenticate` header and retry with `Authorization: Payment <credential>`. A successful paid response carries `Payment-Receipt`.',
|
|
237
|
+
headers: { 'WWW-Authenticate': headerRef('WwwAuthenticate') },
|
|
238
|
+
} as const
|
|
239
|
+
|
|
240
|
+
/** Shared `429` rate-limit response, registered as `components.responses.RateLimited`. */
|
|
241
|
+
const rateLimitedResponse = {
|
|
242
|
+
content: errorContent(errorCodes[429], 'Rate limit exceeded.'),
|
|
243
|
+
description:
|
|
244
|
+
'Rate limit exceeded. On endpoints that accept MPP, over-quota unpaid requests return `402 Payment Required` instead.',
|
|
245
|
+
headers: { ...rateLimitHeaders },
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Shared `500` internal-error response, registered as `components.responses.InternalError`. */
|
|
249
|
+
const serverErrorResponse = {
|
|
250
|
+
content: errorContent(errorCodes[500], 'Internal server error.'),
|
|
251
|
+
description: 'Internal server error.',
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Reusable responses registered under `components.responses` (see `App.create`)
|
|
256
|
+
* and `$ref`-erenced from operations, so the uniform `402`/`429`/`500` responses
|
|
257
|
+
* are defined once instead of inlined on every operation.
|
|
258
|
+
*/
|
|
259
|
+
export const responseComponents: ResponsesWithResolver = {
|
|
260
|
+
InternalError: serverErrorResponse,
|
|
261
|
+
PaymentRequired: paymentChallenge,
|
|
262
|
+
RateLimited: rateLimitedResponse,
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const responseRef = (name: keyof typeof responseComponents) => ({
|
|
266
|
+
$ref: `#/components/responses/${name}`,
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
/** `$ref` to the shared `402` payment-challenge response. */
|
|
270
|
+
export const paymentChallengeRef = responseRef('PaymentRequired')
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Builds a single standard JSON error response with `error.code` enumerated for
|
|
274
|
+
* the status. For routes whose custom `responses` map can't go through
|
|
275
|
+
* {@link responses} — non-JSON success bodies (e.g. image, SSE) or proxy routes
|
|
276
|
+
* with upstream-shaped error bodies. `429`/`500` resolve to the shared
|
|
277
|
+
* `components.responses` entries.
|
|
278
|
+
*/
|
|
279
|
+
export function standardError(
|
|
280
|
+
status: keyof typeof errorCodes,
|
|
281
|
+
description: string,
|
|
282
|
+
codes?: readonly [string, ...string[]],
|
|
283
|
+
): ResponsesWithResolver[string] {
|
|
284
|
+
if (status === 429) return responseRef('RateLimited')
|
|
285
|
+
if (status === 500) return responseRef('InternalError')
|
|
286
|
+
return { content: errorContent(codes ?? errorCodes[status], description), description }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Builds an OpenAPI `responses` map with the API's standard error responses
|
|
291
|
+
* pre-filled, plus the success response (with rate-limit headers):
|
|
292
|
+
*
|
|
293
|
+
* - `400` invalid request, `401` missing/invalid key, `429` rate limited,
|
|
294
|
+
* `500` internal error, and `502` upstream failure on every operation;
|
|
295
|
+
* - `403`/`404`/`409`/`412`/`413`/`415` only when an `errors` entry is set.
|
|
296
|
+
*
|
|
297
|
+
* `error.code` is enumerated per status from {@link errorCodes}; narrow 400/404
|
|
298
|
+
* to a route's exact codes by passing `{ description, codes }` for that status.
|
|
299
|
+
* `429`/`500` `$ref` the shared {@link responseComponents}. `402` is not emitted
|
|
300
|
+
* here — it is injected per operation from the route's MPP policy during spec
|
|
301
|
+
* generation (see `App.ts`).
|
|
302
|
+
*/
|
|
303
|
+
export function responses<schema extends z.ZodMiniType>(
|
|
304
|
+
options: responses.Options<schema>,
|
|
305
|
+
): ResponsesWithResolver {
|
|
306
|
+
const { errors, success } = options
|
|
307
|
+
const error = (status: number, fallback: string) => {
|
|
308
|
+
const override = errors?.[status as 400]
|
|
309
|
+
const description =
|
|
310
|
+
typeof override === 'string' ? override : (override?.description ?? fallback)
|
|
311
|
+
const codes =
|
|
312
|
+
(typeof override === 'object' ? override.codes : undefined) ??
|
|
313
|
+
errorCodes[status as keyof typeof errorCodes]
|
|
314
|
+
return { content: errorContent(codes, description), description }
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
200: {
|
|
318
|
+
content: {
|
|
319
|
+
'application/json': {
|
|
320
|
+
schema: resolver(success.schema, schemaOptions),
|
|
321
|
+
...(success.example === undefined ? {} : { example: success.example }),
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
description: success.description,
|
|
325
|
+
headers: { ...successHeaders },
|
|
326
|
+
},
|
|
327
|
+
400: error(400, 'Invalid request.'),
|
|
328
|
+
401: error(401, 'Missing or invalid API key.'),
|
|
329
|
+
...(errors?.[403] && { 403: error(403, 'Forbidden.') }),
|
|
330
|
+
...(errors?.[404] && { 404: error(404, 'Not found.') }),
|
|
331
|
+
...(errors?.[409] && { 409: error(409, 'Conflict.') }),
|
|
332
|
+
...(errors?.[412] && { 412: error(412, 'Precondition failed.') }),
|
|
333
|
+
...(errors?.[413] && { 413: error(413, 'Payload too large.') }),
|
|
334
|
+
...(errors?.[415] && { 415: error(415, 'Unsupported media type.') }),
|
|
335
|
+
429: responseRef('RateLimited'),
|
|
336
|
+
500: responseRef('InternalError'),
|
|
337
|
+
502: error(502, 'Upstream data failure.'),
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export declare namespace responses {
|
|
342
|
+
/**
|
|
343
|
+
* Override for a standard error response: a description string, or an object
|
|
344
|
+
* adding the exact `codes` that status can return (narrowing the enum).
|
|
345
|
+
*/
|
|
346
|
+
type ErrorOverride =
|
|
347
|
+
| string
|
|
348
|
+
| {
|
|
349
|
+
/** Human-readable description of the error response. */
|
|
350
|
+
description?: string | undefined
|
|
351
|
+
/** Exact `error.code` values this status returns for the operation. */
|
|
352
|
+
codes?: readonly [string, ...string[]] | undefined
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Options for building a standard OpenAPI responses map. */
|
|
356
|
+
type Options<schema> = {
|
|
357
|
+
/**
|
|
358
|
+
* Optional overrides for standard error responses (description and/or exact
|
|
359
|
+
* `error.code` enum). Setting `403`/`404`/`409`/`412`/`413`/`415` also
|
|
360
|
+
* includes that status in the map.
|
|
361
|
+
*/
|
|
362
|
+
errors?:
|
|
363
|
+
| {
|
|
364
|
+
/** Override for the 400 response. */
|
|
365
|
+
400?: ErrorOverride | undefined
|
|
366
|
+
/** Override for the 401 response. */
|
|
367
|
+
401?: ErrorOverride | undefined
|
|
368
|
+
/** Override for the 403 response. Setting this includes 403 in the map. */
|
|
369
|
+
403?: ErrorOverride | undefined
|
|
370
|
+
/** Override for the 404 response. Setting this includes 404 in the map. */
|
|
371
|
+
404?: ErrorOverride | undefined
|
|
372
|
+
/** Override for the 409 response. Setting this includes 409 in the map. */
|
|
373
|
+
409?: ErrorOverride | undefined
|
|
374
|
+
/** Override for the 412 response. Setting this includes 412 in the map. */
|
|
375
|
+
412?: ErrorOverride | undefined
|
|
376
|
+
/** Override for the 413 response. Setting this includes 413 in the map. */
|
|
377
|
+
413?: ErrorOverride | undefined
|
|
378
|
+
/** Override for the 415 response. Setting this includes 415 in the map. */
|
|
379
|
+
415?: ErrorOverride | undefined
|
|
380
|
+
/** Override for the 502 response. */
|
|
381
|
+
502?: ErrorOverride | undefined
|
|
382
|
+
}
|
|
383
|
+
| undefined
|
|
384
|
+
/** 200 response schema and description. */
|
|
385
|
+
success: {
|
|
386
|
+
/** Human-readable description of the success body. */
|
|
387
|
+
description: string
|
|
388
|
+
/** Optional full example body rendered for the 200 response. */
|
|
389
|
+
example?: unknown
|
|
390
|
+
/** Zod schema describing the 200 response body. */
|
|
391
|
+
schema: schema
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Always false at runtime, but typed as `boolean` so route handlers can include
|
|
398
|
+
* a never-reached validation-error branch in Hono's inferred response union.
|
|
399
|
+
*/
|
|
400
|
+
export const narrowValidation = false as boolean
|
|
401
|
+
|
|
402
|
+
/** Typed validation error response for Hono client inference. Never reached at runtime. */
|
|
403
|
+
export function validationError<const code extends string>(
|
|
404
|
+
c: Context,
|
|
405
|
+
options: validationError.Options<code>,
|
|
406
|
+
) {
|
|
407
|
+
return Response.error(c, { code: options.code, message: options.message, status: 400 })
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export declare namespace validationError {
|
|
411
|
+
/** Options for building a typed validation error response. */
|
|
412
|
+
type Options<code extends string = string> = {
|
|
413
|
+
/** Stable machine-readable validation error code. */
|
|
414
|
+
code: code
|
|
415
|
+
/** Human-readable validation error message. */
|
|
416
|
+
message: string
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Wrapper around `hono-openapi`'s `validator` that returns the API's standard
|
|
422
|
+
* 400 error envelope (with structured validation details) when parsing fails.
|
|
423
|
+
*
|
|
424
|
+
* Use this for every route validator instead of repeating the `result.success`
|
|
425
|
+
* ceremony per route.
|
|
426
|
+
*/
|
|
427
|
+
export function validate<
|
|
428
|
+
const target extends keyof ValidationTargets,
|
|
429
|
+
const schema extends z.ZodMiniType,
|
|
430
|
+
>(
|
|
431
|
+
target: target,
|
|
432
|
+
schema: schema,
|
|
433
|
+
options: validate.Options,
|
|
434
|
+
): MiddlewareHandler<Env, string, validate.Input<target, schema>> {
|
|
435
|
+
return validator(
|
|
436
|
+
target,
|
|
437
|
+
schema,
|
|
438
|
+
(result, c) => {
|
|
439
|
+
if (result.success) return undefined
|
|
440
|
+
return Response.error(c, {
|
|
441
|
+
code: options.code,
|
|
442
|
+
details: Response.validationDetails(result.error),
|
|
443
|
+
message: options.message,
|
|
444
|
+
status: 400,
|
|
445
|
+
})
|
|
446
|
+
},
|
|
447
|
+
// Recover `examples` zod strips from pipe/default input schemas, so every
|
|
448
|
+
// generated parameter surfaces the example attached via `z.meta(...)`.
|
|
449
|
+
schemaOptions,
|
|
450
|
+
) as never
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export declare namespace validate {
|
|
454
|
+
/** Hono input attached by the standard OpenAPI validator wrapper. */
|
|
455
|
+
type Input<target extends keyof ValidationTargets, schema extends z.ZodMiniType> = {
|
|
456
|
+
in: RequestInput<target, z.input<schema>>
|
|
457
|
+
out: { [key in target]: z.output<schema> }
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Options for the standard validator helper. */
|
|
461
|
+
type Options = {
|
|
462
|
+
/** Stable machine-readable error code (e.g. `query_invalid`). */
|
|
463
|
+
code: string
|
|
464
|
+
/** Human-readable error message. */
|
|
465
|
+
message: string
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** Request input accepted by `hono/client` for a validation target. */
|
|
469
|
+
type RequestInput<target extends keyof ValidationTargets, input> = target extends 'query'
|
|
470
|
+
? input extends object
|
|
471
|
+
? HasRequiredKeys<input> extends true
|
|
472
|
+
? { query: TargetInput<'query', input> }
|
|
473
|
+
: { query?: TargetInput<'query', input> | undefined }
|
|
474
|
+
: { query: input }
|
|
475
|
+
: { [key in target]: TargetInput<target, input> }
|
|
476
|
+
|
|
477
|
+
/** Converts schema input into the fetch-client input shape for a target. */
|
|
478
|
+
type TargetInput<
|
|
479
|
+
target extends keyof ValidationTargets,
|
|
480
|
+
input,
|
|
481
|
+
> = input extends ValidationTargets[target]
|
|
482
|
+
? input
|
|
483
|
+
: {
|
|
484
|
+
[key in keyof input]: key extends keyof ValidationTargets[target]
|
|
485
|
+
? ValidationTargets[target][key]
|
|
486
|
+
: never
|
|
487
|
+
}
|
|
488
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as Path from './Path.js'
|
|
2
|
+
|
|
3
|
+
describe('join', () => {
|
|
4
|
+
test('normalizes URL path segments', () => {
|
|
5
|
+
expect([Path.join('/api', 'data', '42431'), Path.join('/', 'data', '/42431/'), Path.join('')])
|
|
6
|
+
.toMatchInlineSnapshot(`
|
|
7
|
+
[
|
|
8
|
+
"/api/data/42431",
|
|
9
|
+
"/data/42431",
|
|
10
|
+
"/",
|
|
11
|
+
]
|
|
12
|
+
`)
|
|
13
|
+
})
|
|
14
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Normalizes a route prefix to a leading slash with no trailing slash. */
|
|
2
|
+
export function normalize(path: string) {
|
|
3
|
+
const normalized = path.startsWith('/') ? path : `/${path}`
|
|
4
|
+
if (normalized.length > 1 && normalized.endsWith('/')) return normalized.slice(0, -1)
|
|
5
|
+
return normalized
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Joins URL path segments into one normalized absolute path. */
|
|
9
|
+
export function join(...segments: string[]) {
|
|
10
|
+
const path = segments
|
|
11
|
+
.flatMap((segment) => segment.split('/'))
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.join('/')
|
|
14
|
+
return path ? `/${path}` : '/'
|
|
15
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { RateLimit, Store } from 'cadent'
|
|
2
|
+
|
|
3
|
+
describe('memory', () => {
|
|
4
|
+
test('tracks fixed-window quota in a store', async () => {
|
|
5
|
+
const store = RateLimit.memory({
|
|
6
|
+
now: () => new Date('2026-05-25T00:00:30.000Z'),
|
|
7
|
+
})
|
|
8
|
+
const first = await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
9
|
+
const second = await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
10
|
+
const third = await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
11
|
+
|
|
12
|
+
expect(first).toMatchInlineSnapshot(`
|
|
13
|
+
{
|
|
14
|
+
"allowed": true,
|
|
15
|
+
"limit": 2,
|
|
16
|
+
"remaining": 1,
|
|
17
|
+
"reset": 1779667260,
|
|
18
|
+
}
|
|
19
|
+
`)
|
|
20
|
+
expect(second).toMatchInlineSnapshot(`
|
|
21
|
+
{
|
|
22
|
+
"allowed": true,
|
|
23
|
+
"limit": 2,
|
|
24
|
+
"remaining": 0,
|
|
25
|
+
"reset": 1779667260,
|
|
26
|
+
}
|
|
27
|
+
`)
|
|
28
|
+
expect(third).toMatchInlineSnapshot(`
|
|
29
|
+
{
|
|
30
|
+
"allowed": false,
|
|
31
|
+
"limit": 2,
|
|
32
|
+
"remaining": 0,
|
|
33
|
+
"reset": 1779667260,
|
|
34
|
+
}
|
|
35
|
+
`)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('restarts the count when the next window opens', async () => {
|
|
39
|
+
// The window reset rides on counter expiry (the key is stable, not
|
|
40
|
+
// bucket-suffixed), so the store clock and the consume clock must agree.
|
|
41
|
+
vi.useFakeTimers()
|
|
42
|
+
try {
|
|
43
|
+
vi.setSystemTime(new Date('2026-05-25T00:00:30.000Z'))
|
|
44
|
+
const store = RateLimit.memory()
|
|
45
|
+
await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
46
|
+
await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
47
|
+
|
|
48
|
+
vi.setSystemTime(new Date('2026-05-25T00:01:00.001Z'))
|
|
49
|
+
const next = await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
50
|
+
|
|
51
|
+
expect(next).toMatchInlineSnapshot(`
|
|
52
|
+
{
|
|
53
|
+
"allowed": true,
|
|
54
|
+
"limit": 2,
|
|
55
|
+
"remaining": 1,
|
|
56
|
+
"reset": 1779667320,
|
|
57
|
+
}
|
|
58
|
+
`)
|
|
59
|
+
} finally {
|
|
60
|
+
vi.useRealTimers()
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('consumes with one increment that expires at the end of the window', async () => {
|
|
65
|
+
const increments: { key: string; options: Store.Store.PutOptions | undefined }[] = []
|
|
66
|
+
const backing = Store.memory()
|
|
67
|
+
const recording = Store.from({
|
|
68
|
+
...backing,
|
|
69
|
+
async increment(key, options) {
|
|
70
|
+
increments.push({ key, options })
|
|
71
|
+
return Store.increment(backing, key, options)
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
const store = RateLimit.memory({
|
|
75
|
+
// 30s into the minute, so 30s of the window remains.
|
|
76
|
+
now: () => new Date('2026-05-25T00:00:30.000Z'),
|
|
77
|
+
store: recording,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await store.consume({ key: 'public:anonymous', limit: { perMinute: 2 } })
|
|
81
|
+
|
|
82
|
+
expect(increments).toMatchInlineSnapshot(`
|
|
83
|
+
[
|
|
84
|
+
{
|
|
85
|
+
"key": "ratelimit:public:anonymous",
|
|
86
|
+
"options": {
|
|
87
|
+
"ttl": 30000,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
]
|
|
91
|
+
`)
|
|
92
|
+
})
|
|
93
|
+
})
|