tapimo 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -3
- package/dist/ApiKey.d.ts +1 -0
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +5 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +28 -1
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +34 -1
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +7167 -4507
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +8 -0
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +11 -2
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +14 -3
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +128 -118
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +7 -0
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/scopes.d.ts +8 -0
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/scopes.js +3 -0
- package/dist/admin/apps/scopes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +57 -57
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +13 -13
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +151 -0
- package/dist/analytics/Analytics.d.ts.map +1 -0
- package/dist/analytics/Analytics.js +212 -0
- package/dist/analytics/Analytics.js.map +1 -0
- package/dist/analytics/tables/requestEvents.d.ts +215 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
- package/dist/analytics/tables/requestEvents.js +264 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -0
- package/dist/apps/data/App.d.ts +1024 -624
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +36 -0
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +45 -45
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/exchanges.d.ts +455 -455
- package/dist/apps/data/routes/fee-amm.d.ts +101 -101
- package/dist/apps/data/routes/funding.d.ts +765 -0
- package/dist/apps/data/routes/funding.d.ts.map +1 -0
- package/dist/apps/data/routes/funding.js +383 -0
- package/dist/apps/data/routes/funding.js.map +1 -0
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +2 -8
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +29 -36
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +29 -1
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +36 -36
- package/dist/apps/data/routes/transfers.d.ts +56 -56
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/webhooks.d.ts +45 -45
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +8 -8
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/docs/App.d.ts +4 -2
- package/dist/apps/docs/App.d.ts.map +1 -1
- package/dist/apps/docs/App.js +27 -95
- package/dist/apps/docs/App.js.map +1 -1
- package/dist/apps/docs/reference.d.ts +21 -0
- package/dist/apps/docs/reference.d.ts.map +1 -0
- package/dist/apps/docs/reference.js +112 -0
- package/dist/apps/docs/reference.js.map +1 -0
- package/dist/apps/index.d.ts +1 -0
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -0
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/mcp.d.ts +76 -0
- package/dist/apps/mcp.d.ts.map +1 -0
- package/dist/apps/mcp.js +188 -0
- package/dist/apps/mcp.js.map +1 -0
- package/dist/apps/platform/App.d.ts +3005 -728
- package/dist/apps/platform/App.d.ts.map +1 -1
- package/dist/apps/platform/App.js +13 -3
- package/dist/apps/platform/App.js.map +1 -1
- package/dist/apps/platform/Billing.d.ts +279 -0
- package/dist/apps/platform/Billing.d.ts.map +1 -0
- package/dist/apps/platform/Billing.js +477 -0
- package/dist/apps/platform/Billing.js.map +1 -0
- package/dist/apps/platform/index.d.ts +1 -0
- package/dist/apps/platform/index.d.ts.map +1 -1
- package/dist/apps/platform/index.js +1 -0
- package/dist/apps/platform/index.js.map +1 -1
- package/dist/apps/platform/routes/api-keys.d.ts +341 -49
- package/dist/apps/platform/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/platform/routes/api-keys.js +115 -13
- package/dist/apps/platform/routes/api-keys.js.map +1 -1
- package/dist/apps/platform/routes/billing.d.ts +1520 -0
- package/dist/apps/platform/routes/billing.d.ts.map +1 -0
- package/dist/apps/platform/routes/billing.js +795 -0
- package/dist/apps/platform/routes/billing.js.map +1 -0
- package/dist/apps/platform/routes/invitations.d.ts +201 -83
- package/dist/apps/platform/routes/invitations.d.ts.map +1 -1
- package/dist/apps/platform/routes/invitations.js +58 -0
- package/dist/apps/platform/routes/invitations.js.map +1 -1
- package/dist/apps/platform/routes/me.d.ts +17 -17
- package/dist/apps/platform/routes/orgs.d.ts +50 -36
- package/dist/apps/platform/routes/orgs.d.ts.map +1 -1
- package/dist/apps/platform/routes/orgs.js +14 -3
- package/dist/apps/platform/routes/orgs.js.map +1 -1
- package/dist/apps/platform/routes/projects.d.ts +97 -97
- package/dist/apps/platform/routes/scopes.d.ts +107 -0
- package/dist/apps/platform/routes/scopes.d.ts.map +1 -0
- package/dist/apps/platform/routes/scopes.js +66 -0
- package/dist/apps/platform/routes/scopes.js.map +1 -0
- package/dist/apps/platform/routes/usage.d.ts +588 -0
- package/dist/apps/platform/routes/usage.d.ts.map +1 -0
- package/dist/apps/platform/routes/usage.js +391 -0
- package/dist/apps/platform/routes/usage.js.map +1 -0
- package/dist/apps/relay/App.d.ts +4 -1
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +118 -10
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +2 -1
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/cli/Cli.d.ts +8 -1
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +11 -3
- package/dist/cli/Cli.js.map +1 -1
- package/dist/cli/commands/admin.d.ts +4 -0
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/admin.js +80 -1
- package/dist/cli/commands/admin.js.map +1 -1
- package/dist/db/Db.d.ts +7 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +126 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +79 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +88 -2
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/billingSettings.d.ts +55 -0
- package/dist/db/tables/billingSettings.d.ts.map +1 -0
- package/dist/db/tables/billingSettings.js +70 -0
- package/dist/db/tables/billingSettings.js.map +1 -0
- package/dist/db/tables/invitations.js +2 -2
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +6 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +10 -4
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.js +2 -2
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +121 -0
- package/dist/db/tables/requestUsage.d.ts.map +1 -0
- package/dist/db/tables/requestUsage.js +150 -0
- package/dist/db/tables/requestUsage.js.map +1 -0
- package/dist/db/tables/sponsoredTransactions.d.ts +119 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +155 -2
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/stripeCustomers.d.ts +81 -0
- package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
- package/dist/db/tables/stripeCustomers.js +120 -0
- package/dist/db/tables/stripeCustomers.js.map +1 -0
- package/dist/db/tables/users.js +2 -2
- package/dist/db/tables/users.js.map +1 -1
- package/dist/handlers/internal/sponsorship.d.ts +5 -2
- package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
- package/dist/handlers/internal/sponsorship.js +19 -5
- package/dist/handlers/internal/sponsorship.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +10 -3
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +14 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/Auth.d.ts +18 -4
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +148 -76
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +4 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +10 -0
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +39 -8
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/Fees.d.ts +27 -0
- package/dist/internal/Fees.d.ts.map +1 -0
- package/dist/internal/Fees.js +48 -0
- package/dist/internal/Fees.js.map +1 -0
- package/dist/internal/FundingRoutes.d.ts +183 -0
- package/dist/internal/FundingRoutes.d.ts.map +1 -0
- package/dist/internal/FundingRoutes.js +490 -0
- package/dist/internal/FundingRoutes.js.map +1 -0
- package/dist/internal/Id.d.ts +15 -0
- package/dist/internal/Id.d.ts.map +1 -0
- package/dist/internal/Id.js +22 -0
- package/dist/internal/Id.js.map +1 -0
- package/dist/internal/Log.d.ts +2 -0
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +3 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +10 -1
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +8 -1
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +25 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +51 -0
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Response.d.ts +1 -1
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Schema.d.ts +8 -0
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +7 -0
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +3 -3
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +4 -3
- package/src/ApiKey.ts +9 -2
- package/src/ApiKeys.test.ts +51 -0
- package/src/ApiKeys.ts +50 -1
- package/src/App.test.ts +33 -86718
- package/src/App.ts +18 -0
- package/src/Client.test-d.ts +351 -0
- package/src/Scope.ts +16 -3
- package/src/admin/apps/scopes.test.ts +6 -0
- package/src/admin/apps/scopes.ts +3 -0
- package/src/admin/ui/src/components/Page.tsx +2 -3
- package/src/admin/ui/src/routes/__root.tsx +2 -2
- package/src/admin/ui/src/routes/api-keys.tsx +2 -2
- package/src/admin/ui.generated.ts +13 -13
- package/src/analytics/Analytics.test.ts +527 -0
- package/src/analytics/Analytics.ts +318 -0
- package/src/analytics/tables/requestEvents.ts +523 -0
- package/src/apps/data/App.test.ts +72 -0
- package/src/apps/data/App.ts +35 -0
- package/src/apps/data/routes/funding.test.ts +214 -0
- package/src/apps/data/routes/funding.ts +584 -0
- package/src/apps/data/routes/receipts.ts +2 -9
- package/src/apps/data/routes/rpc.test.ts +78 -2
- package/src/apps/data/routes/rpc.ts +31 -1
- package/src/apps/data/routes/webhooks.test.ts +1 -1
- package/src/apps/data/routes/webhooks.ts +11 -8
- package/src/apps/docs/App.ts +29 -100
- package/src/apps/docs/reference.ts +132 -0
- package/src/apps/index.ts +1 -0
- package/src/apps/mcp.test.ts +206 -0
- package/src/apps/mcp.ts +250 -0
- package/src/apps/platform/App.ts +43 -4
- package/src/apps/platform/Billing.test.ts +530 -0
- package/src/apps/platform/Billing.ts +682 -0
- package/src/apps/platform/index.ts +1 -0
- package/src/apps/platform/routes/api-keys.test.ts +172 -9
- package/src/apps/platform/routes/api-keys.ts +136 -20
- package/src/apps/platform/routes/billing.test.ts +1100 -0
- package/src/apps/platform/routes/billing.ts +966 -0
- package/src/apps/platform/routes/invitations.test.ts +55 -7
- package/src/apps/platform/routes/invitations.ts +68 -0
- package/src/apps/platform/routes/me.test.ts +230 -0
- package/src/apps/platform/routes/orgs.ts +26 -4
- package/src/apps/platform/routes/scopes.test.ts +29 -0
- package/src/apps/platform/routes/scopes.ts +85 -0
- package/src/apps/platform/routes/usage.test.ts +422 -0
- package/src/apps/platform/routes/usage.ts +527 -0
- package/src/apps/relay/App.test.ts +457 -8
- package/src/apps/relay/App.ts +120 -12
- package/src/apps/relay/Sponsorships.test.ts +1 -1
- package/src/apps/relay/Sponsorships.ts +2 -1
- package/src/cli/Cli.test.ts +25 -2
- package/src/cli/Cli.ts +17 -2
- package/src/cli/commands/admin.test.ts +83 -0
- package/src/cli/commands/admin.ts +89 -1
- package/src/db/Db.ts +137 -0
- package/src/db/Schema.ts +104 -2
- package/src/db/tables/billingSettings.test.ts +87 -0
- package/src/db/tables/billingSettings.ts +108 -0
- package/src/db/tables/invitations.ts +2 -2
- package/src/db/tables/organizations.test.ts +1 -1
- package/src/db/tables/organizations.ts +15 -5
- package/src/db/tables/projects.ts +2 -2
- package/src/db/tables/requestUsage.ts +231 -0
- package/src/db/tables/sponsoredTransactions.test.ts +108 -1
- package/src/db/tables/sponsoredTransactions.ts +230 -2
- package/src/db/tables/stripeCustomers.test.ts +109 -0
- package/src/db/tables/stripeCustomers.ts +162 -0
- package/src/db/tables/users.ts +2 -2
- package/src/handlers/internal/sponsorship.ts +34 -7
- package/src/handlers/internal/utils.ts +19 -7
- package/src/index.ts +1 -0
- package/src/internal/Auth.test.ts +175 -25
- package/src/internal/Auth.ts +175 -86
- package/src/internal/Cache.ts +5 -1
- package/src/internal/EdgeCache.test.ts +27 -4
- package/src/internal/EdgeCache.ts +47 -9
- package/src/internal/Fees.test.ts +32 -0
- package/src/internal/Fees.ts +51 -0
- package/src/internal/FundingRoutes.ts +583 -0
- package/src/internal/Id.test.ts +17 -0
- package/src/internal/Id.ts +24 -0
- package/src/internal/Log.test.ts +1 -0
- package/src/internal/Log.ts +5 -0
- package/src/internal/OpenApi.ts +12 -1
- package/src/internal/RateLimit.test.ts +84 -0
- package/src/internal/RateLimit.ts +70 -0
- package/src/internal/Response.ts +1 -1
- package/src/internal/Schema.ts +8 -0
- package/src/internal/Webhooks.test.ts +3 -3
- package/src/internal/Webhooks.ts +3 -3
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import { type Context, Hono } from 'hono'
|
|
2
|
+
import * as z from 'zod/mini'
|
|
3
|
+
|
|
4
|
+
import * as Analytics from '../../../analytics/Analytics.js'
|
|
5
|
+
import * as ApiKeys from '../../../ApiKeys.js'
|
|
6
|
+
import * as Auth from '../../../internal/Auth.js'
|
|
7
|
+
import * as BillingSettings from '../../../db/tables/billingSettings.js'
|
|
8
|
+
import * as Db from '../../../db/Db.js'
|
|
9
|
+
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
10
|
+
import * as RequestEvents from '../../../analytics/tables/requestEvents.js'
|
|
11
|
+
import * as Response from '../../../internal/Response.js'
|
|
12
|
+
import * as Schema from '../../../internal/Schema.js'
|
|
13
|
+
import * as SponsoredTransactions from '../../../db/tables/sponsoredTransactions.js'
|
|
14
|
+
import * as core_Billing from '../Billing.js'
|
|
15
|
+
import type { Environment } from '../App.js'
|
|
16
|
+
|
|
17
|
+
/** Zod schemas owned by the usage resource. */
|
|
18
|
+
export namespace schema {
|
|
19
|
+
/** Schemas for the getRequestUsage operation. */
|
|
20
|
+
export namespace getRequestUsage {
|
|
21
|
+
/** Usage grouped by API key. */
|
|
22
|
+
export const KeyBreakdown = z
|
|
23
|
+
.object({
|
|
24
|
+
apiKeyId: z
|
|
25
|
+
.string()
|
|
26
|
+
.check(
|
|
27
|
+
z.describe('API key id (`key_…`).'),
|
|
28
|
+
z.meta({ examples: ['key_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
29
|
+
),
|
|
30
|
+
averageDurationMs: z
|
|
31
|
+
.number()
|
|
32
|
+
.check(
|
|
33
|
+
z.describe('Average request duration in milliseconds.'),
|
|
34
|
+
z.meta({ examples: [12.3] }),
|
|
35
|
+
),
|
|
36
|
+
errors: z
|
|
37
|
+
.number()
|
|
38
|
+
.check(z.int(), z.describe('Requests whose status was at least 400.'), z.meta({ examples: [3] })), // prettier-ignore
|
|
39
|
+
requests: z
|
|
40
|
+
.number()
|
|
41
|
+
.check(z.int(), z.describe('Total requests.'), z.meta({ examples: [120] })),
|
|
42
|
+
})
|
|
43
|
+
.check(z.describe('Usage grouped by API key.'))
|
|
44
|
+
|
|
45
|
+
/** Path parameters addressing one organization's usage. */
|
|
46
|
+
export const Params = z
|
|
47
|
+
.object({
|
|
48
|
+
orgId: z
|
|
49
|
+
.string()
|
|
50
|
+
.check(
|
|
51
|
+
z.describe('The organization id (`org_…`).'),
|
|
52
|
+
z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
53
|
+
),
|
|
54
|
+
})
|
|
55
|
+
.check(z.describe("Path parameters for an organization's usage."))
|
|
56
|
+
|
|
57
|
+
/** Query parameters for request usage. */
|
|
58
|
+
export const Query = z
|
|
59
|
+
.strictObject({
|
|
60
|
+
environment: z
|
|
61
|
+
.optional(z.enum(['production', 'sandbox']))
|
|
62
|
+
.check(z.describe('Only include requests made with this API-key environment.'), z.meta({ examples: ['sandbox'] })), // prettier-ignore
|
|
63
|
+
from: z
|
|
64
|
+
.optional(z.iso.datetime({ offset: true }))
|
|
65
|
+
.check(
|
|
66
|
+
z.describe('Only include requests at or after this ISO 8601 timestamp.'),
|
|
67
|
+
z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
|
|
68
|
+
),
|
|
69
|
+
interval: z
|
|
70
|
+
._default(z.enum(['day', 'hour']), 'day')
|
|
71
|
+
.check(
|
|
72
|
+
z.describe('Time bucket size for the usage series.'),
|
|
73
|
+
z.meta({ examples: ['day'] }),
|
|
74
|
+
),
|
|
75
|
+
projectId: z.optional(z.string()).check(
|
|
76
|
+
z.describe('Only include requests attributed to this project (`prj_…`). Omit for organization-wide usage.'), // prettier-ignore
|
|
77
|
+
z.meta({ examples: ['prj_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
78
|
+
),
|
|
79
|
+
to: z
|
|
80
|
+
.optional(z.iso.datetime({ offset: true }))
|
|
81
|
+
.check(
|
|
82
|
+
z.describe('Only include requests at or before this ISO 8601 timestamp.'),
|
|
83
|
+
z.meta({ examples: ['2026-01-31T23:59:59Z'] }),
|
|
84
|
+
),
|
|
85
|
+
})
|
|
86
|
+
.check(z.describe('Query parameters for request usage.'))
|
|
87
|
+
|
|
88
|
+
/** Usage grouped by route. */
|
|
89
|
+
export const RouteBreakdown = z
|
|
90
|
+
.object({
|
|
91
|
+
averageDurationMs: z
|
|
92
|
+
.number()
|
|
93
|
+
.check(
|
|
94
|
+
z.describe('Average request duration in milliseconds.'),
|
|
95
|
+
z.meta({ examples: [18.2] }),
|
|
96
|
+
),
|
|
97
|
+
errors: z
|
|
98
|
+
.number()
|
|
99
|
+
.check(z.int(), z.describe('Requests whose status was at least 400.'), z.meta({ examples: [2] })), // prettier-ignore
|
|
100
|
+
requests: z
|
|
101
|
+
.number()
|
|
102
|
+
.check(z.int(), z.describe('Total requests.'), z.meta({ examples: [80] })),
|
|
103
|
+
route: z
|
|
104
|
+
.string()
|
|
105
|
+
.check(
|
|
106
|
+
z.describe('Matched route pattern.'),
|
|
107
|
+
z.meta({ examples: ['/v1/transactions/:hash'] }),
|
|
108
|
+
),
|
|
109
|
+
})
|
|
110
|
+
.check(z.describe('Usage grouped by route.'))
|
|
111
|
+
|
|
112
|
+
/** One usage series point. */
|
|
113
|
+
export const SeriesPoint = z
|
|
114
|
+
.object({
|
|
115
|
+
errors: z
|
|
116
|
+
.number()
|
|
117
|
+
.check(z.int(), z.describe('Requests whose status was at least 400.'), z.meta({ examples: [1] })), // prettier-ignore
|
|
118
|
+
requests: z
|
|
119
|
+
.number()
|
|
120
|
+
.check(z.int(), z.describe('Total requests.'), z.meta({ examples: [40] })),
|
|
121
|
+
time: z
|
|
122
|
+
.string()
|
|
123
|
+
.check(
|
|
124
|
+
z.describe('Bucket start timestamp (ISO 8601).'),
|
|
125
|
+
z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
|
|
126
|
+
),
|
|
127
|
+
})
|
|
128
|
+
.check(z.describe('One usage series point.'))
|
|
129
|
+
|
|
130
|
+
/** Usage grouped by status code. */
|
|
131
|
+
export const StatusBreakdown = z
|
|
132
|
+
.object({
|
|
133
|
+
requests: z
|
|
134
|
+
.number()
|
|
135
|
+
.check(z.int(), z.describe('Total requests.'), z.meta({ examples: [100] })),
|
|
136
|
+
status: z
|
|
137
|
+
.number()
|
|
138
|
+
.check(z.int(), z.describe('HTTP status code.'), z.meta({ examples: [200] })),
|
|
139
|
+
})
|
|
140
|
+
.check(z.describe('Usage grouped by status code.'))
|
|
141
|
+
|
|
142
|
+
/** Overall usage totals. */
|
|
143
|
+
export const Totals = z
|
|
144
|
+
.object({
|
|
145
|
+
averageDurationMs: z
|
|
146
|
+
.number()
|
|
147
|
+
.check(
|
|
148
|
+
z.describe('Average request duration in milliseconds.'),
|
|
149
|
+
z.meta({ examples: [15.6] }),
|
|
150
|
+
),
|
|
151
|
+
errors: z
|
|
152
|
+
.number()
|
|
153
|
+
.check(z.int(), z.describe('Requests whose status was at least 400.'), z.meta({ examples: [5] })), // prettier-ignore
|
|
154
|
+
requests: z
|
|
155
|
+
.number()
|
|
156
|
+
.check(z.int(), z.describe('Total requests.'), z.meta({ examples: [200] })),
|
|
157
|
+
})
|
|
158
|
+
.check(z.describe('Overall usage totals.'))
|
|
159
|
+
|
|
160
|
+
/** Request usage. */
|
|
161
|
+
export const Response = Schema.describe(
|
|
162
|
+
z.object({
|
|
163
|
+
byKey: z.array(KeyBreakdown).check(z.describe('Usage grouped by API key.')),
|
|
164
|
+
byRoute: z.array(RouteBreakdown).check(z.describe('Usage grouped by route.')),
|
|
165
|
+
byStatus: z.array(StatusBreakdown).check(z.describe('Usage grouped by status code.')),
|
|
166
|
+
from: z
|
|
167
|
+
.string()
|
|
168
|
+
.check(
|
|
169
|
+
z.describe('Inclusive lower timestamp bound used for the read (ISO 8601).'),
|
|
170
|
+
z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
|
|
171
|
+
),
|
|
172
|
+
interval: z
|
|
173
|
+
.enum(['day', 'hour'])
|
|
174
|
+
.check(
|
|
175
|
+
z.describe('Bucket size used for the time series.'),
|
|
176
|
+
z.meta({ examples: ['day'] }),
|
|
177
|
+
),
|
|
178
|
+
series: z.array(SeriesPoint).check(z.describe('Usage grouped into time buckets.')),
|
|
179
|
+
to: z
|
|
180
|
+
.string()
|
|
181
|
+
.check(
|
|
182
|
+
z.describe('Inclusive upper timestamp bound used for the read (ISO 8601).'),
|
|
183
|
+
z.meta({ examples: ['2026-01-31T23:59:59.000Z'] }),
|
|
184
|
+
),
|
|
185
|
+
totals: Totals,
|
|
186
|
+
}),
|
|
187
|
+
'Request usage.',
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Schemas for the getSponsorshipUsage operation. */
|
|
192
|
+
export namespace getSponsorshipUsage {
|
|
193
|
+
/** One time bucket of sponsorship usage. */
|
|
194
|
+
export const Bucket = Schema.describe(
|
|
195
|
+
z.object({
|
|
196
|
+
count: z
|
|
197
|
+
.number()
|
|
198
|
+
.check(
|
|
199
|
+
z.describe('Sponsored transactions recorded in the bucket, any status.'),
|
|
200
|
+
z.meta({ examples: [42] }),
|
|
201
|
+
),
|
|
202
|
+
feeTotal: z
|
|
203
|
+
.object({
|
|
204
|
+
amount: z.string().check(
|
|
205
|
+
z.describe('Committed fees as a decimal string: finalized fees plus in-flight fee caps; failed rows contribute zero.'), // prettier-ignore
|
|
206
|
+
z.meta({ examples: ['12.34'] }),
|
|
207
|
+
),
|
|
208
|
+
currency: z
|
|
209
|
+
.enum(BillingSettings.currencies)
|
|
210
|
+
.check(z.describe('Currency of the fee figure.'), z.meta({ examples: ['usd'] })),
|
|
211
|
+
})
|
|
212
|
+
.check(
|
|
213
|
+
z.describe('Committed fees for the bucket.'),
|
|
214
|
+
z.meta({ examples: [{ amount: '12.34', currency: 'usd' }] }),
|
|
215
|
+
),
|
|
216
|
+
timestamp: z
|
|
217
|
+
.string()
|
|
218
|
+
.check(
|
|
219
|
+
z.describe('Bucket start (ISO 8601), aligned to UTC calendar boundaries.'),
|
|
220
|
+
z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
|
|
221
|
+
),
|
|
222
|
+
}),
|
|
223
|
+
'One time bucket of sponsorship usage.',
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
/** Path parameters addressing one organization's usage. */
|
|
227
|
+
export const Params = z
|
|
228
|
+
.object({
|
|
229
|
+
orgId: z
|
|
230
|
+
.string()
|
|
231
|
+
.check(
|
|
232
|
+
z.describe('The organization id (`org_…`).'),
|
|
233
|
+
z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
234
|
+
),
|
|
235
|
+
})
|
|
236
|
+
.check(z.describe("Path parameters for one organization's usage."))
|
|
237
|
+
|
|
238
|
+
/** Query parameters scoping the sponsorship usage series. */
|
|
239
|
+
export const Query = z
|
|
240
|
+
.strictObject({
|
|
241
|
+
environment: z
|
|
242
|
+
.optional(z.enum(['production', 'sandbox']))
|
|
243
|
+
.check(
|
|
244
|
+
z.describe('Only include sponsorships requested under this key environment.'),
|
|
245
|
+
z.meta({ examples: ['production'] }),
|
|
246
|
+
),
|
|
247
|
+
from: z
|
|
248
|
+
.optional(z.iso.datetime({ offset: true }))
|
|
249
|
+
.check(
|
|
250
|
+
z.describe('Window start (ISO 8601), inclusive. Defaults to 30 days before `to`.'),
|
|
251
|
+
z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
|
|
252
|
+
),
|
|
253
|
+
interval: z
|
|
254
|
+
._default(z.enum(['day', 'hour', 'month', 'week']), 'day')
|
|
255
|
+
.check(
|
|
256
|
+
z.describe('Bucket width, aligned to UTC calendar boundaries.'),
|
|
257
|
+
z.meta({ examples: ['day'] }),
|
|
258
|
+
),
|
|
259
|
+
projectId: z
|
|
260
|
+
.optional(z.string())
|
|
261
|
+
.check(
|
|
262
|
+
z.describe('Only include sponsorships attributed to this project (`prj_…`).'),
|
|
263
|
+
z.meta({ examples: ['prj_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
264
|
+
),
|
|
265
|
+
to: z
|
|
266
|
+
.optional(z.iso.datetime({ offset: true }))
|
|
267
|
+
.check(
|
|
268
|
+
z.describe('Window end (ISO 8601), exclusive. Defaults to now.'),
|
|
269
|
+
z.meta({ examples: ['2026-01-31T00:00:00Z'] }),
|
|
270
|
+
),
|
|
271
|
+
})
|
|
272
|
+
.check(z.describe('Query parameters scoping the sponsorship usage series.'))
|
|
273
|
+
|
|
274
|
+
/** Sponsorship usage bucketed over time. */
|
|
275
|
+
export const Response = Schema.describe(
|
|
276
|
+
z.object({
|
|
277
|
+
data: z
|
|
278
|
+
.array(Bucket)
|
|
279
|
+
.check(
|
|
280
|
+
z.describe('Time-ordered usage buckets; buckets with no sponsorships are omitted.'),
|
|
281
|
+
),
|
|
282
|
+
}),
|
|
283
|
+
'Sponsorship usage bucketed over time.',
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Mounts the usage surface: project request usage (read from a host-supplied
|
|
290
|
+
* analytics capability) and an organization's sponsorship volume and fees
|
|
291
|
+
* over time. Session lane; reads for members.
|
|
292
|
+
*/
|
|
293
|
+
export function usage() {
|
|
294
|
+
return new Hono<Environment>()
|
|
295
|
+
.get(
|
|
296
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/usage/requests',
|
|
297
|
+
Auth.policy({ session: true }),
|
|
298
|
+
Auth.ensureOrg(),
|
|
299
|
+
OpenApi.validate('param', schema.getRequestUsage.Params, {
|
|
300
|
+
code: 'param_invalid',
|
|
301
|
+
message: 'Check the path parameters and try again.',
|
|
302
|
+
}),
|
|
303
|
+
OpenApi.validate('query', schema.getRequestUsage.Query, {
|
|
304
|
+
code: 'query_invalid',
|
|
305
|
+
message: 'Check the query parameters and try again.',
|
|
306
|
+
}),
|
|
307
|
+
OpenApi.describeRoute({
|
|
308
|
+
operationId: 'getRequestUsage',
|
|
309
|
+
responses: OpenApi.responses({
|
|
310
|
+
errors: {
|
|
311
|
+
400: { codes: ['query_invalid'], description: 'Invalid query parameters.' },
|
|
312
|
+
404: {
|
|
313
|
+
codes: ['organization_not_found'],
|
|
314
|
+
description: 'No accessible organization was found for this id.',
|
|
315
|
+
},
|
|
316
|
+
501: {
|
|
317
|
+
codes: ['analytics_unconfigured'],
|
|
318
|
+
description: 'Usage analytics is not configured on this deployment.',
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
success: {
|
|
322
|
+
description: 'The request usage.',
|
|
323
|
+
schema: schema.getRequestUsage.Response,
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
326
|
+
summary: 'Get request usage',
|
|
327
|
+
tags: ['Usage'],
|
|
328
|
+
}),
|
|
329
|
+
async (c) => {
|
|
330
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
331
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
332
|
+
if (OpenApi.narrowValidation)
|
|
333
|
+
return OpenApi.validationError(c, {
|
|
334
|
+
code: 'param_invalid',
|
|
335
|
+
message: 'Check the path parameters and try again.',
|
|
336
|
+
})
|
|
337
|
+
if (OpenApi.narrowValidation)
|
|
338
|
+
return OpenApi.validationError(c, {
|
|
339
|
+
code: 'query_invalid',
|
|
340
|
+
message: 'Check the query parameters and try again.',
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
const analytics = c.get('analytics')
|
|
344
|
+
if (!analytics) return analyticsUnconfigured(c)
|
|
345
|
+
|
|
346
|
+
const query = c.req.valid('query')
|
|
347
|
+
const to = new Date(Date.parse(query.to ?? new Date().toISOString())).toISOString()
|
|
348
|
+
const lookback = query.interval === 'day' ? 30 * dayMs : 24 * hourMs
|
|
349
|
+
const from = new Date(Date.parse(query.from ?? new Date(Date.parse(to) - lookback).toISOString())).toISOString() // prettier-ignore
|
|
350
|
+
if (Date.parse(from) > Date.parse(to))
|
|
351
|
+
return Response.error(c, {
|
|
352
|
+
code: 'query_invalid',
|
|
353
|
+
message: '`from` must be before or equal to `to`.',
|
|
354
|
+
status: 400,
|
|
355
|
+
})
|
|
356
|
+
if (Date.parse(to) - Date.parse(from) > (maxBuckets - 1) * intervalMs(query.interval))
|
|
357
|
+
return Response.error(c, {
|
|
358
|
+
code: 'query_invalid',
|
|
359
|
+
message: `Usage series are limited to ${maxBuckets} buckets.`,
|
|
360
|
+
status: 400,
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
const environment =
|
|
365
|
+
query.environment === undefined ? {} : { environment: query.environment }
|
|
366
|
+
const keyIds = await legacyKeyIds(c, {
|
|
367
|
+
environment: query.environment,
|
|
368
|
+
projectId: query.projectId,
|
|
369
|
+
})
|
|
370
|
+
return c.json(
|
|
371
|
+
Response.validated(
|
|
372
|
+
schema.getRequestUsage.Response,
|
|
373
|
+
await RequestEvents.readProjectUsage(Analytics.get(analytics), {
|
|
374
|
+
attributions: [
|
|
375
|
+
// `projectId` present scopes to one project; absent covers the
|
|
376
|
+
// whole org. Either way legacy null-project rows are folded in
|
|
377
|
+
// by explicit key id below.
|
|
378
|
+
{
|
|
379
|
+
...environment,
|
|
380
|
+
...(query.projectId === undefined ? {} : { projectId: query.projectId }),
|
|
381
|
+
},
|
|
382
|
+
...(keyIds.length > 0
|
|
383
|
+
? [{ apiKeyIds: keyIds, ...environment, projectId: null }]
|
|
384
|
+
: []),
|
|
385
|
+
],
|
|
386
|
+
from,
|
|
387
|
+
interval: query.interval,
|
|
388
|
+
orgId: Auth.org(c).id,
|
|
389
|
+
to,
|
|
390
|
+
}),
|
|
391
|
+
),
|
|
392
|
+
200,
|
|
393
|
+
)
|
|
394
|
+
} catch (cause) {
|
|
395
|
+
return Response.upstream(c, cause)
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
)
|
|
399
|
+
.get(
|
|
400
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/usage/sponsorships',
|
|
401
|
+
Auth.policy({ session: true }),
|
|
402
|
+
Auth.ensureOrg(),
|
|
403
|
+
OpenApi.validate('param', schema.getSponsorshipUsage.Params, {
|
|
404
|
+
code: 'param_invalid',
|
|
405
|
+
message: 'Check the path parameters and try again.',
|
|
406
|
+
}),
|
|
407
|
+
OpenApi.validate('query', schema.getSponsorshipUsage.Query, {
|
|
408
|
+
code: 'query_invalid',
|
|
409
|
+
message: 'Check the query parameters and try again.',
|
|
410
|
+
}),
|
|
411
|
+
OpenApi.describeRoute({
|
|
412
|
+
operationId: 'getSponsorshipUsage',
|
|
413
|
+
responses: OpenApi.responses({
|
|
414
|
+
errors: {
|
|
415
|
+
404: 'No accessible organization was found for this id.',
|
|
416
|
+
},
|
|
417
|
+
success: {
|
|
418
|
+
description: "The organization's sponsorship usage series.",
|
|
419
|
+
schema: schema.getSponsorshipUsage.Response,
|
|
420
|
+
},
|
|
421
|
+
}),
|
|
422
|
+
summary: 'Get sponsorship usage',
|
|
423
|
+
tags: ['Usage'],
|
|
424
|
+
}),
|
|
425
|
+
async (c) => {
|
|
426
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
427
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
428
|
+
if (OpenApi.narrowValidation)
|
|
429
|
+
return OpenApi.validationError(c, {
|
|
430
|
+
code: 'param_invalid',
|
|
431
|
+
message: 'Check the path parameters and try again.',
|
|
432
|
+
})
|
|
433
|
+
if (OpenApi.narrowValidation)
|
|
434
|
+
return OpenApi.validationError(c, {
|
|
435
|
+
code: 'query_invalid',
|
|
436
|
+
message: 'Check the query parameters and try again.',
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
const query = c.req.valid('query')
|
|
440
|
+
const to = query.to ? new Date(query.to) : new Date()
|
|
441
|
+
const from = query.from ? new Date(query.from) : new Date(to.getTime() - 30 * dayMs)
|
|
442
|
+
if (from.getTime() >= to.getTime()) return windowInvalid(c, '`from` must be before `to`')
|
|
443
|
+
// Bound the scan, not just the output: 31 days of hours is 744 buckets;
|
|
444
|
+
// wider intervals cap at 400 days regardless of bucket count.
|
|
445
|
+
const maxDays = query.interval === 'hour' ? 31 : 400
|
|
446
|
+
if (to.getTime() - from.getTime() > maxDays * dayMs)
|
|
447
|
+
return windowInvalid(
|
|
448
|
+
c,
|
|
449
|
+
`The window may span at most ${maxDays} days at \`${query.interval}\` interval`,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
const buckets = await SponsoredTransactions.usage(Db.get(c.get('dbCached')), {
|
|
454
|
+
environment: query.environment,
|
|
455
|
+
from: from.toISOString(),
|
|
456
|
+
interval: query.interval,
|
|
457
|
+
orgId: Auth.org(c).id,
|
|
458
|
+
projectId: query.projectId,
|
|
459
|
+
to: to.toISOString(),
|
|
460
|
+
})
|
|
461
|
+
// Sponsored fees settle in USD: the relay refuses non-USD fee tokens
|
|
462
|
+
// on mainnet and rows snapshot `currency`, so one constant is correct
|
|
463
|
+
// until multi-currency sponsorship ships (then group by currency).
|
|
464
|
+
const currency = 'usd'
|
|
465
|
+
return c.json(
|
|
466
|
+
Response.validated(schema.getSponsorshipUsage.Response, {
|
|
467
|
+
data: buckets.map((bucket) => ({
|
|
468
|
+
count: bucket.count,
|
|
469
|
+
feeTotal: { amount: core_Billing.fromBaseUnits(bucket.feeTotal), currency },
|
|
470
|
+
timestamp: bucket.timestamp,
|
|
471
|
+
})),
|
|
472
|
+
}),
|
|
473
|
+
200,
|
|
474
|
+
)
|
|
475
|
+
} catch (cause) {
|
|
476
|
+
return Response.upstream(c, cause)
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** One day in milliseconds; window defaults and caps derive from it. */
|
|
483
|
+
const dayMs = 24 * 60 * 60 * 1000
|
|
484
|
+
|
|
485
|
+
/** One hour in milliseconds. */
|
|
486
|
+
const hourMs = 60 * 60 * 1000
|
|
487
|
+
|
|
488
|
+
/** Upper bound on request-usage series length. */
|
|
489
|
+
const maxBuckets = 200
|
|
490
|
+
|
|
491
|
+
/** API-key ids minted before project attribution; matched by explicit id. */
|
|
492
|
+
async function legacyKeyIds(
|
|
493
|
+
c: Context<Environment>,
|
|
494
|
+
options: {
|
|
495
|
+
environment: 'production' | 'sandbox' | undefined
|
|
496
|
+
projectId: string | undefined
|
|
497
|
+
},
|
|
498
|
+
): Promise<readonly string[]> {
|
|
499
|
+
const kv = c.get('kv')
|
|
500
|
+
if (!kv) return []
|
|
501
|
+
const records = await ApiKeys.listByOrg(
|
|
502
|
+
kv.store,
|
|
503
|
+
Auth.org(c).id,
|
|
504
|
+
options.projectId === undefined ? {} : { projectId: options.projectId },
|
|
505
|
+
)
|
|
506
|
+
return records
|
|
507
|
+
.filter(
|
|
508
|
+
(record) => options.environment === undefined || record.environment === options.environment,
|
|
509
|
+
) // prettier-ignore
|
|
510
|
+
.map((record) => record.id)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function analyticsUnconfigured(c: Context<Environment>) {
|
|
514
|
+
return Response.error(c, {
|
|
515
|
+
code: 'analytics_unconfigured',
|
|
516
|
+
message: 'Usage analytics is not configured on this deployment',
|
|
517
|
+
status: 501,
|
|
518
|
+
})
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function intervalMs(interval: 'day' | 'hour') {
|
|
522
|
+
return interval === 'day' ? dayMs : hourMs
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function windowInvalid(c: Context<Environment>, message: string) {
|
|
526
|
+
return Response.error(c, { code: 'query_invalid', message, status: 400 })
|
|
527
|
+
}
|