@antseed/cli 0.1.178 → 0.1.180
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 +5 -0
- package/dist/buyer-identities/store.d.ts +39 -2
- package/dist/buyer-identities/store.d.ts.map +1 -1
- package/dist/buyer-identities/store.js +99 -10
- package/dist/buyer-identities/store.js.map +1 -1
- package/dist/cli/commands/apps/index.d.ts +42 -0
- package/dist/cli/commands/apps/index.d.ts.map +1 -0
- package/dist/cli/commands/apps/index.js +224 -0
- package/dist/cli/commands/apps/index.js.map +1 -0
- package/dist/cli/commands/apps/index.test.d.ts +2 -0
- package/dist/cli/commands/apps/index.test.d.ts.map +1 -0
- package/dist/cli/commands/apps/index.test.js +206 -0
- package/dist/cli/commands/apps/index.test.js.map +1 -0
- package/dist/cli/commands/buyer/deposit.d.ts.map +1 -1
- package/dist/cli/commands/buyer/deposit.js +9 -1
- package/dist/cli/commands/buyer/deposit.js.map +1 -1
- package/dist/cli/commands/buyer/identity.d.ts +3 -1
- package/dist/cli/commands/buyer/identity.d.ts.map +1 -1
- package/dist/cli/commands/buyer/identity.js +55 -8
- package/dist/cli/commands/buyer/identity.js.map +1 -1
- package/dist/cli/commands/buyer/identity.test.d.ts +2 -0
- package/dist/cli/commands/buyer/identity.test.d.ts.map +1 -0
- package/dist/cli/commands/buyer/identity.test.js +168 -0
- package/dist/cli/commands/buyer/identity.test.js.map +1 -0
- package/dist/cli/commands/buyer/set-authorized-wallet.d.ts +10 -0
- package/dist/cli/commands/buyer/set-authorized-wallet.d.ts.map +1 -1
- package/dist/cli/commands/buyer/set-authorized-wallet.js +26 -4
- package/dist/cli/commands/buyer/set-authorized-wallet.js.map +1 -1
- package/dist/cli/commands/buyer/set-authorized-wallet.test.js +37 -2
- package/dist/cli/commands/buyer/set-authorized-wallet.test.js.map +1 -1
- package/dist/cli/commands/buyer/start.d.ts +15 -0
- package/dist/cli/commands/buyer/start.d.ts.map +1 -1
- package/dist/cli/commands/buyer/start.js +158 -48
- package/dist/cli/commands/buyer/start.js.map +1 -1
- package/dist/cli/commands/buyer/start.test.js +16 -1
- package/dist/cli/commands/buyer/start.test.js.map +1 -1
- package/dist/cli/commands/chat.d.ts +3 -0
- package/dist/cli/commands/chat.d.ts.map +1 -0
- package/dist/cli/commands/chat.js +189 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/gateway/activity.d.ts +15 -0
- package/dist/cli/commands/gateway/activity.d.ts.map +1 -0
- package/dist/cli/commands/gateway/activity.js +233 -0
- package/dist/cli/commands/gateway/activity.js.map +1 -0
- package/dist/cli/commands/gateway/admin-token.d.ts +3 -0
- package/dist/cli/commands/gateway/admin-token.d.ts.map +1 -0
- package/dist/cli/commands/gateway/admin-token.js +90 -0
- package/dist/cli/commands/gateway/admin-token.js.map +1 -0
- package/dist/cli/commands/gateway/console-link.d.ts +20 -0
- package/dist/cli/commands/gateway/console-link.d.ts.map +1 -0
- package/dist/cli/commands/gateway/console-link.js +92 -0
- package/dist/cli/commands/gateway/console-link.js.map +1 -0
- package/dist/cli/commands/gateway/gateway-commands.test.d.ts +2 -0
- package/dist/cli/commands/gateway/gateway-commands.test.d.ts.map +1 -0
- package/dist/cli/commands/gateway/gateway-commands.test.js +230 -0
- package/dist/cli/commands/gateway/gateway-commands.test.js.map +1 -0
- package/dist/cli/commands/gateway/gateway-console-commands.test.d.ts +2 -0
- package/dist/cli/commands/gateway/gateway-console-commands.test.d.ts.map +1 -0
- package/dist/cli/commands/gateway/gateway-console-commands.test.js +373 -0
- package/dist/cli/commands/gateway/gateway-console-commands.test.js.map +1 -0
- package/dist/cli/commands/gateway/index.d.ts +8 -0
- package/dist/cli/commands/gateway/index.d.ts.map +1 -1
- package/dist/cli/commands/gateway/index.js +93 -14
- package/dist/cli/commands/gateway/index.js.map +1 -1
- package/dist/cli/commands/gateway/key.d.ts +4 -0
- package/dist/cli/commands/gateway/key.d.ts.map +1 -1
- package/dist/cli/commands/gateway/key.js +297 -182
- package/dist/cli/commands/gateway/key.js.map +1 -1
- package/dist/cli/commands/gateway/member.d.ts +3 -0
- package/dist/cli/commands/gateway/member.d.ts.map +1 -0
- package/dist/cli/commands/gateway/member.js +302 -0
- package/dist/cli/commands/gateway/member.js.map +1 -0
- package/dist/cli/commands/gateway/migrate.d.ts +18 -0
- package/dist/cli/commands/gateway/migrate.d.ts.map +1 -0
- package/dist/cli/commands/gateway/migrate.js +158 -0
- package/dist/cli/commands/gateway/migrate.js.map +1 -0
- package/dist/cli/commands/gateway/operator.d.ts +11 -0
- package/dist/cli/commands/gateway/operator.d.ts.map +1 -0
- package/dist/cli/commands/gateway/operator.js +199 -0
- package/dist/cli/commands/gateway/operator.js.map +1 -0
- package/dist/cli/commands/gateway/operator.test.d.ts +2 -0
- package/dist/cli/commands/gateway/operator.test.d.ts.map +1 -0
- package/dist/cli/commands/gateway/operator.test.js +151 -0
- package/dist/cli/commands/gateway/operator.test.js.map +1 -0
- package/dist/cli/commands/gateway/peer-list.d.ts +3 -0
- package/dist/cli/commands/gateway/peer-list.d.ts.map +1 -0
- package/dist/cli/commands/gateway/peer-list.js +107 -0
- package/dist/cli/commands/gateway/peer-list.js.map +1 -0
- package/dist/cli/commands/gateway/policy-options.d.ts +23 -0
- package/dist/cli/commands/gateway/policy-options.d.ts.map +1 -0
- package/dist/cli/commands/gateway/policy-options.js +156 -0
- package/dist/cli/commands/gateway/policy-options.js.map +1 -0
- package/dist/cli/commands/gateway/preset.d.ts +3 -0
- package/dist/cli/commands/gateway/preset.d.ts.map +1 -0
- package/dist/cli/commands/gateway/preset.js +181 -0
- package/dist/cli/commands/gateway/preset.js.map +1 -0
- package/dist/cli/commands/gateway/routing.d.ts +3 -0
- package/dist/cli/commands/gateway/routing.d.ts.map +1 -0
- package/dist/cli/commands/gateway/routing.js +110 -0
- package/dist/cli/commands/gateway/routing.js.map +1 -0
- package/dist/cli/commands/gateway/settings.d.ts +4 -0
- package/dist/cli/commands/gateway/settings.d.ts.map +1 -0
- package/dist/cli/commands/gateway/settings.js +314 -0
- package/dist/cli/commands/gateway/settings.js.map +1 -0
- package/dist/cli/commands/gateway/shared.d.ts +55 -6
- package/dist/cli/commands/gateway/shared.d.ts.map +1 -1
- package/dist/cli/commands/gateway/shared.js +206 -26
- package/dist/cli/commands/gateway/shared.js.map +1 -1
- package/dist/cli/commands/gateway/workspace.d.ts +3 -0
- package/dist/cli/commands/gateway/workspace.d.ts.map +1 -0
- package/dist/cli/commands/gateway/workspace.js +250 -0
- package/dist/cli/commands/gateway/workspace.js.map +1 -0
- package/dist/cli/commands/tunnel/start.d.ts.map +1 -1
- package/dist/cli/commands/tunnel/start.js +23 -5
- package/dist/cli/commands/tunnel/start.js.map +1 -1
- package/dist/cli/index.js +12 -42
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/program.d.ts +4 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +49 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/program.test.d.ts +2 -0
- package/dist/cli/program.test.d.ts.map +1 -0
- package/dist/cli/program.test.js +38 -0
- package/dist/cli/program.test.js.map +1 -0
- package/dist/cli/prompt-hidden.d.ts +3 -0
- package/dist/cli/prompt-hidden.d.ts.map +1 -0
- package/dist/cli/prompt-hidden.js +38 -0
- package/dist/cli/prompt-hidden.js.map +1 -0
- package/dist/cli/wallet-passphrase.d.ts +48 -0
- package/dist/cli/wallet-passphrase.d.ts.map +1 -0
- package/dist/cli/wallet-passphrase.js +119 -0
- package/dist/cli/wallet-passphrase.js.map +1 -0
- package/dist/cli/wallet-passphrase.test.d.ts +2 -0
- package/dist/cli/wallet-passphrase.test.d.ts.map +1 -0
- package/dist/cli/wallet-passphrase.test.js +79 -0
- package/dist/cli/wallet-passphrase.test.js.map +1 -0
- package/dist/config/effective.d.ts +12 -0
- package/dist/config/effective.d.ts.map +1 -1
- package/dist/config/effective.js +39 -6
- package/dist/config/effective.js.map +1 -1
- package/dist/config/effective.test.js +9 -1
- package/dist/config/effective.test.js.map +1 -1
- package/dist/config/loader.d.ts +6 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +12 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/loader.test.js +7 -1
- package/dist/config/loader.test.js.map +1 -1
- package/dist/config/types.d.ts +14 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +19 -0
- package/dist/config/validation.js.map +1 -1
- package/dist/gateway/accounting.d.ts +33 -3
- package/dist/gateway/accounting.d.ts.map +1 -1
- package/dist/gateway/accounting.js +86 -7
- package/dist/gateway/accounting.js.map +1 -1
- package/dist/gateway/admission-benchmark.test.d.ts +2 -0
- package/dist/gateway/admission-benchmark.test.d.ts.map +1 -0
- package/dist/gateway/admission-benchmark.test.js +75 -0
- package/dist/gateway/admission-benchmark.test.js.map +1 -0
- package/dist/gateway/auth/auth.test.d.ts +4 -0
- package/dist/gateway/auth/auth.test.d.ts.map +1 -0
- package/dist/gateway/auth/auth.test.js +337 -0
- package/dist/gateway/auth/auth.test.js.map +1 -0
- package/dist/gateway/auth/credentials.test.d.ts +2 -0
- package/dist/gateway/auth/credentials.test.d.ts.map +1 -0
- package/dist/gateway/auth/credentials.test.js +132 -0
- package/dist/gateway/auth/credentials.test.js.map +1 -0
- package/dist/gateway/auth/db.d.ts +156 -0
- package/dist/gateway/auth/db.d.ts.map +1 -0
- package/dist/gateway/auth/db.js +390 -0
- package/dist/gateway/auth/db.js.map +1 -0
- package/dist/gateway/auth/hardening.test.d.ts +2 -0
- package/dist/gateway/auth/hardening.test.d.ts.map +1 -0
- package/dist/gateway/auth/hardening.test.js +155 -0
- package/dist/gateway/auth/hardening.test.js.map +1 -0
- package/dist/gateway/auth/http.d.ts +53 -0
- package/dist/gateway/auth/http.d.ts.map +1 -0
- package/dist/gateway/auth/http.js +165 -0
- package/dist/gateway/auth/http.js.map +1 -0
- package/dist/gateway/auth/index.d.ts +26 -0
- package/dist/gateway/auth/index.d.ts.map +1 -0
- package/dist/gateway/auth/index.js +1014 -0
- package/dist/gateway/auth/index.js.map +1 -0
- package/dist/gateway/auth/oidc.d.ts +57 -0
- package/dist/gateway/auth/oidc.d.ts.map +1 -0
- package/dist/gateway/auth/oidc.js +159 -0
- package/dist/gateway/auth/oidc.js.map +1 -0
- package/dist/gateway/auth/oidc.test.d.ts +2 -0
- package/dist/gateway/auth/oidc.test.d.ts.map +1 -0
- package/dist/gateway/auth/oidc.test.js +223 -0
- package/dist/gateway/auth/oidc.test.js.map +1 -0
- package/dist/gateway/auth/reauth.test.d.ts +2 -0
- package/dist/gateway/auth/reauth.test.d.ts.map +1 -0
- package/dist/gateway/auth/reauth.test.js +108 -0
- package/dist/gateway/auth/reauth.test.js.map +1 -0
- package/dist/gateway/auth/store-integration.test.d.ts +2 -0
- package/dist/gateway/auth/store-integration.test.d.ts.map +1 -0
- package/dist/gateway/auth/store-integration.test.js +100 -0
- package/dist/gateway/auth/store-integration.test.js.map +1 -0
- package/dist/gateway/auth/test-helpers.d.ts +167 -0
- package/dist/gateway/auth/test-helpers.d.ts.map +1 -0
- package/dist/gateway/auth/test-helpers.js +368 -0
- package/dist/gateway/auth/test-helpers.js.map +1 -0
- package/dist/gateway/auth/types.d.ts +145 -0
- package/dist/gateway/auth/types.d.ts.map +1 -0
- package/dist/gateway/auth/types.js +2 -0
- package/dist/gateway/auth/types.js.map +1 -0
- package/dist/gateway/auth/wallet.d.ts +15 -0
- package/dist/gateway/auth/wallet.d.ts.map +1 -0
- package/dist/gateway/auth/wallet.js +43 -0
- package/dist/gateway/auth/wallet.js.map +1 -0
- package/dist/gateway/bundle.d.ts +127 -0
- package/dist/gateway/bundle.d.ts.map +1 -0
- package/dist/gateway/bundle.js +604 -0
- package/dist/gateway/bundle.js.map +1 -0
- package/dist/gateway/bundle.test.d.ts +2 -0
- package/dist/gateway/bundle.test.d.ts.map +1 -0
- package/dist/gateway/bundle.test.js +277 -0
- package/dist/gateway/bundle.test.js.map +1 -0
- package/dist/gateway/buyer-control.d.ts +33 -0
- package/dist/gateway/buyer-control.d.ts.map +1 -0
- package/dist/gateway/buyer-control.js +93 -0
- package/dist/gateway/buyer-control.js.map +1 -0
- package/dist/gateway/buyer-policy-probe.d.ts +41 -0
- package/dist/gateway/buyer-policy-probe.d.ts.map +1 -0
- package/dist/gateway/buyer-policy-probe.js +99 -0
- package/dist/gateway/buyer-policy-probe.js.map +1 -0
- package/dist/gateway/buyer-policy-probe.test.d.ts +2 -0
- package/dist/gateway/buyer-policy-probe.test.d.ts.map +1 -0
- package/dist/gateway/buyer-policy-probe.test.js +128 -0
- package/dist/gateway/buyer-policy-probe.test.js.map +1 -0
- package/dist/gateway/buyer-process.d.ts +30 -0
- package/dist/gateway/buyer-process.d.ts.map +1 -0
- package/dist/gateway/buyer-process.js +101 -0
- package/dist/gateway/buyer-process.js.map +1 -0
- package/dist/gateway/buyer-process.test.d.ts +2 -0
- package/dist/gateway/buyer-process.test.d.ts.map +1 -0
- package/dist/gateway/buyer-process.test.js +112 -0
- package/dist/gateway/buyer-process.test.js.map +1 -0
- package/dist/gateway/chat/routes.d.ts +45 -0
- package/dist/gateway/chat/routes.d.ts.map +1 -0
- package/dist/gateway/chat/routes.js +439 -0
- package/dist/gateway/chat/routes.js.map +1 -0
- package/dist/gateway/chat/routes.test.d.ts +2 -0
- package/dist/gateway/chat/routes.test.d.ts.map +1 -0
- package/dist/gateway/chat/routes.test.js +304 -0
- package/dist/gateway/chat/routes.test.js.map +1 -0
- package/dist/gateway/chat/tools.d.ts +35 -0
- package/dist/gateway/chat/tools.d.ts.map +1 -0
- package/dist/gateway/chat/tools.js +347 -0
- package/dist/gateway/chat/tools.js.map +1 -0
- package/dist/gateway/chat/tools.test.d.ts +2 -0
- package/dist/gateway/chat/tools.test.d.ts.map +1 -0
- package/dist/gateway/chat/tools.test.js +136 -0
- package/dist/gateway/chat/tools.test.js.map +1 -0
- package/dist/gateway/console-api/access.d.ts +52 -0
- package/dist/gateway/console-api/access.d.ts.map +1 -0
- package/dist/gateway/console-api/access.js +171 -0
- package/dist/gateway/console-api/access.js.map +1 -0
- package/dist/gateway/console-api/deps.d.ts +52 -0
- package/dist/gateway/console-api/deps.d.ts.map +1 -0
- package/dist/gateway/console-api/deps.js +2 -0
- package/dist/gateway/console-api/deps.js.map +1 -0
- package/dist/gateway/console-api/handlers/admin-tokens.d.ts +8 -0
- package/dist/gateway/console-api/handlers/admin-tokens.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/admin-tokens.js +48 -0
- package/dist/gateway/console-api/handlers/admin-tokens.js.map +1 -0
- package/dist/gateway/console-api/handlers/audit.d.ts +8 -0
- package/dist/gateway/console-api/handlers/audit.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/audit.js +19 -0
- package/dist/gateway/console-api/handlers/audit.js.map +1 -0
- package/dist/gateway/console-api/handlers/audit.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/audit.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/audit.test.js +241 -0
- package/dist/gateway/console-api/handlers/audit.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/data-settings.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/data-settings.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/data-settings.test.js +264 -0
- package/dist/gateway/console-api/handlers/data-settings.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/index.d.ts +4 -0
- package/dist/gateway/console-api/handlers/index.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/index.js +24 -0
- package/dist/gateway/console-api/handlers/index.js.map +1 -0
- package/dist/gateway/console-api/handlers/keys.d.ts +13 -0
- package/dist/gateway/console-api/handlers/keys.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/keys.js +128 -0
- package/dist/gateway/console-api/handlers/keys.js.map +1 -0
- package/dist/gateway/console-api/handlers/keys.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/keys.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/keys.test.js +166 -0
- package/dist/gateway/console-api/handlers/keys.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/network-buyer.d.ts +22 -0
- package/dist/gateway/console-api/handlers/network-buyer.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/network-buyer.js +39 -0
- package/dist/gateway/console-api/handlers/network-buyer.js.map +1 -0
- package/dist/gateway/console-api/handlers/network-mapping.d.ts +33 -0
- package/dist/gateway/console-api/handlers/network-mapping.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/network-mapping.js +219 -0
- package/dist/gateway/console-api/handlers/network-mapping.js.map +1 -0
- package/dist/gateway/console-api/handlers/network-test-helpers.d.ts +35 -0
- package/dist/gateway/console-api/handlers/network-test-helpers.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/network-test-helpers.js +121 -0
- package/dist/gateway/console-api/handlers/network-test-helpers.js.map +1 -0
- package/dist/gateway/console-api/handlers/network.d.ts +15 -0
- package/dist/gateway/console-api/handlers/network.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/network.js +57 -0
- package/dist/gateway/console-api/handlers/network.js.map +1 -0
- package/dist/gateway/console-api/handlers/network.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/network.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/network.test.js +383 -0
- package/dist/gateway/console-api/handlers/network.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/org.d.ts +10 -0
- package/dist/gateway/console-api/handlers/org.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/org.js +150 -0
- package/dist/gateway/console-api/handlers/org.js.map +1 -0
- package/dist/gateway/console-api/handlers/peer-lists.d.ts +5 -0
- package/dist/gateway/console-api/handlers/peer-lists.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/peer-lists.js +43 -0
- package/dist/gateway/console-api/handlers/peer-lists.js.map +1 -0
- package/dist/gateway/console-api/handlers/presets.d.ts +9 -0
- package/dist/gateway/console-api/handlers/presets.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/presets.js +79 -0
- package/dist/gateway/console-api/handlers/presets.js.map +1 -0
- package/dist/gateway/console-api/handlers/routing.d.ts +5 -0
- package/dist/gateway/console-api/handlers/routing.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/routing.js +20 -0
- package/dist/gateway/console-api/handlers/routing.js.map +1 -0
- package/dist/gateway/console-api/handlers/settings.d.ts +10 -0
- package/dist/gateway/console-api/handlers/settings.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/settings.js +38 -0
- package/dist/gateway/console-api/handlers/settings.js.map +1 -0
- package/dist/gateway/console-api/handlers/status.d.ts +9 -0
- package/dist/gateway/console-api/handlers/status.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/status.js +47 -0
- package/dist/gateway/console-api/handlers/status.js.map +1 -0
- package/dist/gateway/console-api/handlers/status.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/status.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/status.test.js +82 -0
- package/dist/gateway/console-api/handlers/status.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/usage.d.ts +10 -0
- package/dist/gateway/console-api/handlers/usage.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/usage.js +68 -0
- package/dist/gateway/console-api/handlers/usage.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-card-link.d.ts +29 -0
- package/dist/gateway/console-api/handlers/wallet-card-link.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-card-link.js +46 -0
- package/dist/gateway/console-api/handlers/wallet-card-link.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-chain.d.ts +26 -0
- package/dist/gateway/console-api/handlers/wallet-chain.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-chain.js +80 -0
- package/dist/gateway/console-api/handlers/wallet-chain.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-mapping.d.ts +45 -0
- package/dist/gateway/console-api/handlers/wallet-mapping.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-mapping.js +202 -0
- package/dist/gateway/console-api/handlers/wallet-mapping.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-operator.d.ts +41 -0
- package/dist/gateway/console-api/handlers/wallet-operator.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-operator.js +198 -0
- package/dist/gateway/console-api/handlers/wallet-operator.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-operator.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/wallet-operator.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet-operator.test.js +195 -0
- package/dist/gateway/console-api/handlers/wallet-operator.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet.d.ts +61 -0
- package/dist/gateway/console-api/handlers/wallet.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet.js +221 -0
- package/dist/gateway/console-api/handlers/wallet.js.map +1 -0
- package/dist/gateway/console-api/handlers/wallet.test.d.ts +2 -0
- package/dist/gateway/console-api/handlers/wallet.test.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/wallet.test.js +581 -0
- package/dist/gateway/console-api/handlers/wallet.test.js.map +1 -0
- package/dist/gateway/console-api/handlers/workspaces.d.ts +12 -0
- package/dist/gateway/console-api/handlers/workspaces.d.ts.map +1 -0
- package/dist/gateway/console-api/handlers/workspaces.js +96 -0
- package/dist/gateway/console-api/handlers/workspaces.js.map +1 -0
- package/dist/gateway/console-api/operator-types.d.ts +68 -0
- package/dist/gateway/console-api/operator-types.d.ts.map +1 -0
- package/dist/gateway/console-api/operator-types.js +21 -0
- package/dist/gateway/console-api/operator-types.js.map +1 -0
- package/dist/gateway/console-api/router.d.ts +97 -0
- package/dist/gateway/console-api/router.d.ts.map +1 -0
- package/dist/gateway/console-api/router.js +69 -0
- package/dist/gateway/console-api/router.js.map +1 -0
- package/dist/gateway/console-api/routes.test.d.ts +2 -0
- package/dist/gateway/console-api/routes.test.d.ts.map +1 -0
- package/dist/gateway/console-api/routes.test.js +331 -0
- package/dist/gateway/console-api/routes.test.js.map +1 -0
- package/dist/gateway/console-api/serialize.d.ts +33 -0
- package/dist/gateway/console-api/serialize.d.ts.map +1 -0
- package/dist/gateway/console-api/serialize.js +179 -0
- package/dist/gateway/console-api/serialize.js.map +1 -0
- package/dist/gateway/console-api/server.d.ts +38 -0
- package/dist/gateway/console-api/server.d.ts.map +1 -0
- package/dist/gateway/console-api/server.js +308 -0
- package/dist/gateway/console-api/server.js.map +1 -0
- package/dist/gateway/console-api/server.test.d.ts +2 -0
- package/dist/gateway/console-api/server.test.d.ts.map +1 -0
- package/dist/gateway/console-api/server.test.js +149 -0
- package/dist/gateway/console-api/server.test.js.map +1 -0
- package/dist/gateway/console-api/test-support.d.ts +59 -0
- package/dist/gateway/console-api/test-support.d.ts.map +1 -0
- package/dist/gateway/console-api/test-support.js +120 -0
- package/dist/gateway/console-api/test-support.js.map +1 -0
- package/dist/gateway/console-api/types.d.ts +779 -0
- package/dist/gateway/console-api/types.d.ts.map +1 -0
- package/dist/gateway/console-api/types.js +6 -0
- package/dist/gateway/console-api/types.js.map +1 -0
- package/dist/gateway/console-location.d.ts +21 -0
- package/dist/gateway/console-location.d.ts.map +1 -0
- package/dist/gateway/console-location.js +41 -0
- package/dist/gateway/console-location.js.map +1 -0
- package/dist/gateway/console-recovery.d.ts +34 -0
- package/dist/gateway/console-recovery.d.ts.map +1 -0
- package/dist/gateway/console-recovery.js +94 -0
- package/dist/gateway/console-recovery.js.map +1 -0
- package/dist/gateway/console-recovery.test.d.ts +2 -0
- package/dist/gateway/console-recovery.test.d.ts.map +1 -0
- package/dist/gateway/console-recovery.test.js +106 -0
- package/dist/gateway/console-recovery.test.js.map +1 -0
- package/dist/gateway/console.d.ts +18 -0
- package/dist/gateway/console.d.ts.map +1 -0
- package/dist/gateway/console.js +101 -0
- package/dist/gateway/console.js.map +1 -0
- package/dist/gateway/console.test.d.ts +2 -0
- package/dist/gateway/console.test.d.ts.map +1 -0
- package/dist/gateway/console.test.js +165 -0
- package/dist/gateway/console.test.js.map +1 -0
- package/dist/gateway/errors.d.ts +3 -0
- package/dist/gateway/errors.d.ts.map +1 -0
- package/dist/gateway/errors.js +5 -0
- package/dist/gateway/errors.js.map +1 -0
- package/dist/gateway/exposure.d.ts +33 -0
- package/dist/gateway/exposure.d.ts.map +1 -0
- package/dist/gateway/exposure.js +146 -0
- package/dist/gateway/exposure.js.map +1 -0
- package/dist/gateway/exposure.test.d.ts +2 -0
- package/dist/gateway/exposure.test.d.ts.map +1 -0
- package/dist/gateway/exposure.test.js +93 -0
- package/dist/gateway/exposure.test.js.map +1 -0
- package/dist/gateway/gateway-policy.test.d.ts +2 -0
- package/dist/gateway/gateway-policy.test.d.ts.map +1 -0
- package/dist/gateway/gateway-policy.test.js +404 -0
- package/dist/gateway/gateway-policy.test.js.map +1 -0
- package/dist/gateway/gateway.test.js +77 -24
- package/dist/gateway/gateway.test.js.map +1 -1
- package/dist/gateway/keys.d.ts +2 -0
- package/dist/gateway/keys.d.ts.map +1 -1
- package/dist/gateway/keys.js +2 -0
- package/dist/gateway/keys.js.map +1 -1
- package/dist/gateway/limits.d.ts +32 -8
- package/dist/gateway/limits.d.ts.map +1 -1
- package/dist/gateway/limits.js +27 -11
- package/dist/gateway/limits.js.map +1 -1
- package/dist/gateway/observability.d.ts +51 -0
- package/dist/gateway/observability.d.ts.map +1 -0
- package/dist/gateway/observability.js +136 -0
- package/dist/gateway/observability.js.map +1 -0
- package/dist/gateway/policy-resolver.d.ts +73 -0
- package/dist/gateway/policy-resolver.d.ts.map +1 -0
- package/dist/gateway/policy-resolver.js +142 -0
- package/dist/gateway/policy-resolver.js.map +1 -0
- package/dist/gateway/policy-resolver.test.d.ts +2 -0
- package/dist/gateway/policy-resolver.test.d.ts.map +1 -0
- package/dist/gateway/policy-resolver.test.js +273 -0
- package/dist/gateway/policy-resolver.test.js.map +1 -0
- package/dist/gateway/request-errors.test.d.ts +2 -0
- package/dist/gateway/request-errors.test.d.ts.map +1 -0
- package/dist/gateway/request-errors.test.js +108 -0
- package/dist/gateway/request-errors.test.js.map +1 -0
- package/dist/gateway/request-shaping.d.ts +25 -0
- package/dist/gateway/request-shaping.d.ts.map +1 -0
- package/dist/gateway/request-shaping.js +66 -0
- package/dist/gateway/request-shaping.js.map +1 -0
- package/dist/gateway/response-usage.d.ts +35 -0
- package/dist/gateway/response-usage.d.ts.map +1 -0
- package/dist/gateway/response-usage.js +167 -0
- package/dist/gateway/response-usage.js.map +1 -0
- package/dist/gateway/response-usage.test.d.ts +2 -0
- package/dist/gateway/response-usage.test.d.ts.map +1 -0
- package/dist/gateway/response-usage.test.js +78 -0
- package/dist/gateway/response-usage.test.js.map +1 -0
- package/dist/gateway/runtime.d.ts +25 -0
- package/dist/gateway/runtime.d.ts.map +1 -1
- package/dist/gateway/runtime.js +39 -19
- package/dist/gateway/runtime.js.map +1 -1
- package/dist/gateway/server.d.ts +68 -2
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +533 -114
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/services/audit.d.ts +16 -0
- package/dist/gateway/services/audit.d.ts.map +1 -0
- package/dist/gateway/services/audit.js +18 -0
- package/dist/gateway/services/audit.js.map +1 -0
- package/dist/gateway/services/context.d.ts +66 -0
- package/dist/gateway/services/context.d.ts.map +1 -0
- package/dist/gateway/services/context.js +52 -0
- package/dist/gateway/services/context.js.map +1 -0
- package/dist/gateway/services/keys.d.ts +78 -0
- package/dist/gateway/services/keys.d.ts.map +1 -0
- package/dist/gateway/services/keys.js +232 -0
- package/dist/gateway/services/keys.js.map +1 -0
- package/dist/gateway/services/members.d.ts +72 -0
- package/dist/gateway/services/members.d.ts.map +1 -0
- package/dist/gateway/services/members.js +161 -0
- package/dist/gateway/services/members.js.map +1 -0
- package/dist/gateway/services/network.d.ts +36 -0
- package/dist/gateway/services/network.d.ts.map +1 -0
- package/dist/gateway/services/network.js +147 -0
- package/dist/gateway/services/network.js.map +1 -0
- package/dist/gateway/services/operator.d.ts +98 -0
- package/dist/gateway/services/operator.d.ts.map +1 -0
- package/dist/gateway/services/operator.js +170 -0
- package/dist/gateway/services/operator.js.map +1 -0
- package/dist/gateway/services/operator.test.d.ts +2 -0
- package/dist/gateway/services/operator.test.d.ts.map +1 -0
- package/dist/gateway/services/operator.test.js +184 -0
- package/dist/gateway/services/operator.test.js.map +1 -0
- package/dist/gateway/services/peer-lists.d.ts +20 -0
- package/dist/gateway/services/peer-lists.d.ts.map +1 -0
- package/dist/gateway/services/peer-lists.js +134 -0
- package/dist/gateway/services/peer-lists.js.map +1 -0
- package/dist/gateway/services/presets.d.ts +34 -0
- package/dist/gateway/services/presets.d.ts.map +1 -0
- package/dist/gateway/services/presets.js +134 -0
- package/dist/gateway/services/presets.js.map +1 -0
- package/dist/gateway/services/routing.d.ts +13 -0
- package/dist/gateway/services/routing.d.ts.map +1 -0
- package/dist/gateway/services/routing.js +18 -0
- package/dist/gateway/services/routing.js.map +1 -0
- package/dist/gateway/services/services.test.d.ts +2 -0
- package/dist/gateway/services/services.test.d.ts.map +1 -0
- package/dist/gateway/services/services.test.js +476 -0
- package/dist/gateway/services/services.test.js.map +1 -0
- package/dist/gateway/services/settings.d.ts +68 -0
- package/dist/gateway/services/settings.d.ts.map +1 -0
- package/dist/gateway/services/settings.js +580 -0
- package/dist/gateway/services/settings.js.map +1 -0
- package/dist/gateway/services/tokens.d.ts +29 -0
- package/dist/gateway/services/tokens.d.ts.map +1 -0
- package/dist/gateway/services/tokens.js +48 -0
- package/dist/gateway/services/tokens.js.map +1 -0
- package/dist/gateway/services/usage.d.ts +55 -0
- package/dist/gateway/services/usage.d.ts.map +1 -0
- package/dist/gateway/services/usage.js +225 -0
- package/dist/gateway/services/usage.js.map +1 -0
- package/dist/gateway/services/wallet-address-env.test.d.ts +2 -0
- package/dist/gateway/services/wallet-address-env.test.d.ts.map +1 -0
- package/dist/gateway/services/wallet-address-env.test.js +119 -0
- package/dist/gateway/services/wallet-address-env.test.js.map +1 -0
- package/dist/gateway/services/wallet-address.d.ts +40 -0
- package/dist/gateway/services/wallet-address.d.ts.map +1 -0
- package/dist/gateway/services/wallet-address.js +116 -0
- package/dist/gateway/services/wallet-address.js.map +1 -0
- package/dist/gateway/services/wallet-address.test.d.ts +2 -0
- package/dist/gateway/services/wallet-address.test.d.ts.map +1 -0
- package/dist/gateway/services/wallet-address.test.js +84 -0
- package/dist/gateway/services/wallet-address.test.js.map +1 -0
- package/dist/gateway/services/workspaces.d.ts +75 -0
- package/dist/gateway/services/workspaces.d.ts.map +1 -0
- package/dist/gateway/services/workspaces.js +228 -0
- package/dist/gateway/services/workspaces.js.map +1 -0
- package/dist/gateway/spend-durability.test.d.ts +2 -0
- package/dist/gateway/spend-durability.test.d.ts.map +1 -0
- package/dist/gateway/spend-durability.test.js +330 -0
- package/dist/gateway/spend-durability.test.js.map +1 -0
- package/dist/gateway/spend-feed.d.ts +11 -1
- package/dist/gateway/spend-feed.d.ts.map +1 -1
- package/dist/gateway/spend-feed.js +17 -4
- package/dist/gateway/spend-feed.js.map +1 -1
- package/dist/gateway/spend-feed.test.d.ts +2 -0
- package/dist/gateway/spend-feed.test.d.ts.map +1 -0
- package/dist/gateway/spend-feed.test.js +34 -0
- package/dist/gateway/spend-feed.test.js.map +1 -0
- package/dist/gateway/store-data.test.d.ts +2 -0
- package/dist/gateway/store-data.test.d.ts.map +1 -0
- package/dist/gateway/store-data.test.js +346 -0
- package/dist/gateway/store-data.test.js.map +1 -0
- package/dist/gateway/store-migrations.d.ts +6 -0
- package/dist/gateway/store-migrations.d.ts.map +1 -0
- package/dist/gateway/store-migrations.js +301 -0
- package/dist/gateway/store-migrations.js.map +1 -0
- package/dist/gateway/store.d.ts +595 -10
- package/dist/gateway/store.d.ts.map +1 -1
- package/dist/gateway/store.js +1242 -120
- package/dist/gateway/store.js.map +1 -1
- package/dist/gateway/store.test.d.ts +2 -0
- package/dist/gateway/store.test.d.ts.map +1 -0
- package/dist/gateway/store.test.js +185 -0
- package/dist/gateway/store.test.js.map +1 -0
- package/dist/proxy/buyer-chain-reader.d.ts +68 -0
- package/dist/proxy/buyer-chain-reader.d.ts.map +1 -0
- package/dist/proxy/buyer-chain-reader.js +152 -0
- package/dist/proxy/buyer-chain-reader.js.map +1 -0
- package/dist/proxy/buyer-chain-reader.test.d.ts +2 -0
- package/dist/proxy/buyer-chain-reader.test.d.ts.map +1 -0
- package/dist/proxy/buyer-chain-reader.test.js +102 -0
- package/dist/proxy/buyer-chain-reader.test.js.map +1 -0
- package/dist/proxy/buyer-proxy.d.ts +169 -3
- package/dist/proxy/buyer-proxy.d.ts.map +1 -1
- package/dist/proxy/buyer-proxy.js +882 -118
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/buyer-proxy.test.js +108 -0
- package/dist/proxy/buyer-proxy.test.js.map +1 -1
- package/dist/proxy/chain-read-cache.d.ts +47 -0
- package/dist/proxy/chain-read-cache.d.ts.map +1 -0
- package/dist/proxy/chain-read-cache.js +110 -0
- package/dist/proxy/chain-read-cache.js.map +1 -0
- package/dist/proxy/chain-read-cache.test.d.ts +2 -0
- package/dist/proxy/chain-read-cache.test.d.ts.map +1 -0
- package/dist/proxy/chain-read-cache.test.js +75 -0
- package/dist/proxy/chain-read-cache.test.js.map +1 -0
- package/dist/proxy/chain-rpc-test-support.d.ts +31 -0
- package/dist/proxy/chain-rpc-test-support.d.ts.map +1 -0
- package/dist/proxy/chain-rpc-test-support.js +136 -0
- package/dist/proxy/chain-rpc-test-support.js.map +1 -0
- package/dist/proxy/chain-rpc.d.ts +121 -0
- package/dist/proxy/chain-rpc.d.ts.map +1 -0
- package/dist/proxy/chain-rpc.js +420 -0
- package/dist/proxy/chain-rpc.js.map +1 -0
- package/dist/proxy/chain-rpc.test.d.ts +2 -0
- package/dist/proxy/chain-rpc.test.d.ts.map +1 -0
- package/dist/proxy/chain-rpc.test.js +180 -0
- package/dist/proxy/chain-rpc.test.js.map +1 -0
- package/dist/proxy/credential-headers.d.ts +17 -0
- package/dist/proxy/credential-headers.d.ts.map +1 -0
- package/dist/proxy/credential-headers.js +29 -0
- package/dist/proxy/credential-headers.js.map +1 -0
- package/dist/proxy/deposit-watch-hub.d.ts +47 -0
- package/dist/proxy/deposit-watch-hub.d.ts.map +1 -0
- package/dist/proxy/deposit-watch-hub.js +111 -0
- package/dist/proxy/deposit-watch-hub.js.map +1 -0
- package/dist/proxy/deposit-watch-hub.test.d.ts +2 -0
- package/dist/proxy/deposit-watch-hub.test.d.ts.map +1 -0
- package/dist/proxy/deposit-watch-hub.test.js +133 -0
- package/dist/proxy/deposit-watch-hub.test.js.map +1 -0
- package/dist/proxy/deposit-watcher.d.ts +63 -4
- package/dist/proxy/deposit-watcher.d.ts.map +1 -1
- package/dist/proxy/deposit-watcher.js +120 -19
- package/dist/proxy/deposit-watcher.js.map +1 -1
- package/dist/proxy/deposit-watcher.test.js +81 -5
- package/dist/proxy/deposit-watcher.test.js.map +1 -1
- package/dist/proxy/gateway-policy.test.d.ts +2 -0
- package/dist/proxy/gateway-policy.test.d.ts.map +1 -0
- package/dist/proxy/gateway-policy.test.js +576 -0
- package/dist/proxy/gateway-policy.test.js.map +1 -0
- package/dist/proxy/network-models.d.ts +2 -0
- package/dist/proxy/network-models.d.ts.map +1 -1
- package/dist/proxy/network-models.js +3 -1
- package/dist/proxy/network-models.js.map +1 -1
- package/dist/proxy/route-policy.d.ts +97 -0
- package/dist/proxy/route-policy.d.ts.map +1 -0
- package/dist/proxy/route-policy.js +230 -0
- package/dist/proxy/route-policy.js.map +1 -0
- package/dist/proxy/route-policy.test.d.ts +2 -0
- package/dist/proxy/route-policy.test.d.ts.map +1 -0
- package/dist/proxy/route-policy.test.js +120 -0
- package/dist/proxy/route-policy.test.js.map +1 -0
- package/dist/proxy/spend-attribution.d.ts +41 -10
- package/dist/proxy/spend-attribution.d.ts.map +1 -1
- package/dist/proxy/spend-attribution.js +133 -37
- package/dist/proxy/spend-attribution.js.map +1 -1
- package/dist/proxy/tee-control.d.ts +3 -1
- package/dist/proxy/tee-control.d.ts.map +1 -1
- package/dist/proxy/tee-control.js +5 -3
- package/dist/proxy/tee-control.js.map +1 -1
- package/dist/proxy/telemetry.d.ts +2 -1
- package/dist/proxy/telemetry.d.ts.map +1 -1
- package/dist/proxy/telemetry.js +10 -5
- package/dist/proxy/telemetry.js.map +1 -1
- package/dist/routing-policy/policy.d.ts +149 -0
- package/dist/routing-policy/policy.d.ts.map +1 -0
- package/dist/routing-policy/policy.js +450 -0
- package/dist/routing-policy/policy.js.map +1 -0
- package/dist/routing-policy/policy.test.d.ts +2 -0
- package/dist/routing-policy/policy.test.d.ts.map +1 -0
- package/dist/routing-policy/policy.test.js +134 -0
- package/dist/routing-policy/policy.test.js.map +1 -0
- package/dist/system-proxy/proxy-server.js +2 -2
- package/dist/system-proxy/proxy-server.js.map +1 -1
- package/dist/system-proxy/proxy-server.test.js +40 -0
- package/dist/system-proxy/proxy-server.test.js.map +1 -1
- package/package.json +16 -7
package/dist/gateway/server.js
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
1
2
|
import * as http from 'node:http';
|
|
2
3
|
import { DEFAULT_BUYER_IDENTITY } from '@antseed/node';
|
|
3
4
|
import { SPEND_ATTRIBUTION_HEADER } from '../proxy/spend-attribution.js';
|
|
4
5
|
import { BUYER_IDENTITY_HEADER } from '../proxy/request-utils.js';
|
|
5
|
-
import {
|
|
6
|
+
import { GATEWAY_CONTROL_HEADER, ROUTING_POLICY_HEADER, encodePolicyHeader, meaningfulPolicy, policyAllowsModel } from '../routing-policy/policy.js';
|
|
7
|
+
import { effectiveKeyLimits, newRequestTag } from './accounting.js';
|
|
8
|
+
import { errorMessage } from './errors.js';
|
|
9
|
+
import { isClientCredentialHeader } from '../proxy/credential-headers.js';
|
|
6
10
|
import { parseBearerToken } from './keys.js';
|
|
7
|
-
import {
|
|
11
|
+
import { BUDGET_PERIODS } from './limits.js';
|
|
8
12
|
import { formatUsdc, optionalUsdcToDecimalString, parseUsdToUsdc, usdcToDecimalString } from './money.js';
|
|
13
|
+
import { OtlpExporter, observabilitySettings } from './observability.js';
|
|
14
|
+
import { isEmptyPolicy, resolvePolicy } from './policy-resolver.js';
|
|
15
|
+
import { END_USER_HEADER, applyPreset, effectiveRequestModel, extractEndUser, presetSlug } from './request-shaping.js';
|
|
16
|
+
import { ResponseUsageReader } from './response-usage.js';
|
|
17
|
+
import { SPEND_FEED_UNAUTHORIZED_HINT } from './spend-feed.js';
|
|
9
18
|
import { PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, X402_VERSION, buildPaymentRequirements, checkPaymentPayload, decodeHeaderJson, encodeHeaderJson, } from './x402.js';
|
|
19
|
+
/**
|
|
20
|
+
* The gateway's own components (the console chat agent) call `/v1` as a key
|
|
21
|
+
* by its id, without its secret: this header plus the control secret, from
|
|
22
|
+
* loopback only. Stripped from everything forwarded to the buyer.
|
|
23
|
+
*/
|
|
24
|
+
export const GATEWAY_INTERNAL_KEY_HEADER = 'x-antseed-gateway-key';
|
|
10
25
|
const HOP_BY_HOP = new Set([
|
|
11
26
|
'connection',
|
|
12
27
|
'keep-alive',
|
|
@@ -21,6 +36,19 @@ const HOP_BY_HOP = new Set([
|
|
|
21
36
|
const MAX_MODEL_SNIFF_BYTES = 4 * 1024 * 1024;
|
|
22
37
|
/** Largest request body the gateway accepts, matching the buyer's default upload limit. */
|
|
23
38
|
const MAX_BODY_BYTES = 64 * 1024 * 1024;
|
|
39
|
+
/** How much of a failed response is read for its error code and message. */
|
|
40
|
+
const MAX_ERROR_BODY_BYTES = 16 * 1024;
|
|
41
|
+
const MAX_ERROR_MESSAGE_CHARS = 500;
|
|
42
|
+
/** Request and response bodies kept per request while content logging is on. */
|
|
43
|
+
const MAX_LOGGED_CONTENT_BYTES = 64 * 1024;
|
|
44
|
+
const RETENTION_SWEEP_MS = 60 * 60 * 1000;
|
|
45
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
46
|
+
/** Why a key with caps cannot be served while its buyer's spend feed is not reporting. */
|
|
47
|
+
const SPEND_FEED_UNAVAILABLE_MESSAGES = {
|
|
48
|
+
unsupported: 'The buyer for this API key does not report spend; upgrade it to enforce spend limits',
|
|
49
|
+
unauthorized: `The buyer for this API key does not report spend to this gateway; ${SPEND_FEED_UNAUTHORIZED_HINT}`,
|
|
50
|
+
unreachable: 'The buyer for this API key is not reachable',
|
|
51
|
+
};
|
|
24
52
|
const KEY_INFO_PATH = '/v1/key';
|
|
25
53
|
const TOPUP_PATH = '/v1/key/topup';
|
|
26
54
|
/**
|
|
@@ -47,8 +75,12 @@ export class GatewayServer {
|
|
|
47
75
|
_options;
|
|
48
76
|
_server = null;
|
|
49
77
|
_port = 0;
|
|
78
|
+
_retentionTimer = null;
|
|
79
|
+
_pruning = null;
|
|
80
|
+
_exporter;
|
|
50
81
|
constructor(_options) {
|
|
51
82
|
this._options = _options;
|
|
83
|
+
this._exporter = _options.exporter ?? new OtlpExporter(() => observabilitySettings(_options.store), { onLog: (m) => this._log(m) });
|
|
52
84
|
}
|
|
53
85
|
get port() {
|
|
54
86
|
return this._port;
|
|
@@ -58,7 +90,7 @@ export class GatewayServer {
|
|
|
58
90
|
return this._port;
|
|
59
91
|
this._server = http.createServer((req, res) => {
|
|
60
92
|
this._handle(req, res).catch((error) => {
|
|
61
|
-
this._log(`gateway error: ${
|
|
93
|
+
this._log(`gateway error: ${errorMessage(error)}`);
|
|
62
94
|
if (!res.headersSent)
|
|
63
95
|
sendError(res, 500, 'api_error', 'internal_error', 'Gateway error');
|
|
64
96
|
else
|
|
@@ -70,12 +102,42 @@ export class GatewayServer {
|
|
|
70
102
|
this._server.listen(this._options.listenPort ?? 0, this._options.listenHost ?? '127.0.0.1', () => resolve());
|
|
71
103
|
});
|
|
72
104
|
this._port = this._server.address().port;
|
|
105
|
+
void this.pruneRequestLog();
|
|
106
|
+
this._retentionTimer = setInterval(() => { void this.pruneRequestLog(); }, RETENTION_SWEEP_MS);
|
|
107
|
+
this._retentionTimer.unref?.();
|
|
73
108
|
return this._port;
|
|
74
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Applies the request-log retention setting; resolves to rows removed. A
|
|
112
|
+
* large backlog is pruned one chunk per event-loop turn, and a sweep that
|
|
113
|
+
* is still running is joined rather than started twice.
|
|
114
|
+
*/
|
|
115
|
+
pruneRequestLog(now = Date.now()) {
|
|
116
|
+
if (this._pruning)
|
|
117
|
+
return this._pruning;
|
|
118
|
+
const { retentionDays } = observabilitySettings(this._options.store);
|
|
119
|
+
if (!retentionDays)
|
|
120
|
+
return Promise.resolve(0);
|
|
121
|
+
this._pruning = this._options.store.pruneRequests(now - retentionDays * DAY_MS)
|
|
122
|
+
.then((removed) => {
|
|
123
|
+
if (removed > 0)
|
|
124
|
+
this._log(`pruned ${removed} request log row(s) older than ${retentionDays} day(s)`);
|
|
125
|
+
return removed;
|
|
126
|
+
}, (error) => {
|
|
127
|
+
this._log(`gateway could not prune the request log: ${errorMessage(error)}`);
|
|
128
|
+
return 0;
|
|
129
|
+
})
|
|
130
|
+
.finally(() => { this._pruning = null; });
|
|
131
|
+
return this._pruning;
|
|
132
|
+
}
|
|
75
133
|
async stop() {
|
|
76
134
|
const server = this._server;
|
|
77
135
|
this._server = null;
|
|
78
136
|
this._port = 0;
|
|
137
|
+
if (this._retentionTimer)
|
|
138
|
+
clearInterval(this._retentionTimer);
|
|
139
|
+
this._retentionTimer = null;
|
|
140
|
+
await this._exporter.stop();
|
|
79
141
|
if (!server)
|
|
80
142
|
return;
|
|
81
143
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
@@ -86,26 +148,21 @@ export class GatewayServer {
|
|
|
86
148
|
async _handle(req, res) {
|
|
87
149
|
const method = req.method ?? 'GET';
|
|
88
150
|
const path = req.url ?? '/';
|
|
151
|
+
const pathname = path.split('?')[0];
|
|
152
|
+
if (this._options.console && (pathname === '/console' || pathname.startsWith('/console/'))) {
|
|
153
|
+
if (await this._options.console.handle(req, res))
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
89
156
|
const route = canonicalizeRoute(method, path);
|
|
90
157
|
if (!route) {
|
|
91
158
|
this._log(`gateway rejected route: ${method} ${path}`);
|
|
92
159
|
sendError(res, 404, 'invalid_request_error', 'not_found', 'Not found');
|
|
93
160
|
return;
|
|
94
161
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
const key = secret ? this._options.store.findKeyBySecret(secret) : null;
|
|
98
|
-
if (!key || key.status !== 'active') {
|
|
99
|
-
this._log(`gateway rejected authentication: ${method} ${path}`);
|
|
100
|
-
res.setHeader('www-authenticate', 'Bearer');
|
|
101
|
-
sendError(res, 401, 'authentication_error', key ? 'key_revoked' : 'invalid_api_key', key ? 'API key has been revoked' : 'Invalid API key');
|
|
162
|
+
const authenticated = this._authenticate(req, res, `${method} ${path}`);
|
|
163
|
+
if (!authenticated)
|
|
102
164
|
return;
|
|
103
|
-
}
|
|
104
|
-
if (key.expiresAt !== null && key.expiresAt <= Date.now()) {
|
|
105
|
-
res.setHeader('www-authenticate', 'Bearer');
|
|
106
|
-
sendError(res, 401, 'authentication_error', 'key_expired', 'API key has expired');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
165
|
+
const { key, context } = authenticated;
|
|
109
166
|
if (route.local) {
|
|
110
167
|
if (route.prefix === TOPUP_PATH)
|
|
111
168
|
await this._topup(req, res, key);
|
|
@@ -113,110 +170,324 @@ export class GatewayServer {
|
|
|
113
170
|
sendJson(res, 200, { data: await this._keyInfo(key) });
|
|
114
171
|
return;
|
|
115
172
|
}
|
|
116
|
-
const buyerPort = this._options.buyerPort;
|
|
117
173
|
// Caps are only as good as the spend that reaches the ledger, so a key
|
|
118
174
|
// with caps fails closed while its buyer is not reporting spend.
|
|
119
|
-
if (route.paid &&
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (state !== 'reporting') {
|
|
123
|
-
sendError(res, 503, 'api_error', 'spend_tracking_unavailable', state === 'unsupported'
|
|
124
|
-
? 'The buyer for this API key does not report spend; upgrade it to enforce spend limits'
|
|
125
|
-
: 'The buyer for this API key is not reachable');
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const body = await readBody(req);
|
|
175
|
+
if (route.paid && this._options.accounting.hasBudgets(key, context) && !await this._spendFeedReporting(res))
|
|
176
|
+
return;
|
|
177
|
+
let body = await readBody(req);
|
|
130
178
|
if (!body)
|
|
131
179
|
return sendBodyTooLarge(res);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
180
|
+
const contentType = req.headers['content-type'];
|
|
181
|
+
let parsed = parseJsonBody(body, contentType);
|
|
182
|
+
// What the buyer routes by (`service ?? model`), so the allow list and
|
|
183
|
+
// the request log see the model that is actually bought.
|
|
184
|
+
let model = effectiveRequestModel(parsed, body, contentType);
|
|
185
|
+
// `model: "@preset/<slug>"` runs the workspace's (or org's) preset.
|
|
186
|
+
const slug = presetSlug(model);
|
|
187
|
+
const preset = slug ? this._options.store.findPresetBySlug(slug, key.workspaceId) : null;
|
|
188
|
+
if (slug) {
|
|
189
|
+
if (!parsed) {
|
|
190
|
+
sendError(res, 400, 'invalid_request_error', 'preset_requires_json', 'Presets can only be used with JSON request bodies');
|
|
138
191
|
return;
|
|
139
192
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
193
|
+
if (!preset) {
|
|
194
|
+
sendError(res, 400, 'invalid_request_error', 'preset_not_found', `No preset named "${slug}"`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
parsed = applyPreset(parsed, preset, route.prefix);
|
|
198
|
+
body = Buffer.from(JSON.stringify(parsed), 'utf8');
|
|
199
|
+
model = preset.model;
|
|
144
200
|
}
|
|
145
|
-
this.
|
|
201
|
+
const policy = this._routingPolicy(res, route, key, context, preset, model);
|
|
202
|
+
if (!policy.allowed)
|
|
203
|
+
return;
|
|
204
|
+
const tag = this._admit(res, route, key, context);
|
|
205
|
+
if (!tag)
|
|
206
|
+
return;
|
|
207
|
+
const request = {
|
|
146
208
|
tag,
|
|
147
|
-
|
|
148
|
-
buyerIdentity: key.buyerIdentity,
|
|
209
|
+
key,
|
|
149
210
|
method,
|
|
150
|
-
path
|
|
151
|
-
|
|
211
|
+
path,
|
|
212
|
+
buyerPath: route.path,
|
|
213
|
+
requestPath: route.prefix,
|
|
214
|
+
model: model ? model.slice(0, 200) : null,
|
|
215
|
+
endUser: extractEndUser(parsed, firstHeader(req.headers[END_USER_HEADER]) || undefined),
|
|
152
216
|
startedAt: Date.now(),
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
let finished = false;
|
|
157
|
-
const finish = (status, buyerRequestId) => {
|
|
158
|
-
if (finished)
|
|
159
|
-
return;
|
|
160
|
-
finished = true;
|
|
161
|
-
this._options.store.finishRequest(tag, { status, buyerRequestId });
|
|
162
|
-
this._options.accounting.finish(tag);
|
|
217
|
+
body,
|
|
218
|
+
policyHeaders: policy.headers,
|
|
219
|
+
modelListPolicy: route.prefix === '/v1/models' && policy.policy.allowedModels ? policy.policy : null,
|
|
163
220
|
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
221
|
+
try {
|
|
222
|
+
this._options.store.startRequest({
|
|
223
|
+
tag,
|
|
224
|
+
keyId: key.id,
|
|
225
|
+
buyerIdentity: key.buyerIdentity,
|
|
226
|
+
method,
|
|
227
|
+
path: request.requestPath,
|
|
228
|
+
model: request.model,
|
|
229
|
+
startedAt: request.startedAt,
|
|
230
|
+
workspaceId: key.workspaceId,
|
|
231
|
+
memberId: key.ownerMemberId,
|
|
232
|
+
endUser: request.endUser,
|
|
233
|
+
});
|
|
234
|
+
this._options.store.touchKey(key.id);
|
|
175
235
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
res
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
236
|
+
catch (error) {
|
|
237
|
+
// Nothing was sent; the hold must not keep counting against the caps.
|
|
238
|
+
this._options.accounting.release(tag);
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
this._forward(req, res, request);
|
|
242
|
+
}
|
|
243
|
+
/** The request's active API key and who it is accounted to; answers 401 itself otherwise. */
|
|
244
|
+
_authenticate(req, res, requestLine) {
|
|
245
|
+
const store = this._options.store;
|
|
246
|
+
const key = this._requestKey(req);
|
|
247
|
+
if (!key || key.status !== 'active') {
|
|
248
|
+
this._log(`gateway rejected authentication: ${requestLine}`);
|
|
249
|
+
if (key)
|
|
250
|
+
sendUnauthorized(res, 'key_revoked', 'API key has been revoked');
|
|
251
|
+
else
|
|
252
|
+
sendUnauthorized(res, 'invalid_api_key', 'Invalid API key');
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
if (key.expiresAt !== null && key.expiresAt <= Date.now()) {
|
|
256
|
+
sendUnauthorized(res, 'key_expired', 'API key has expired');
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
// Loaded once and shared by policy resolution and budget admission.
|
|
260
|
+
const member = key.ownerMemberId ? store.getMember(key.ownerMemberId) : null;
|
|
261
|
+
if (member?.status === 'disabled') {
|
|
262
|
+
sendUnauthorized(res, 'key_revoked', 'API key has been revoked');
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return { key, context: { member, workspace: store.getWorkspace(key.workspaceId) } };
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The key a request names: by id for the gateway's own components (see
|
|
269
|
+
* GATEWAY_INTERNAL_KEY_HEADER), else by its Bearer secret. The id header is
|
|
270
|
+
* only honored from an internal caller; from anyone else it is ignored, so
|
|
271
|
+
* it can neither stand in for a key nor block a valid Bearer one.
|
|
272
|
+
*/
|
|
273
|
+
_requestKey(req) {
|
|
274
|
+
const internalKeyId = firstHeader(req.headers[GATEWAY_INTERNAL_KEY_HEADER]);
|
|
275
|
+
if (internalKeyId && this._internalCaller(req))
|
|
276
|
+
return this._options.store.getKey(internalKeyId);
|
|
277
|
+
const secret = parseBearerToken(req.headers.authorization);
|
|
278
|
+
return secret ? this._options.store.findKeyBySecret(secret) : null;
|
|
279
|
+
}
|
|
280
|
+
/** A request from the gateway process itself: loopback, carrying the control secret. */
|
|
281
|
+
_internalCaller(req) {
|
|
282
|
+
const expected = this._options.controlSecret;
|
|
283
|
+
const sent = firstHeader(req.headers[GATEWAY_CONTROL_HEADER]);
|
|
284
|
+
if (!expected || !sent || !isLoopback(req.socket.remoteAddress))
|
|
285
|
+
return false;
|
|
286
|
+
const a = Buffer.from(sent);
|
|
287
|
+
const b = Buffer.from(expected);
|
|
288
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
289
|
+
}
|
|
290
|
+
/** Whether the buyer reports spend, refreshing the feed once; answers 503 itself when it does not. */
|
|
291
|
+
async _spendFeedReporting(res) {
|
|
292
|
+
if (this._options.spendFeedState() === 'reporting')
|
|
293
|
+
return true;
|
|
294
|
+
await this._options.refreshSpendFeed();
|
|
295
|
+
const state = this._options.spendFeedState();
|
|
296
|
+
if (state === 'reporting')
|
|
297
|
+
return true;
|
|
298
|
+
sendError(res, 503, 'api_error', 'spend_tracking_unavailable', SPEND_FEED_UNAVAILABLE_MESSAGES[state]);
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The key's effective routing policy: refuses (answering itself) a model
|
|
303
|
+
* it does not allow, or a seller restriction the buyer would not apply.
|
|
304
|
+
* Settings that change nothing (the default sort, flags set to false) are
|
|
305
|
+
* not sent: a request without restrictions reaches the buyer exactly like
|
|
306
|
+
* one through a gateway without policies.
|
|
307
|
+
*/
|
|
308
|
+
_routingPolicy(res, route, key, context, preset, model) {
|
|
309
|
+
const { policy } = resolvePolicy(this._options.store, { key, preset, member: context.member, workspace: context.workspace });
|
|
310
|
+
if ((route.paid || model) && !policyAllowsModel(policy, model)) {
|
|
311
|
+
sendError(res, 403, 'permission_error', 'model_not_allowed', model
|
|
312
|
+
? `Model "${model}" is not allowed for this API key`
|
|
313
|
+
: 'This API key may only use specific models; name one in the request');
|
|
314
|
+
return { allowed: false };
|
|
315
|
+
}
|
|
316
|
+
const routed = meaningfulPolicy(policy);
|
|
317
|
+
if (isEmptyPolicy(routed))
|
|
318
|
+
return { allowed: true, headers: {}, policy };
|
|
319
|
+
const controlSecret = this._options.controlSecret ?? null;
|
|
320
|
+
const sellersRestricted = restrictsSellers(routed);
|
|
321
|
+
if (!controlSecret && sellersRestricted) {
|
|
322
|
+
sendError(res, 503, 'api_error', 'routing_policy_unavailable', 'This API key has a routing policy the gateway cannot pass to the buyer');
|
|
323
|
+
return { allowed: false };
|
|
324
|
+
}
|
|
325
|
+
if (route.paid && sellersRestricted && this._options.buyerPolicyUnsupported?.()) {
|
|
326
|
+
sendError(res, 503, 'api_error', 'buyer_policy_unsupported', "The buyer does not apply this API key's routing policy; upgrade it or check the gateway control secret");
|
|
327
|
+
return { allowed: false };
|
|
328
|
+
}
|
|
329
|
+
if (!controlSecret)
|
|
330
|
+
return { allowed: true, headers: {}, policy };
|
|
331
|
+
return { allowed: true, headers: { [ROUTING_POLICY_HEADER]: encodePolicyHeader(routed), [GATEWAY_CONTROL_HEADER]: controlSecret }, policy };
|
|
332
|
+
}
|
|
333
|
+
/** The request's tag; a paid request is admitted against its budgets first (402 answered here when one is spent). */
|
|
334
|
+
_admit(res, route, key, context) {
|
|
335
|
+
if (!route.paid)
|
|
336
|
+
return newRequestTag();
|
|
337
|
+
const admission = this._options.accounting.admit(key, context);
|
|
338
|
+
if (admission.ok)
|
|
339
|
+
return admission.tag;
|
|
340
|
+
this._log(`gateway spend limit reached: key=${key.id} level=${admission.breach.level ?? 'key'} period=${admission.breach.period}`);
|
|
341
|
+
sendJson(res, 402, { error: spendLimitError(admission.breach) });
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Sends an admitted request to the buyer and streams the answer back.
|
|
346
|
+
* Every path must finish the request (and so release or start expiring
|
|
347
|
+
* its hold); an unexpected throw must not leak it.
|
|
348
|
+
*/
|
|
349
|
+
_forward(req, res, request) {
|
|
350
|
+
const { tag, key, method, startedAt, endUser, body } = request;
|
|
351
|
+
const buyerPort = this._options.buyerPort;
|
|
352
|
+
let finish = null;
|
|
353
|
+
let sentToBuyer = false;
|
|
354
|
+
try {
|
|
355
|
+
this._log(`gateway request: key=${key.id} identity=${key.buyerIdentity} ${method} ${request.path} -> ${request.buyerPath}`);
|
|
356
|
+
const observability = observabilitySettings(this._options.store);
|
|
357
|
+
const requestContent = observability.logContent ? truncateContent(body) : null;
|
|
358
|
+
let responseChunks = [];
|
|
359
|
+
// The start of a failed response, read whatever the content setting, for its error code and message.
|
|
360
|
+
let errorChunks = [];
|
|
361
|
+
let gatewayError = null;
|
|
362
|
+
let sellerPeerId = null;
|
|
363
|
+
let reportedLatency = null;
|
|
364
|
+
let servedFree = false;
|
|
365
|
+
// Token counts the response reports, kept on the request until (or if
|
|
366
|
+
// the buyer never reports) its spend.
|
|
367
|
+
let usageReader = null;
|
|
368
|
+
let finished = false;
|
|
369
|
+
finish = (status, buyerRequestId) => {
|
|
370
|
+
if (finished)
|
|
371
|
+
return;
|
|
372
|
+
finished = true;
|
|
373
|
+
const finishedAt = Date.now();
|
|
374
|
+
const latencyMs = reportedLatency ?? finishedAt - startedAt;
|
|
375
|
+
const responseContent = observability.logContent ? truncateContent(Buffer.concat(responseChunks)) : null;
|
|
376
|
+
const store = this._options.store;
|
|
377
|
+
try {
|
|
378
|
+
const error = status >= 400 ? gatewayError ?? parseErrorBody(Buffer.concat(errorChunks), status) : null;
|
|
379
|
+
store.finishRequest(tag, { status, buyerRequestId, error });
|
|
380
|
+
store.recordRequestOutcome(tag, { sellerPeerId, latencyMs, endUser, servedFree });
|
|
381
|
+
const usage = usageReader?.result() ?? null;
|
|
382
|
+
if (usage)
|
|
383
|
+
store.recordResponseUsage(tag, usage);
|
|
384
|
+
if (observability.logContent)
|
|
385
|
+
store.recordRequestContent(tag, { requestBody: requestContent, responseBody: responseContent });
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
this._log(`gateway could not record request ${tag}: ${errorMessage(error)}`);
|
|
389
|
+
}
|
|
390
|
+
this._options.accounting.finish(tag);
|
|
391
|
+
this._exporter.record({
|
|
392
|
+
tag, method, path: request.requestPath, model: request.model, status, startedAt, finishedAt,
|
|
393
|
+
keyId: key.id, workspaceId: key.workspaceId, memberId: key.ownerMemberId, endUser, sellerPeerId, latencyMs,
|
|
394
|
+
...(observability.logContent ? { requestBody: requestContent, responseBody: responseContent } : {}),
|
|
395
|
+
});
|
|
396
|
+
};
|
|
397
|
+
const headers = { ...forwardedHeaders(req.headers), ...request.policyHeaders };
|
|
398
|
+
headers.host = `127.0.0.1:${buyerPort}`;
|
|
399
|
+
headers.connection = 'close';
|
|
400
|
+
headers['content-length'] = String(body.length);
|
|
401
|
+
headers['x-antseed-system-proxy-source'] = tunnelRequestSource(req.headers);
|
|
402
|
+
headers[SPEND_ATTRIBUTION_HEADER] = tag;
|
|
403
|
+
if (key.buyerIdentity !== DEFAULT_BUYER_IDENTITY) {
|
|
404
|
+
headers[BUYER_IDENTITY_HEADER] = key.buyerIdentity;
|
|
405
|
+
// The buyer lets only its gateway pay from a non-default wallet.
|
|
406
|
+
const controlSecret = this._options.controlSecret;
|
|
407
|
+
if (controlSecret)
|
|
408
|
+
headers[GATEWAY_CONTROL_HEADER] = controlSecret;
|
|
209
409
|
}
|
|
410
|
+
const upstream = http.request({
|
|
411
|
+
hostname: '127.0.0.1',
|
|
412
|
+
port: buyerPort,
|
|
413
|
+
method,
|
|
414
|
+
path: request.buyerPath,
|
|
415
|
+
headers,
|
|
416
|
+
}, (upstreamRes) => {
|
|
417
|
+
const status = upstreamRes.statusCode ?? 502;
|
|
418
|
+
const buyerRequestId = firstHeader(upstreamRes.headers['x-antseed-request-id']) || null;
|
|
419
|
+
sellerPeerId = firstHeader(upstreamRes.headers['x-antseed-peer-id']).slice(0, 200) || null;
|
|
420
|
+
reportedLatency = latencyHeader(firstHeader(upstreamRes.headers['x-antseed-latency-ms']));
|
|
421
|
+
servedFree = freeSellerPricing(upstreamRes.headers);
|
|
422
|
+
if (observability.logContent)
|
|
423
|
+
responseChunks = collectPrefix(upstreamRes, MAX_LOGGED_CONTENT_BYTES);
|
|
424
|
+
if (status >= 400)
|
|
425
|
+
errorChunks = collectPrefix(upstreamRes, MAX_ERROR_BODY_BYTES);
|
|
426
|
+
else if (request.model !== null)
|
|
427
|
+
usageReader = readUsage(upstreamRes, (message) => this._log(message));
|
|
428
|
+
const responseHeaders = {};
|
|
429
|
+
for (const [name, value] of Object.entries(upstreamRes.headers)) {
|
|
430
|
+
if (!HOP_BY_HOP.has(name.toLowerCase()) && value !== undefined)
|
|
431
|
+
responseHeaders[name] = value;
|
|
432
|
+
}
|
|
433
|
+
responseHeaders.connection = 'close';
|
|
434
|
+
upstreamRes.once('error', () => finish(status, buyerRequestId));
|
|
435
|
+
res.once('close', () => finish(status, buyerRequestId));
|
|
436
|
+
const modelListPolicy = request.modelListPolicy;
|
|
437
|
+
if (modelListPolicy && status === 200) {
|
|
438
|
+
const chunks = [];
|
|
439
|
+
upstreamRes.on('data', (chunk) => chunks.push(chunk));
|
|
440
|
+
upstreamRes.once('end', () => {
|
|
441
|
+
const listing = filterModelList(Buffer.concat(chunks), modelListPolicy);
|
|
442
|
+
res.writeHead(status, { ...responseHeaders, 'content-length': String(listing.length) });
|
|
443
|
+
res.end(listing);
|
|
444
|
+
finish(status, buyerRequestId);
|
|
445
|
+
});
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
res.writeHead(status, responseHeaders);
|
|
449
|
+
upstreamRes.pipe(res);
|
|
450
|
+
upstreamRes.once('end', () => finish(status, buyerRequestId));
|
|
451
|
+
});
|
|
452
|
+
upstream.on('error', (error) => {
|
|
453
|
+
this._log(`gateway upstream error: ${error.message}`);
|
|
454
|
+
gatewayError = { code: 'buyer_unavailable', message: 'Antseed buyer proxy is unavailable' };
|
|
455
|
+
finish(502, null);
|
|
456
|
+
if (!res.headersSent) {
|
|
457
|
+
sendError(res, 502, 'api_error', 'buyer_unavailable', 'Antseed buyer proxy is unavailable');
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
res.destroy();
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
// A client that disconnects mid-stream should stop the paid request too.
|
|
464
|
+
res.once('close', () => {
|
|
465
|
+
if (!res.writableFinished)
|
|
466
|
+
upstream.destroy();
|
|
467
|
+
});
|
|
468
|
+
sentToBuyer = true;
|
|
469
|
+
upstream.end(body);
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
this._log(`gateway error after admission: ${errorMessage(error)}`);
|
|
473
|
+
if (finish)
|
|
474
|
+
finish(500, null);
|
|
210
475
|
else {
|
|
211
|
-
|
|
476
|
+
try {
|
|
477
|
+
this._options.store.finishRequest(tag, { status: 500, buyerRequestId: null, error: { code: 'internal_error', message: 'Gateway error' } });
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
// Already logged above; the hold still goes.
|
|
481
|
+
}
|
|
212
482
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!res.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
483
|
+
// A request the buyer never saw cannot be signed for: drop its hold now.
|
|
484
|
+
if (!sentToBuyer)
|
|
485
|
+
this._options.accounting.release(tag);
|
|
486
|
+
if (!res.headersSent)
|
|
487
|
+
sendError(res, 500, 'api_error', 'internal_error', 'Gateway error');
|
|
488
|
+
else
|
|
489
|
+
res.destroy();
|
|
490
|
+
}
|
|
220
491
|
}
|
|
221
492
|
/**
|
|
222
493
|
* x402 top-up: the key holder pays USDC straight to the key's buyer wallet.
|
|
@@ -308,7 +579,7 @@ export class GatewayServer {
|
|
|
308
579
|
});
|
|
309
580
|
}
|
|
310
581
|
catch (error) {
|
|
311
|
-
this._log(`gateway top-up settled but NOT recorded in the ledger: key=${key.id} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}: ${
|
|
582
|
+
this._log(`gateway top-up settled but NOT recorded in the ledger: key=${key.id} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}: ${errorMessage(error)}`);
|
|
312
583
|
}
|
|
313
584
|
this._log(`gateway top-up: key=${key.id} identity=${key.buyerIdentity} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}`);
|
|
314
585
|
res.setHeader(PAYMENT_RESPONSE_HEADER, encodeHeaderJson(settled));
|
|
@@ -335,16 +606,18 @@ export class GatewayServer {
|
|
|
335
606
|
return await topup.facilitator.settle(payment, requirements);
|
|
336
607
|
}
|
|
337
608
|
catch (error) {
|
|
338
|
-
this._log(`gateway facilitator error: ${
|
|
609
|
+
this._log(`gateway facilitator error: ${errorMessage(error)}`);
|
|
339
610
|
return failure('unexpected_settle_error');
|
|
340
611
|
}
|
|
341
612
|
}
|
|
342
613
|
async _keyInfo(key) {
|
|
343
|
-
const spent = this._options.store.
|
|
614
|
+
const spent = this._options.store.spendByPeriod({ keyId: key.id });
|
|
344
615
|
const usage = this._options.store.usageStats(key.id);
|
|
345
616
|
const buyerAddress = await this._options.identityAddress(key.buyerIdentity).catch(() => null);
|
|
346
|
-
|
|
347
|
-
|
|
617
|
+
// The caps admission enforces: the lower of the admins' and the owner's.
|
|
618
|
+
const caps = effectiveKeyLimits(key);
|
|
619
|
+
const limits = Object.fromEntries(BUDGET_PERIODS.map((period) => {
|
|
620
|
+
const limit = caps[period];
|
|
348
621
|
return [period, {
|
|
349
622
|
limit_usd: optionalUsdcToDecimalString(limit),
|
|
350
623
|
spent_usd: usdcToDecimalString(spent[period]),
|
|
@@ -378,11 +651,13 @@ export class GatewayServer {
|
|
|
378
651
|
*/
|
|
379
652
|
function spendLimitError(breach) {
|
|
380
653
|
const label = breach.period === 'total' ? 'lifetime' : breach.period;
|
|
654
|
+
const level = breach.level ?? 'key';
|
|
381
655
|
return {
|
|
382
656
|
type: 'insufficient_quota',
|
|
383
657
|
code: 'spend_limit_reached',
|
|
384
|
-
message:
|
|
658
|
+
message: `${budgetHolder(level)} reached its ${label} spend limit of ${formatUsdc(breach.limitUsdc)}.`,
|
|
385
659
|
limit: {
|
|
660
|
+
level,
|
|
386
661
|
period: breach.period,
|
|
387
662
|
limit_usd: usdcToDecimalString(breach.limitUsdc),
|
|
388
663
|
spent_usd: usdcToDecimalString(breach.spentUsdc),
|
|
@@ -390,6 +665,13 @@ function spendLimitError(breach) {
|
|
|
390
665
|
},
|
|
391
666
|
};
|
|
392
667
|
}
|
|
668
|
+
function budgetHolder(level) {
|
|
669
|
+
if (level === 'key')
|
|
670
|
+
return 'This API key';
|
|
671
|
+
if (level === 'member')
|
|
672
|
+
return 'The member who owns this API key';
|
|
673
|
+
return 'This API key\'s workspace';
|
|
674
|
+
}
|
|
393
675
|
function sendJson(res, status, payload) {
|
|
394
676
|
res.writeHead(status, { 'content-type': 'application/json' });
|
|
395
677
|
res.end(JSON.stringify(payload));
|
|
@@ -397,6 +679,10 @@ function sendJson(res, status, payload) {
|
|
|
397
679
|
function sendError(res, status, type, code, message) {
|
|
398
680
|
sendJson(res, status, { error: { message, type, code } });
|
|
399
681
|
}
|
|
682
|
+
function sendUnauthorized(res, code, message) {
|
|
683
|
+
res.setHeader('www-authenticate', 'Bearer');
|
|
684
|
+
sendError(res, 401, 'authentication_error', code, message);
|
|
685
|
+
}
|
|
400
686
|
/** The request body, or null once it exceeds MAX_BODY_BYTES (the rest is drained, not kept). */
|
|
401
687
|
async function readBody(req) {
|
|
402
688
|
if (Number(req.headers['content-length']) > MAX_BODY_BYTES) {
|
|
@@ -415,19 +701,132 @@ async function readBody(req) {
|
|
|
415
701
|
function sendBodyTooLarge(res) {
|
|
416
702
|
sendError(res, 413, 'invalid_request_error', 'request_too_large', `Request bodies are limited to ${MAX_BODY_BYTES / 1024 / 1024} MiB`);
|
|
417
703
|
}
|
|
418
|
-
|
|
704
|
+
/** A JSON object body, or null (empty, too large to inspect, not JSON, not an object). */
|
|
705
|
+
function parseJsonBody(body, contentType) {
|
|
419
706
|
if (body.length === 0 || body.length > MAX_MODEL_SNIFF_BYTES)
|
|
420
707
|
return null;
|
|
421
708
|
if (contentType && !contentType.includes('json'))
|
|
422
709
|
return null;
|
|
423
710
|
try {
|
|
424
|
-
|
|
425
|
-
return typeof parsed.model === 'string' ? parsed.model.slice(0, 200) : null;
|
|
711
|
+
return jsonObject(JSON.parse(body.toString('utf8')));
|
|
426
712
|
}
|
|
427
713
|
catch {
|
|
428
714
|
return null;
|
|
429
715
|
}
|
|
430
716
|
}
|
|
717
|
+
function jsonObject(value) {
|
|
718
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Error code and message of a failed response: the OpenAI/Anthropic envelope
|
|
722
|
+
* (`{ error: { code | type, message } }`, `{ error: "…" }`), a top-level
|
|
723
|
+
* `{ code, message }`, or the start of a non-JSON body.
|
|
724
|
+
*/
|
|
725
|
+
export function parseErrorBody(body, status) {
|
|
726
|
+
const text = body.subarray(0, MAX_ERROR_BODY_BYTES).toString('utf8').trim();
|
|
727
|
+
const fallback = `http_${status}`;
|
|
728
|
+
const clip = (value) => value ? value.slice(0, MAX_ERROR_MESSAGE_CHARS) : null;
|
|
729
|
+
let parsed;
|
|
730
|
+
try {
|
|
731
|
+
parsed = JSON.parse(text);
|
|
732
|
+
}
|
|
733
|
+
catch {
|
|
734
|
+
return { code: fallback, message: clip(text.replace(/\s+/g, ' ')) };
|
|
735
|
+
}
|
|
736
|
+
const pick = (value) => typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
737
|
+
const root = jsonObject(parsed) ?? {};
|
|
738
|
+
const envelope = root['error'];
|
|
739
|
+
if (typeof envelope === 'string')
|
|
740
|
+
return { code: pick(root['code']) ?? fallback, message: clip(envelope) };
|
|
741
|
+
const inner = jsonObject(envelope) ?? root;
|
|
742
|
+
return {
|
|
743
|
+
code: (pick(inner['code']) ?? pick(inner['type']) ?? fallback).slice(0, 100),
|
|
744
|
+
message: clip(pick(inner['message']) ?? pick(root['message']) ?? pick(root['detail'])),
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
/** Keeps the first `maxBytes` (or so) of a stream as it flows past. */
|
|
748
|
+
function collectPrefix(stream, maxBytes) {
|
|
749
|
+
const chunks = [];
|
|
750
|
+
let bytes = 0;
|
|
751
|
+
stream.on('data', (chunk) => {
|
|
752
|
+
if (bytes >= maxBytes)
|
|
753
|
+
return;
|
|
754
|
+
chunks.push(chunk);
|
|
755
|
+
bytes += chunk.length;
|
|
756
|
+
});
|
|
757
|
+
return chunks;
|
|
758
|
+
}
|
|
759
|
+
/** Feeds a successful model response to a usage reader as it streams; a reader error only stops reading. */
|
|
760
|
+
function readUsage(stream, log) {
|
|
761
|
+
const reader = new ResponseUsageReader(firstHeader(stream.headers['content-type']));
|
|
762
|
+
const onData = (chunk) => {
|
|
763
|
+
try {
|
|
764
|
+
reader.push(chunk);
|
|
765
|
+
}
|
|
766
|
+
catch (error) {
|
|
767
|
+
stream.off('data', onData);
|
|
768
|
+
log(`gateway could not read response usage: ${errorMessage(error)}`);
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
stream.on('data', onData);
|
|
772
|
+
return reader;
|
|
773
|
+
}
|
|
774
|
+
/** The buyer's own latency measurement, when it sent a usable one. */
|
|
775
|
+
/**
|
|
776
|
+
* Whether the seller's advertised prices (the buyer's pricing headers) are
|
|
777
|
+
* all zero: a free seller, for which the buyer never reports spend. Unknown
|
|
778
|
+
* input or output prices are not free.
|
|
779
|
+
*/
|
|
780
|
+
function freeSellerPricing(headers) {
|
|
781
|
+
const price = (name) => {
|
|
782
|
+
const value = firstHeader(headers[name]);
|
|
783
|
+
const amount = Number(value);
|
|
784
|
+
return value && Number.isFinite(amount) ? amount : null;
|
|
785
|
+
};
|
|
786
|
+
const cached = price('x-antseed-cached-input-usd-per-million');
|
|
787
|
+
return price('x-antseed-input-usd-per-million') === 0 && price('x-antseed-output-usd-per-million') === 0 && (cached === null || cached === 0);
|
|
788
|
+
}
|
|
789
|
+
function latencyHeader(value) {
|
|
790
|
+
const latency = Number(value);
|
|
791
|
+
return value && Number.isFinite(latency) && latency >= 0 ? Math.floor(latency) : null;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Client headers never forwarded: the gateway sets its own `host` and
|
|
795
|
+
* `content-length`, and the key (never the client) decides who pays, how
|
|
796
|
+
* spend is tagged and which sellers may serve.
|
|
797
|
+
*/
|
|
798
|
+
const STRIPPED_HEADERS = new Set([
|
|
799
|
+
'host',
|
|
800
|
+
'content-length',
|
|
801
|
+
SPEND_ATTRIBUTION_HEADER,
|
|
802
|
+
BUYER_IDENTITY_HEADER,
|
|
803
|
+
ROUTING_POLICY_HEADER,
|
|
804
|
+
GATEWAY_CONTROL_HEADER,
|
|
805
|
+
GATEWAY_INTERNAL_KEY_HEADER,
|
|
806
|
+
END_USER_HEADER,
|
|
807
|
+
]);
|
|
808
|
+
/** Client headers passed on to the buyer, minus everything the key (not the client) decides. */
|
|
809
|
+
function forwardedHeaders(incoming) {
|
|
810
|
+
const headers = {};
|
|
811
|
+
for (const [name, value] of Object.entries(incoming)) {
|
|
812
|
+
const normalized = name.toLowerCase();
|
|
813
|
+
// The client's key authenticated it to this gateway; its other
|
|
814
|
+
// credentials are never needed downstream (see credential-headers.ts).
|
|
815
|
+
if (isClientCredentialHeader(normalized) || STRIPPED_HEADERS.has(normalized))
|
|
816
|
+
continue;
|
|
817
|
+
if (normalized.startsWith('x-forwarded-') || HOP_BY_HOP.has(normalized))
|
|
818
|
+
continue;
|
|
819
|
+
headers[name] = value;
|
|
820
|
+
}
|
|
821
|
+
return headers;
|
|
822
|
+
}
|
|
823
|
+
function truncateContent(body) {
|
|
824
|
+
return body.subarray(0, MAX_LOGGED_CONTENT_BYTES).toString('utf8');
|
|
825
|
+
}
|
|
826
|
+
/** Whether a policy says anything the buyer must apply (the gateway enforces `allowedModels` itself). */
|
|
827
|
+
function restrictsSellers(policy) {
|
|
828
|
+
return Object.keys(policy).some((field) => field !== 'allowedModels' && field !== 'sort' && field !== 'preferFreePeers');
|
|
829
|
+
}
|
|
431
830
|
function tunnelRequestSource(headers) {
|
|
432
831
|
const originator = normalizeSource(firstHeader(headers.originator));
|
|
433
832
|
if (originator)
|
|
@@ -439,12 +838,32 @@ function tunnelRequestSource(headers) {
|
|
|
439
838
|
const product = normalizeSource(userAgent.split(/[/\s]/, 1)[0] ?? '');
|
|
440
839
|
return product.startsWith('cursor') ? 'cursor' : 'public-tunnel';
|
|
441
840
|
}
|
|
841
|
+
function isLoopback(address) {
|
|
842
|
+
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
843
|
+
}
|
|
442
844
|
function firstHeader(value) {
|
|
443
845
|
return Array.isArray(value) ? value[0] ?? '' : value ?? '';
|
|
444
846
|
}
|
|
445
847
|
function normalizeSource(value) {
|
|
446
848
|
return value.trim().toLowerCase().replace(/[^a-z0-9.]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64);
|
|
447
849
|
}
|
|
850
|
+
/** A `/v1/models` listing without the models the policy does not allow (matched by id or alias). */
|
|
851
|
+
function filterModelList(body, policy) {
|
|
852
|
+
let listing;
|
|
853
|
+
try {
|
|
854
|
+
listing = JSON.parse(body.toString('utf8'));
|
|
855
|
+
}
|
|
856
|
+
catch {
|
|
857
|
+
return body;
|
|
858
|
+
}
|
|
859
|
+
if (!listing || !Array.isArray(listing.data))
|
|
860
|
+
return body;
|
|
861
|
+
listing.data = listing.data.filter((entry) => {
|
|
862
|
+
const names = [entry?.id, ...(Array.isArray(entry?.aliases) ? entry.aliases : [])];
|
|
863
|
+
return names.some((name) => typeof name === 'string' && policyAllowsModel(policy, name));
|
|
864
|
+
});
|
|
865
|
+
return Buffer.from(JSON.stringify(listing), 'utf8');
|
|
866
|
+
}
|
|
448
867
|
function canonicalizeRoute(method, path) {
|
|
449
868
|
const queryIndex = path.indexOf('?');
|
|
450
869
|
const pathname = (queryIndex === -1 ? path : path.slice(0, queryIndex)).toLowerCase();
|