tapimo 0.4.0 → 0.4.3
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 +1 -1
- package/dist/ApiKey.d.ts +1 -9
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +2 -3
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +53 -27
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +32 -17
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +2451 -1533
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +23 -9
- package/dist/App.js.map +1 -1
- package/dist/Assets.d.ts +10 -0
- package/dist/Assets.d.ts.map +1 -1
- package/dist/Assets.js +4 -0
- package/dist/Assets.js.map +1 -1
- package/dist/Auth.d.ts +2 -1
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js +2 -1
- package/dist/Auth.js.map +1 -1
- package/dist/Scope.d.ts +40 -15
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +44 -13
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +560 -9
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +38 -6
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +10 -24
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +10 -3
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +833 -0
- package/dist/admin/apps/organizations.d.ts.map +1 -0
- package/dist/admin/apps/organizations.js +733 -0
- package/dist/admin/apps/organizations.js.map +1 -0
- package/dist/admin/apps/scopes.d.ts +8 -0
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +53 -13
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +10 -0
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +8 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +9 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +14 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +1354 -984
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +20 -3
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingRouteProviders.d.ts +94 -5
- package/dist/apps/data/FundingRouteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingRouteProviders.js +196 -5
- package/dist/apps/data/FundingRouteProviders.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +38 -38
- package/dist/apps/data/routes/addresses.d.ts +24 -24
- package/dist/apps/data/routes/balances.d.ts +45 -45
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/exchanges.d.ts +453 -453
- package/dist/apps/data/routes/fee-amm.d.ts +101 -101
- package/dist/apps/data/routes/funding.d.ts +730 -138
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +234 -0
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +5 -5
- package/dist/apps/data/routes/rpc.d.ts +31 -31
- package/dist/apps/data/routes/verified-tokens.d.ts +81 -81
- package/dist/apps/management/App.d.ts +1156 -615
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +2 -2
- package/dist/apps/management/Billing.d.ts +3 -0
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +7 -2
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +106 -90
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +41 -30
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +278 -146
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +14 -14
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +93 -20
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +12 -15
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +13 -13
- package/dist/apps/management/routes/members.d.ts +89 -18
- package/dist/apps/management/routes/members.d.ts.map +1 -1
- package/dist/apps/management/routes/members.js +10 -10
- package/dist/apps/management/routes/members.js.map +1 -1
- package/dist/apps/management/routes/orgs.d.ts +130 -70
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +19 -19
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +137 -48
- package/dist/apps/management/routes/projects.d.ts.map +1 -1
- package/dist/apps/management/routes/projects.js +12 -13
- package/dist/apps/management/routes/projects.js.map +1 -1
- package/dist/apps/management/routes/scopes.d.ts +14 -28
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +6 -7
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +63 -19
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +9 -10
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +35 -3
- package/dist/apps/mcp.js.map +1 -1
- package/dist/apps/relay/App.d.ts +26 -4
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +17 -14
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +5 -3
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +52 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +13 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +16 -1
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/adminAuditLogs.d.ts +27 -0
- package/dist/db/tables/adminAuditLogs.d.ts.map +1 -0
- package/dist/db/tables/adminAuditLogs.js +19 -0
- package/dist/db/tables/adminAuditLogs.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +1 -1
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/memberships.d.ts +32 -4
- package/dist/db/tables/memberships.d.ts.map +1 -1
- package/dist/db/tables/memberships.js +31 -0
- package/dist/db/tables/memberships.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +43 -1
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +103 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +25 -0
- package/dist/db/tables/projects.d.ts.map +1 -1
- package/dist/db/tables/projects.js +22 -0
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/webhookDeliveries.d.ts +26 -0
- package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
- package/dist/db/tables/webhookDeliveries.js +37 -0
- package/dist/db/tables/webhookDeliveries.js.map +1 -1
- package/dist/handlers/relay.d.ts +13 -10
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +46 -16
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +13 -18
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +78 -58
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cursor.d.ts +1 -1
- package/dist/internal/Cursor.d.ts.map +1 -1
- package/dist/internal/Cursor.js +4 -0
- package/dist/internal/Cursor.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +2 -0
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/FundingRoutes.d.ts +170 -0
- package/dist/internal/FundingRoutes.d.ts.map +1 -1
- package/dist/internal/FundingRoutes.js +68 -6
- package/dist/internal/FundingRoutes.js.map +1 -1
- package/dist/internal/Log.d.ts +16 -1
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +5 -3
- package/dist/internal/Log.js.map +1 -1
- package/package.json +2 -2
- package/src/ApiKey.ts +2 -3
- package/src/ApiKeys.ts +95 -17
- package/src/App.test.ts +44 -2
- package/src/App.ts +29 -9
- package/src/Assets.ts +8 -0
- package/src/Auth.test-d.ts +36 -0
- package/src/Auth.ts +20 -1
- package/src/Client.test-d.ts +64 -17
- package/src/Scope.test.ts +34 -0
- package/src/Scope.ts +53 -17
- package/src/admin/App.test.ts +33 -3
- package/src/admin/App.ts +49 -14
- package/src/admin/apps/api-keys.ts +10 -3
- package/src/admin/apps/organizations.test.ts +455 -0
- package/src/admin/apps/organizations.ts +953 -0
- package/src/admin/apps/scopes.test.ts +10 -0
- package/src/admin/ui/plugin.ts +1 -1
- package/src/admin/ui/src/components/MobileProfile.tsx +2 -0
- package/src/admin/ui/src/components/ThemeToggle.tsx +20 -0
- package/src/admin/ui/src/lib/api-keys.ts +36 -19
- package/src/admin/ui/src/lib/config.ts +2 -3
- package/src/admin/ui/src/lib/organizations.test.ts +89 -0
- package/src/admin/ui/src/lib/organizations.ts +262 -0
- package/src/admin/ui/src/lib/query-client.ts +3 -1
- package/src/admin/ui/src/lib/theme.ts +57 -0
- package/src/admin/ui/src/routeTree.gen.ts +47 -4
- package/src/admin/ui/src/routes/__root.tsx +18 -3
- package/src/admin/ui/src/routes/api-keys.tsx +52 -7
- package/src/admin/ui/src/routes/index.tsx +1 -1
- package/src/admin/ui/src/routes/organizations.tsx +158 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +710 -0
- package/src/admin/ui/src/start.ts +6 -0
- package/src/admin/ui.generated.ts +63 -13
- package/src/analytics/Analytics.ts +25 -0
- package/src/analytics/tables/requestEvents.ts +33 -0
- package/src/apps/composition.test.ts +82 -2
- package/src/apps/data/App.ts +24 -3
- package/src/apps/data/FundingRouteProviders.test.ts +204 -0
- package/src/apps/data/FundingRouteProviders.ts +294 -9
- package/src/apps/data/routes/funding.test.ts +90 -23
- package/src/apps/data/routes/funding.ts +315 -0
- package/src/apps/data/routes/rpc.test.ts +33 -0
- package/src/apps/management/App.ts +2 -2
- package/src/apps/management/Billing.ts +10 -2
- package/src/apps/management/routes/api-keys.test.ts +137 -1
- package/src/apps/management/routes/api-keys.ts +63 -38
- package/src/apps/management/routes/billing.ts +14 -14
- package/src/apps/management/routes/invitations.test.ts +102 -1
- package/src/apps/management/routes/invitations.ts +13 -15
- package/src/apps/management/routes/members.ts +10 -10
- package/src/apps/management/routes/orgs.test.ts +78 -16
- package/src/apps/management/routes/orgs.ts +21 -20
- package/src/apps/management/routes/projects.ts +12 -13
- package/src/apps/management/routes/scopes.test.ts +16 -0
- package/src/apps/management/routes/scopes.ts +6 -7
- package/src/apps/management/routes/usage.ts +9 -14
- package/src/apps/mcp.test.ts +25 -1
- package/src/apps/mcp.ts +43 -3
- package/src/apps/relay/App.test.ts +23 -18
- package/src/apps/relay/App.ts +35 -14
- package/src/db/Db.ts +59 -3
- package/src/db/Schema.ts +20 -1
- package/src/db/tables/adminAuditLogs.ts +47 -0
- package/src/db/tables/invitations.ts +1 -1
- package/src/db/tables/memberships.ts +59 -3
- package/src/db/tables/organizations.ts +148 -1
- package/src/db/tables/projects.ts +47 -0
- package/src/db/tables/webhookDeliveries.ts +83 -0
- package/src/handlers/relay.test-d.ts +8 -0
- package/src/handlers/relay.test.ts +2 -2
- package/src/handlers/relay.ts +62 -22
- package/src/internal/Auth.test.ts +174 -7
- package/src/internal/Auth.ts +90 -62
- package/src/internal/Cursor.test.ts +10 -0
- package/src/internal/Cursor.ts +5 -1
- package/src/internal/EdgeCache.test.ts +11 -0
- package/src/internal/EdgeCache.ts +2 -0
- package/src/internal/FundingRoutes.test.ts +26 -0
- package/src/internal/FundingRoutes.ts +187 -18
- package/src/internal/Log.test.ts +41 -3
- package/src/internal/Log.ts +23 -4
package/src/Client.test-d.ts
CHANGED
|
@@ -182,7 +182,7 @@ describe('narrows responses by status', () => {
|
|
|
182
182
|
param: { orgId: 'org_test' },
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
185
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | PublicAccessStatus>()
|
|
186
186
|
|
|
187
187
|
switch (res.status) {
|
|
188
188
|
case 200: {
|
|
@@ -206,7 +206,7 @@ describe('narrows responses by status', () => {
|
|
|
206
206
|
param: { orgId: 'org_test' },
|
|
207
207
|
})
|
|
208
208
|
|
|
209
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
209
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
210
210
|
|
|
211
211
|
switch (res.status) {
|
|
212
212
|
case 200: {
|
|
@@ -230,7 +230,7 @@ describe('narrows responses by status', () => {
|
|
|
230
230
|
param: { orgId: 'org_test' },
|
|
231
231
|
})
|
|
232
232
|
|
|
233
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
233
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
234
234
|
|
|
235
235
|
switch (res.status) {
|
|
236
236
|
case 200: {
|
|
@@ -257,7 +257,7 @@ describe('narrows responses by status', () => {
|
|
|
257
257
|
param: { orgId: 'org_test' },
|
|
258
258
|
})
|
|
259
259
|
|
|
260
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
260
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
261
261
|
|
|
262
262
|
switch (res.status) {
|
|
263
263
|
case 200: {
|
|
@@ -284,7 +284,7 @@ describe('narrows responses by status', () => {
|
|
|
284
284
|
param: { orgId: 'org_test' },
|
|
285
285
|
})
|
|
286
286
|
|
|
287
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
287
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
288
288
|
|
|
289
289
|
switch (res.status) {
|
|
290
290
|
case 200: {
|
|
@@ -310,7 +310,7 @@ describe('narrows responses by status', () => {
|
|
|
310
310
|
param: { orgId: 'org_test' },
|
|
311
311
|
})
|
|
312
312
|
|
|
313
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
313
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
314
314
|
|
|
315
315
|
switch (res.status) {
|
|
316
316
|
case 200: {
|
|
@@ -338,7 +338,7 @@ describe('narrows responses by status', () => {
|
|
|
338
338
|
':methodId{pm_[A-Za-z0-9_-]+}'
|
|
339
339
|
].$delete({ param: { methodId: 'pm_test', orgId: 'org_test' } })
|
|
340
340
|
|
|
341
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
341
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
342
342
|
|
|
343
343
|
switch (res.status) {
|
|
344
344
|
case 200: {
|
|
@@ -364,7 +364,7 @@ describe('narrows responses by status', () => {
|
|
|
364
364
|
param: { orgId: 'org_test' },
|
|
365
365
|
})
|
|
366
366
|
|
|
367
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
367
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
368
368
|
|
|
369
369
|
switch (res.status) {
|
|
370
370
|
case 200: {
|
|
@@ -388,7 +388,7 @@ describe('narrows responses by status', () => {
|
|
|
388
388
|
':projectId{prj_[A-Za-z0-9_-]+}'
|
|
389
389
|
].$get({ param: { orgId: 'org_test', projectId: 'prj_test' } })
|
|
390
390
|
|
|
391
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
391
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | PublicAccessStatus>()
|
|
392
392
|
|
|
393
393
|
switch (res.status) {
|
|
394
394
|
case 200: {
|
|
@@ -414,7 +414,7 @@ describe('narrows responses by status', () => {
|
|
|
414
414
|
':projectId{prj_[A-Za-z0-9_-]+}'
|
|
415
415
|
].$delete({ param: { orgId: 'org_test', projectId: 'prj_test' } })
|
|
416
416
|
|
|
417
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
417
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
418
418
|
|
|
419
419
|
switch (res.status) {
|
|
420
420
|
case 200: {
|
|
@@ -464,7 +464,7 @@ describe('narrows responses by status', () => {
|
|
|
464
464
|
param: { orgId: 'org_test' },
|
|
465
465
|
})
|
|
466
466
|
|
|
467
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
467
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
468
468
|
|
|
469
469
|
switch (res.status) {
|
|
470
470
|
case 200: {
|
|
@@ -487,7 +487,7 @@ describe('narrows responses by status', () => {
|
|
|
487
487
|
param: { keyId: 'key_test', orgId: 'org_test', projectId: 'prj_test' },
|
|
488
488
|
})
|
|
489
489
|
|
|
490
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
490
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
491
491
|
|
|
492
492
|
switch (res.status) {
|
|
493
493
|
case 404: {
|
|
@@ -511,7 +511,7 @@ describe('narrows responses by status', () => {
|
|
|
511
511
|
query: { projectId: 'prj_test' },
|
|
512
512
|
})
|
|
513
513
|
|
|
514
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
514
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 501 | 502 | PublicAccessStatus>()
|
|
515
515
|
|
|
516
516
|
switch (res.status) {
|
|
517
517
|
case 200: {
|
|
@@ -545,7 +545,7 @@ describe('narrows responses by status', () => {
|
|
|
545
545
|
param: { orgId: 'org_test' },
|
|
546
546
|
})
|
|
547
547
|
|
|
548
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
548
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 502 | PublicAccessStatus>()
|
|
549
549
|
|
|
550
550
|
switch (res.status) {
|
|
551
551
|
case 200: {
|
|
@@ -563,7 +563,7 @@ describe('narrows responses by status', () => {
|
|
|
563
563
|
':userId{usr_[A-Za-z0-9_-]+}'
|
|
564
564
|
].$patch({ json: { role: 'admin' }, param: { orgId: 'org_test', userId: 'usr_test' } })
|
|
565
565
|
|
|
566
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
566
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 404 | 409 | 502 | PublicAccessStatus>()
|
|
567
567
|
|
|
568
568
|
switch (res.status) {
|
|
569
569
|
case 409: {
|
|
@@ -627,7 +627,7 @@ describe('narrows responses by status', () => {
|
|
|
627
627
|
const client = Client.create()
|
|
628
628
|
const res = await client.v1.orgs.$get()
|
|
629
629
|
|
|
630
|
-
expectTypeOf(res.status).toEqualTypeOf<200 |
|
|
630
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 502 | PublicAccessStatus>()
|
|
631
631
|
|
|
632
632
|
switch (res.status) {
|
|
633
633
|
case 200: {
|
|
@@ -640,7 +640,7 @@ describe('narrows responses by status', () => {
|
|
|
640
640
|
}
|
|
641
641
|
case 403: {
|
|
642
642
|
const json = await res.json()
|
|
643
|
-
expectTypeOf(json.error.code).toEqualTypeOf<'
|
|
643
|
+
expectTypeOf(json.error.code).toEqualTypeOf<'api_key_forbidden'>()
|
|
644
644
|
expectTypeOf(json.error.message).toEqualTypeOf<string>()
|
|
645
645
|
void json
|
|
646
646
|
return
|
|
@@ -1221,6 +1221,53 @@ describe('narrows responses by status', () => {
|
|
|
1221
1221
|
}
|
|
1222
1222
|
})
|
|
1223
1223
|
|
|
1224
|
+
test('POST /v1/funding/routes/quote', async () => {
|
|
1225
|
+
const client = Client.create()
|
|
1226
|
+
const res = await client.v1.funding.routes.quote.$post({
|
|
1227
|
+
json: {
|
|
1228
|
+
depositor: '0x1111111111111111111111111111111111111111',
|
|
1229
|
+
provider: 'across',
|
|
1230
|
+
sourceAmount: '1000000',
|
|
1231
|
+
sourceChain: 'base',
|
|
1232
|
+
sourceToken: 'USDC',
|
|
1233
|
+
},
|
|
1234
|
+
})
|
|
1235
|
+
|
|
1236
|
+
expectTypeOf(res.status).toEqualTypeOf<200 | 400 | 404 | 501 | 502 | PaidAccessStatus>()
|
|
1237
|
+
|
|
1238
|
+
switch (res.status) {
|
|
1239
|
+
case 200: {
|
|
1240
|
+
const json = await res.json()
|
|
1241
|
+
expectTypeOf(json).toEqualTypeOf<
|
|
1242
|
+
z.output<typeof Funding.schema.quoteFundingRoute.Response>
|
|
1243
|
+
>()
|
|
1244
|
+
return
|
|
1245
|
+
}
|
|
1246
|
+
case 400: {
|
|
1247
|
+
const json = await res.json()
|
|
1248
|
+
expectTypeOf(json.error.code).toEqualTypeOf<Access400<'body_invalid'>>()
|
|
1249
|
+
return
|
|
1250
|
+
}
|
|
1251
|
+
case 404: {
|
|
1252
|
+
const json = await res.json()
|
|
1253
|
+
expectTypeOf(json.error.code).toEqualTypeOf<'quote_unavailable' | 'route_not_found'>()
|
|
1254
|
+
return
|
|
1255
|
+
}
|
|
1256
|
+
case 501: {
|
|
1257
|
+
const json = await res.json()
|
|
1258
|
+
expectTypeOf(json.error.code).toEqualTypeOf<'provider_unconfigured'>()
|
|
1259
|
+
return
|
|
1260
|
+
}
|
|
1261
|
+
case 502: {
|
|
1262
|
+
const json = await res.json()
|
|
1263
|
+
expectTypeOf(json.error.code).toEqualTypeOf<
|
|
1264
|
+
'provider_error' | 'provider_rate_limited' | 'provider_timeout'
|
|
1265
|
+
>()
|
|
1266
|
+
return
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
})
|
|
1270
|
+
|
|
1224
1271
|
test('GET /v1/funding/chains', async () => {
|
|
1225
1272
|
const client = Client.create()
|
|
1226
1273
|
const res = await client.v1.funding.chains.$get()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as Scope from './Scope.js'
|
|
2
|
+
|
|
3
|
+
describe('extend', () => {
|
|
4
|
+
test('appends host scopes to the built-in catalog', () => {
|
|
5
|
+
expect(
|
|
6
|
+
Scope.extend([
|
|
7
|
+
{
|
|
8
|
+
description: 'Read project accounts.',
|
|
9
|
+
scope: 'accounts:read',
|
|
10
|
+
selfServe: true,
|
|
11
|
+
},
|
|
12
|
+
]),
|
|
13
|
+
).toEqual([
|
|
14
|
+
...Scope.catalog,
|
|
15
|
+
{
|
|
16
|
+
description: 'Read project accounts.',
|
|
17
|
+
scope: 'accounts:read',
|
|
18
|
+
selfServe: true,
|
|
19
|
+
},
|
|
20
|
+
])
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('rejects duplicate scope identifiers', () => {
|
|
24
|
+
expect(() =>
|
|
25
|
+
Scope.extend([
|
|
26
|
+
{
|
|
27
|
+
description: 'Duplicate data scope.',
|
|
28
|
+
scope: 'data:read',
|
|
29
|
+
selfServe: true,
|
|
30
|
+
},
|
|
31
|
+
]),
|
|
32
|
+
).toThrowErrorMatchingInlineSnapshot(`[Error: Duplicate scope \`data:read\`.]`)
|
|
33
|
+
})
|
|
34
|
+
})
|
package/src/Scope.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* admin tooling validate scopes against the same list the server enforces.
|
|
2
|
+
* The built-in API-key scope vocabulary. Hosts append entries through
|
|
3
|
+
* `App.create({ scopes })`; the merged catalog drives discovery, minting, and
|
|
4
|
+
* API-key validation.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -13,20 +12,18 @@
|
|
|
13
12
|
export const wildcard = '*'
|
|
14
13
|
|
|
15
14
|
/** Catalog entry describing an issuable API-key scope. */
|
|
16
|
-
type Entry = {
|
|
15
|
+
export type Entry = {
|
|
17
16
|
/** Human-readable explanation of what the scope grants. */
|
|
18
17
|
description: string
|
|
19
18
|
/** Scope identifier used in a key's `scopes` and in route policies. */
|
|
20
19
|
scope: string
|
|
21
|
-
/** Whether
|
|
20
|
+
/** Whether an eligible session may self-mint this scope (else super-admin-only). */
|
|
22
21
|
selfServe: boolean
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
|
-
* The issuable API-key
|
|
27
|
-
*
|
|
28
|
-
* set; {@link wildcard} (`'*'`) is an implicit grant-all and is intentionally
|
|
29
|
-
* not listed as an issuable scope.
|
|
25
|
+
* The built-in issuable API-key scopes. {@link wildcard} (`'*'`) is an implicit
|
|
26
|
+
* grant-all and is intentionally not listed as an issuable scope.
|
|
30
27
|
*/
|
|
31
28
|
export const catalog = [
|
|
32
29
|
{
|
|
@@ -39,6 +36,17 @@ export const catalog = [
|
|
|
39
36
|
scope: 'indexer:query',
|
|
40
37
|
selfServe: true,
|
|
41
38
|
},
|
|
39
|
+
{
|
|
40
|
+
description: 'Read organization resources across projects and environments.',
|
|
41
|
+
scope: 'management:read',
|
|
42
|
+
selfServe: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
description:
|
|
46
|
+
'Create, update, and delete organization resources across projects and environments.',
|
|
47
|
+
scope: 'management:write',
|
|
48
|
+
selfServe: true,
|
|
49
|
+
},
|
|
42
50
|
{
|
|
43
51
|
description: 'Fill and submit transactions through the relay.',
|
|
44
52
|
scope: 'rpc-relay:read',
|
|
@@ -61,16 +69,44 @@ export const catalog = [
|
|
|
61
69
|
},
|
|
62
70
|
] as const satisfies readonly Entry[]
|
|
63
71
|
|
|
64
|
-
/** Issuable API-key scope identifier
|
|
65
|
-
export type Id = (typeof catalog)[number]['scope']
|
|
72
|
+
/** Issuable API-key scope identifier, including host-defined scopes. */
|
|
73
|
+
export type Id = (typeof catalog)[number]['scope'] | (string & {})
|
|
74
|
+
|
|
75
|
+
/** Scope catalog used by API-key issuance and discovery. */
|
|
76
|
+
export type Catalog = readonly Entry[]
|
|
66
77
|
|
|
67
78
|
/**
|
|
68
|
-
* Scopes
|
|
69
|
-
* the catalog's `selfServe` flag.
|
|
70
|
-
*
|
|
71
|
-
* paid APIs for free. Webhooks stay super-admin-only, as does {@link wildcard}
|
|
72
|
-
* (intentionally absent from the catalog).
|
|
79
|
+
* Scopes an eligible session may self-mint through the developer platform,
|
|
80
|
+
* derived from the catalog's `selfServe` flag. Route-specific ownership rules
|
|
81
|
+
* may narrow issuance. Webhooks and {@link wildcard} stay super-admin-only.
|
|
73
82
|
*/
|
|
74
83
|
export const selfServe: readonly Id[] = catalog
|
|
75
84
|
.filter((entry) => entry.selfServe)
|
|
76
85
|
.map((entry) => entry.scope)
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extends the built-in catalog with host-defined scopes.
|
|
89
|
+
*
|
|
90
|
+
* @param entries - Host-defined scope entries.
|
|
91
|
+
* @returns The merged scope catalog.
|
|
92
|
+
*/
|
|
93
|
+
export function extend(entries: readonly Entry[] = []): Catalog {
|
|
94
|
+
const identifiers = new Set<string>()
|
|
95
|
+
const result = [...catalog, ...entries]
|
|
96
|
+
for (const entry of result) {
|
|
97
|
+
if (!entry.scope.trim()) throw new Error('Scope identifier must not be empty.')
|
|
98
|
+
if (identifiers.has(entry.scope)) throw new Error(`Duplicate scope \`${entry.scope}\`.`)
|
|
99
|
+
identifiers.add(entry.scope)
|
|
100
|
+
}
|
|
101
|
+
return result
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Returns whether a catalog contains a scope identifier. */
|
|
105
|
+
export function includes(catalog: Catalog, scope: string): scope is Id {
|
|
106
|
+
return catalog.some((entry) => entry.scope === scope)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Returns the self-issuable identifiers in a scope catalog. */
|
|
110
|
+
export function selfServeFrom(catalog: Catalog): readonly Id[] {
|
|
111
|
+
return catalog.filter((entry) => entry.selfServe).map((entry) => entry.scope)
|
|
112
|
+
}
|
package/src/admin/App.test.ts
CHANGED
|
@@ -18,6 +18,10 @@ describe('create', () => {
|
|
|
18
18
|
method: 'POST',
|
|
19
19
|
}),
|
|
20
20
|
new Request('http://admin/api-keys/key_x', { method: 'DELETE' }),
|
|
21
|
+
new Request('http://admin/organizations'),
|
|
22
|
+
new Request('http://admin/organizations/org_x'),
|
|
23
|
+
new Request('http://admin/organizations/org_x/members'),
|
|
24
|
+
new Request('http://admin/organizations/org_x/projects'),
|
|
21
25
|
new Request('http://admin/verified-tokens?chainId=42431', {
|
|
22
26
|
body: JSON.stringify({ tokens: [] }),
|
|
23
27
|
headers: { 'content-type': 'application/json' },
|
|
@@ -67,13 +71,37 @@ describe('create', () => {
|
|
|
67
71
|
describe('cache policy', () => {
|
|
68
72
|
test('every response is no-store (admin data is per-principal and mutating)', async () => {
|
|
69
73
|
const { app } = TestAdmin.setup()
|
|
70
|
-
for (const path of ['/scopes', '/api-keys', '/config.json']) {
|
|
74
|
+
for (const path of ['/scopes', '/api-keys', '/organizations', '/config.json']) {
|
|
71
75
|
const response = await app.request(`http://admin${path}`)
|
|
72
76
|
expect(response.headers.get('cache-control')).toBe('no-store')
|
|
73
77
|
}
|
|
74
78
|
})
|
|
75
79
|
})
|
|
76
80
|
|
|
81
|
+
describe('audit logging', () => {
|
|
82
|
+
test('records authenticated data access with actor, request id, route, and status', async () => {
|
|
83
|
+
const { app, db } = TestAdmin.setup({
|
|
84
|
+
identify: () => ({ email: 'ops@tempo.xyz' }),
|
|
85
|
+
})
|
|
86
|
+
const response = await app.request('http://admin/organizations?limit=5')
|
|
87
|
+
const records = await db.kysely
|
|
88
|
+
.selectFrom('admin_audit_logs')
|
|
89
|
+
.selectAll()
|
|
90
|
+
.orderBy('createdAt', 'desc')
|
|
91
|
+
.execute()
|
|
92
|
+
|
|
93
|
+
expect(response.status).toBe(200)
|
|
94
|
+
expect(records[0]).toMatchObject({
|
|
95
|
+
actor: 'ops@tempo.xyz',
|
|
96
|
+
method: 'GET',
|
|
97
|
+
path: '/organizations',
|
|
98
|
+
query: 'limit=5',
|
|
99
|
+
status: 200,
|
|
100
|
+
})
|
|
101
|
+
expect(records[0]?.requestId).toBeTruthy()
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
77
105
|
describe('GET /config.json', () => {
|
|
78
106
|
test('reports the signed-in identity and sign-in/out URLs', async () => {
|
|
79
107
|
const { app } = TestAdmin.setup({
|
|
@@ -120,8 +148,10 @@ describe('create', () => {
|
|
|
120
148
|
expect(response.headers.get('content-type')).toContain('text/html')
|
|
121
149
|
const html = await response.text()
|
|
122
150
|
expect(html).toContain('<div id="root">')
|
|
151
|
+
expect(html).not.toContain('data-theme="dark"')
|
|
152
|
+
expect(html).toContain("localStorage.getItem('tempo-api-admin.theme')")
|
|
123
153
|
// Standalone mount → `<base href="/">` so relative asset/API URLs resolve.
|
|
124
|
-
expect(html).toContain('<base href="/"/>')
|
|
154
|
+
expect(html).toContain('<base data-tempo-base="true" href="/"/>')
|
|
125
155
|
})
|
|
126
156
|
|
|
127
157
|
test('inlines the gated auth config into the shell (no bootstrap round trip)', async () => {
|
|
@@ -173,7 +203,7 @@ describe('create', () => {
|
|
|
173
203
|
expect(response.status).toBe(200)
|
|
174
204
|
// The base href is the mount root, not the deep link, so assets/API
|
|
175
205
|
// resolve under `/admin/` from any in-app route.
|
|
176
|
-
expect(await response.text()).toContain('<base href="/admin/"/>')
|
|
206
|
+
expect(await response.text()).toContain('<base data-tempo-base="true" href="/admin/"/>')
|
|
177
207
|
})
|
|
178
208
|
|
|
179
209
|
test('ui: false → no shell; `/` returns the JSON 404', async () => {
|
package/src/admin/App.ts
CHANGED
|
@@ -4,11 +4,14 @@ import { requestId, type RequestIdVariables } from 'hono/request-id'
|
|
|
4
4
|
|
|
5
5
|
import * as ApiKey from '../ApiKey.js'
|
|
6
6
|
import type * as Assets from '../Assets.js'
|
|
7
|
-
import type * as
|
|
7
|
+
import type * as Analytics from '../analytics/Analytics.js'
|
|
8
|
+
import * as Db from '../db/Db.js'
|
|
9
|
+
import * as AdminAuditLogs from '../db/tables/adminAuditLogs.js'
|
|
8
10
|
import type * as Store from '../internal/Store.js'
|
|
9
11
|
import * as Response from '../internal/Response.js'
|
|
10
12
|
|
|
11
13
|
import { apiKeys } from './apps/api-keys.js'
|
|
14
|
+
import { organizations } from './apps/organizations.js'
|
|
12
15
|
import { scopes } from './apps/scopes.js'
|
|
13
16
|
import { verifiedTokens } from './apps/verified-tokens.js'
|
|
14
17
|
import * as Ui from './ui.generated.js'
|
|
@@ -22,6 +25,8 @@ export type Identity = {
|
|
|
22
25
|
/** Hono environment for the admin app. */
|
|
23
26
|
export type Environment = {
|
|
24
27
|
Variables: RequestIdVariables & {
|
|
28
|
+
/** ClickHouse analytics source used by operational usage reads. */
|
|
29
|
+
analytics: Analytics.Source
|
|
25
30
|
/** Static-asset writer (e.g. the R2 icon bucket), when configured. */
|
|
26
31
|
assets: create.Assets | undefined
|
|
27
32
|
/** Authoritative Postgres store, or a per-request factory. Resolve at the leaf with `Db.get`. */
|
|
@@ -54,6 +59,7 @@ export function create(options: create.Options) {
|
|
|
54
59
|
app.use('*', async (c, next) => {
|
|
55
60
|
// Admin data is per-principal and mutating: never cache.
|
|
56
61
|
c.header('Cache-Control', 'no-store')
|
|
62
|
+
c.set('analytics', options.analytics)
|
|
57
63
|
c.set('assets', options.assets)
|
|
58
64
|
c.set('db', options.db)
|
|
59
65
|
c.set('kv', options.kv)
|
|
@@ -73,17 +79,18 @@ export function create(options: create.Options) {
|
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
// Renders the public SPA shell:
|
|
77
|
-
//
|
|
78
|
-
// `identity` is `null` when logged out). `<` is escaped to keep `<script>`.
|
|
82
|
+
// Renders the public SPA shell: stamps its hydration-safe base and auth
|
|
83
|
+
// placeholders with request values. `<` is escaped to keep the config script.
|
|
79
84
|
const serveShell = (c: Context<Environment>) => {
|
|
80
85
|
const mount = c.req.routePath.replace(/\*$/, '').replace(/\/$/, '')
|
|
81
86
|
const config = JSON.stringify(authConfig(c.get('identity'))).replaceAll('<', '\\u003c')
|
|
82
87
|
return c.html(
|
|
83
|
-
Ui.shell
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
Ui.shell
|
|
89
|
+
.replace(
|
|
90
|
+
'<base data-tempo-base="true" href="/"/>',
|
|
91
|
+
`<base data-tempo-base="true" href="${mount}/"/>`,
|
|
92
|
+
)
|
|
93
|
+
.replace('window.__TEMPO_API_CONFIG__=undefined', `window.__TEMPO_API_CONFIG__=${config}`),
|
|
87
94
|
)
|
|
88
95
|
}
|
|
89
96
|
|
|
@@ -106,20 +113,46 @@ export function create(options: create.Options) {
|
|
|
106
113
|
})
|
|
107
114
|
return next()
|
|
108
115
|
}
|
|
109
|
-
|
|
116
|
+
const protectedPaths = [
|
|
110
117
|
'/config.json',
|
|
111
118
|
'/api-keys',
|
|
112
119
|
'/api-keys/*',
|
|
120
|
+
'/organizations',
|
|
121
|
+
'/organizations/*',
|
|
113
122
|
'/scopes',
|
|
114
123
|
'/scopes/*',
|
|
115
124
|
'/verified-tokens',
|
|
116
125
|
'/verified-tokens/*',
|
|
117
|
-
]
|
|
118
|
-
|
|
126
|
+
] as const
|
|
127
|
+
for (const path of protectedPaths) app.use(path, requireAuth)
|
|
128
|
+
|
|
129
|
+
for (const path of protectedPaths)
|
|
130
|
+
app.use(path, async (c, next) => {
|
|
131
|
+
const identity = c.get('identity')
|
|
132
|
+
if (!identity) return
|
|
133
|
+
const search = new URL(c.req.url).searchParams
|
|
134
|
+
const record = (status: number) =>
|
|
135
|
+
AdminAuditLogs.insert(Db.get(c.get('db')), {
|
|
136
|
+
actor: identity.email,
|
|
137
|
+
method: c.req.method,
|
|
138
|
+
path: c.req.path,
|
|
139
|
+
query: search.size ? search.toString() : undefined,
|
|
140
|
+
requestId: c.get('requestId'),
|
|
141
|
+
status,
|
|
142
|
+
})
|
|
143
|
+
try {
|
|
144
|
+
await next()
|
|
145
|
+
} catch (cause) {
|
|
146
|
+
await record(500)
|
|
147
|
+
throw cause
|
|
148
|
+
}
|
|
149
|
+
await record(c.res.status)
|
|
150
|
+
})
|
|
119
151
|
|
|
120
152
|
const routed = app
|
|
121
153
|
.get('/config.json', (c) => c.json(authConfig(c.get('identity')), 200))
|
|
122
154
|
.route('/api-keys', apiKeys())
|
|
155
|
+
.route('/organizations', organizations())
|
|
123
156
|
.route('/scopes', scopes())
|
|
124
157
|
.route('/verified-tokens', verifiedTokens())
|
|
125
158
|
|
|
@@ -172,15 +205,17 @@ export declare namespace create {
|
|
|
172
205
|
|
|
173
206
|
/** Options for {@link create}. */
|
|
174
207
|
type Options = {
|
|
208
|
+
/** ClickHouse analytics source used by operational usage reads. */
|
|
209
|
+
analytics: Analytics.Source
|
|
175
210
|
/**
|
|
176
211
|
* Static-asset writer for logo uploads (shared with the main API's `assets`
|
|
177
212
|
* loader) to enable `PUT /verified-tokens/:address/logo`; omit for `404`.
|
|
178
213
|
*/
|
|
179
214
|
assets?: Assets | undefined
|
|
180
215
|
/**
|
|
181
|
-
* Authoritative Postgres store shared with the main API
|
|
182
|
-
*
|
|
183
|
-
*
|
|
216
|
+
* Authoritative Postgres store shared with the main API. Pass a long-lived
|
|
217
|
+
* `Db.postgres(...)` singleton on Node, or a factory
|
|
218
|
+
* (`() => Db.postgres(...)`) on Workers.
|
|
184
219
|
*/
|
|
185
220
|
db: Db.Source
|
|
186
221
|
/**
|
|
@@ -5,6 +5,7 @@ import * as ApiKeys from '../../ApiKeys.js'
|
|
|
5
5
|
import * as OpenApi from '../../internal/OpenApi.js'
|
|
6
6
|
import * as Response from '../../internal/Response.js'
|
|
7
7
|
import * as Schema from '../../internal/Schema.js'
|
|
8
|
+
import * as Scope from '../../Scope.js'
|
|
8
9
|
import type * as App from '../App.js'
|
|
9
10
|
|
|
10
11
|
/** Zod schemas owned by the admin API-keys handler. */
|
|
@@ -16,7 +17,11 @@ export namespace schema {
|
|
|
16
17
|
* server sets from the verified identity so it can't be spoofed).
|
|
17
18
|
*/
|
|
18
19
|
export const Body = Schema.describe(
|
|
19
|
-
z.omit(ApiKeys.schema.MintInput, { createdBy: true }),
|
|
20
|
+
z.extend(z.omit(ApiKeys.schema.MintInput, { createdBy: true }), {
|
|
21
|
+
scopes: z
|
|
22
|
+
.readonly(z.array(z.enum([...Scope.catalog.map((entry) => entry.scope), Scope.wildcard])))
|
|
23
|
+
.check(z.describe("Granted scopes. '*' grants all scopes.")),
|
|
24
|
+
}),
|
|
20
25
|
'Fields accepted when minting an API key.',
|
|
21
26
|
)
|
|
22
27
|
|
|
@@ -59,7 +64,7 @@ export namespace schema {
|
|
|
59
64
|
export const Body = Schema.describe(
|
|
60
65
|
z.object({
|
|
61
66
|
orgId: z.optional(z.string()).check(z.describe('New owning organization id (`org_…`).')),
|
|
62
|
-
projectId: z.optional(z.string()).check(z.describe('New
|
|
67
|
+
projectId: z.optional(z.string()).check(z.describe('New attributed project id (`prj_…`).')),
|
|
63
68
|
}),
|
|
64
69
|
'Attribution to apply to an API key.',
|
|
65
70
|
)
|
|
@@ -174,7 +179,9 @@ export function apiKeys() {
|
|
|
174
179
|
}),
|
|
175
180
|
async (c) => {
|
|
176
181
|
const { orgId } = c.req.valid('query')
|
|
177
|
-
const data =
|
|
182
|
+
const data = orgId
|
|
183
|
+
? await ApiKeys.listByOrg(c.get('kv').store, orgId)
|
|
184
|
+
: await ApiKeys.list(c.get('kv').store)
|
|
178
185
|
return c.json(Response.validated(schema.listApiKeys.Response, { data }))
|
|
179
186
|
},
|
|
180
187
|
)
|