@antseed/cli 0.1.179 → 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 +2 -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/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 -44
- 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 +47 -25
- 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 +532 -116
- 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 +873 -117
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/buyer-proxy.test.js +31 -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/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 +44 -4
- package/dist/proxy/deposit-watcher.d.ts.map +1 -1
- package/dist/proxy/deposit-watcher.js +76 -11
- package/dist/proxy/deposit-watcher.js.map +1 -1
- package/dist/proxy/deposit-watcher.test.js +54 -1
- 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/package.json +15 -7
package/dist/gateway/server.js
CHANGED
|
@@ -1,13 +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';
|
|
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';
|
|
5
9
|
import { isClientCredentialHeader } from '../proxy/credential-headers.js';
|
|
6
|
-
import { newRequestTag } from './accounting.js';
|
|
7
10
|
import { parseBearerToken } from './keys.js';
|
|
8
|
-
import {
|
|
11
|
+
import { BUDGET_PERIODS } from './limits.js';
|
|
9
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';
|
|
10
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';
|
|
11
25
|
const HOP_BY_HOP = new Set([
|
|
12
26
|
'connection',
|
|
13
27
|
'keep-alive',
|
|
@@ -22,6 +36,19 @@ const HOP_BY_HOP = new Set([
|
|
|
22
36
|
const MAX_MODEL_SNIFF_BYTES = 4 * 1024 * 1024;
|
|
23
37
|
/** Largest request body the gateway accepts, matching the buyer's default upload limit. */
|
|
24
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
|
+
};
|
|
25
52
|
const KEY_INFO_PATH = '/v1/key';
|
|
26
53
|
const TOPUP_PATH = '/v1/key/topup';
|
|
27
54
|
/**
|
|
@@ -48,8 +75,12 @@ export class GatewayServer {
|
|
|
48
75
|
_options;
|
|
49
76
|
_server = null;
|
|
50
77
|
_port = 0;
|
|
78
|
+
_retentionTimer = null;
|
|
79
|
+
_pruning = null;
|
|
80
|
+
_exporter;
|
|
51
81
|
constructor(_options) {
|
|
52
82
|
this._options = _options;
|
|
83
|
+
this._exporter = _options.exporter ?? new OtlpExporter(() => observabilitySettings(_options.store), { onLog: (m) => this._log(m) });
|
|
53
84
|
}
|
|
54
85
|
get port() {
|
|
55
86
|
return this._port;
|
|
@@ -59,7 +90,7 @@ export class GatewayServer {
|
|
|
59
90
|
return this._port;
|
|
60
91
|
this._server = http.createServer((req, res) => {
|
|
61
92
|
this._handle(req, res).catch((error) => {
|
|
62
|
-
this._log(`gateway error: ${
|
|
93
|
+
this._log(`gateway error: ${errorMessage(error)}`);
|
|
63
94
|
if (!res.headersSent)
|
|
64
95
|
sendError(res, 500, 'api_error', 'internal_error', 'Gateway error');
|
|
65
96
|
else
|
|
@@ -71,12 +102,42 @@ export class GatewayServer {
|
|
|
71
102
|
this._server.listen(this._options.listenPort ?? 0, this._options.listenHost ?? '127.0.0.1', () => resolve());
|
|
72
103
|
});
|
|
73
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?.();
|
|
74
108
|
return this._port;
|
|
75
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
|
+
}
|
|
76
133
|
async stop() {
|
|
77
134
|
const server = this._server;
|
|
78
135
|
this._server = null;
|
|
79
136
|
this._port = 0;
|
|
137
|
+
if (this._retentionTimer)
|
|
138
|
+
clearInterval(this._retentionTimer);
|
|
139
|
+
this._retentionTimer = null;
|
|
140
|
+
await this._exporter.stop();
|
|
80
141
|
if (!server)
|
|
81
142
|
return;
|
|
82
143
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
@@ -87,26 +148,21 @@ export class GatewayServer {
|
|
|
87
148
|
async _handle(req, res) {
|
|
88
149
|
const method = req.method ?? 'GET';
|
|
89
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
|
+
}
|
|
90
156
|
const route = canonicalizeRoute(method, path);
|
|
91
157
|
if (!route) {
|
|
92
158
|
this._log(`gateway rejected route: ${method} ${path}`);
|
|
93
159
|
sendError(res, 404, 'invalid_request_error', 'not_found', 'Not found');
|
|
94
160
|
return;
|
|
95
161
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
const key = secret ? this._options.store.findKeyBySecret(secret) : null;
|
|
99
|
-
if (!key || key.status !== 'active') {
|
|
100
|
-
this._log(`gateway rejected authentication: ${method} ${path}`);
|
|
101
|
-
res.setHeader('www-authenticate', 'Bearer');
|
|
102
|
-
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)
|
|
103
164
|
return;
|
|
104
|
-
}
|
|
105
|
-
if (key.expiresAt !== null && key.expiresAt <= Date.now()) {
|
|
106
|
-
res.setHeader('www-authenticate', 'Bearer');
|
|
107
|
-
sendError(res, 401, 'authentication_error', 'key_expired', 'API key has expired');
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
165
|
+
const { key, context } = authenticated;
|
|
110
166
|
if (route.local) {
|
|
111
167
|
if (route.prefix === TOPUP_PATH)
|
|
112
168
|
await this._topup(req, res, key);
|
|
@@ -114,112 +170,324 @@ export class GatewayServer {
|
|
|
114
170
|
sendJson(res, 200, { data: await this._keyInfo(key) });
|
|
115
171
|
return;
|
|
116
172
|
}
|
|
117
|
-
const buyerPort = this._options.buyerPort;
|
|
118
173
|
// Caps are only as good as the spend that reaches the ledger, so a key
|
|
119
174
|
// with caps fails closed while its buyer is not reporting spend.
|
|
120
|
-
if (route.paid &&
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (state !== 'reporting') {
|
|
124
|
-
sendError(res, 503, 'api_error', 'spend_tracking_unavailable', state === 'unsupported'
|
|
125
|
-
? 'The buyer for this API key does not report spend; upgrade it to enforce spend limits'
|
|
126
|
-
: 'The buyer for this API key is not reachable');
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
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);
|
|
131
178
|
if (!body)
|
|
132
179
|
return sendBodyTooLarge(res);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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');
|
|
139
191
|
return;
|
|
140
192
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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;
|
|
145
200
|
}
|
|
146
|
-
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 = {
|
|
147
208
|
tag,
|
|
148
|
-
|
|
149
|
-
buyerIdentity: key.buyerIdentity,
|
|
209
|
+
key,
|
|
150
210
|
method,
|
|
151
|
-
path
|
|
152
|
-
|
|
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),
|
|
153
216
|
startedAt: Date.now(),
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let finished = false;
|
|
158
|
-
const finish = (status, buyerRequestId) => {
|
|
159
|
-
if (finished)
|
|
160
|
-
return;
|
|
161
|
-
finished = true;
|
|
162
|
-
this._options.store.finishRequest(tag, { status, buyerRequestId });
|
|
163
|
-
this._options.accounting.finish(tag);
|
|
217
|
+
body,
|
|
218
|
+
policyHeaders: policy.headers,
|
|
219
|
+
modelListPolicy: route.prefix === '/v1/models' && policy.policy.allowedModels ? policy.policy : null,
|
|
164
220
|
};
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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);
|
|
178
235
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
res
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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;
|
|
212
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);
|
|
213
475
|
else {
|
|
214
|
-
|
|
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
|
+
}
|
|
215
482
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (!res.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
+
}
|
|
223
491
|
}
|
|
224
492
|
/**
|
|
225
493
|
* x402 top-up: the key holder pays USDC straight to the key's buyer wallet.
|
|
@@ -311,7 +579,7 @@ export class GatewayServer {
|
|
|
311
579
|
});
|
|
312
580
|
}
|
|
313
581
|
catch (error) {
|
|
314
|
-
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)}`);
|
|
315
583
|
}
|
|
316
584
|
this._log(`gateway top-up: key=${key.id} identity=${key.buyerIdentity} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}`);
|
|
317
585
|
res.setHeader(PAYMENT_RESPONSE_HEADER, encodeHeaderJson(settled));
|
|
@@ -338,16 +606,18 @@ export class GatewayServer {
|
|
|
338
606
|
return await topup.facilitator.settle(payment, requirements);
|
|
339
607
|
}
|
|
340
608
|
catch (error) {
|
|
341
|
-
this._log(`gateway facilitator error: ${
|
|
609
|
+
this._log(`gateway facilitator error: ${errorMessage(error)}`);
|
|
342
610
|
return failure('unexpected_settle_error');
|
|
343
611
|
}
|
|
344
612
|
}
|
|
345
613
|
async _keyInfo(key) {
|
|
346
|
-
const spent = this._options.store.
|
|
614
|
+
const spent = this._options.store.spendByPeriod({ keyId: key.id });
|
|
347
615
|
const usage = this._options.store.usageStats(key.id);
|
|
348
616
|
const buyerAddress = await this._options.identityAddress(key.buyerIdentity).catch(() => null);
|
|
349
|
-
|
|
350
|
-
|
|
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];
|
|
351
621
|
return [period, {
|
|
352
622
|
limit_usd: optionalUsdcToDecimalString(limit),
|
|
353
623
|
spent_usd: usdcToDecimalString(spent[period]),
|
|
@@ -381,11 +651,13 @@ export class GatewayServer {
|
|
|
381
651
|
*/
|
|
382
652
|
function spendLimitError(breach) {
|
|
383
653
|
const label = breach.period === 'total' ? 'lifetime' : breach.period;
|
|
654
|
+
const level = breach.level ?? 'key';
|
|
384
655
|
return {
|
|
385
656
|
type: 'insufficient_quota',
|
|
386
657
|
code: 'spend_limit_reached',
|
|
387
|
-
message:
|
|
658
|
+
message: `${budgetHolder(level)} reached its ${label} spend limit of ${formatUsdc(breach.limitUsdc)}.`,
|
|
388
659
|
limit: {
|
|
660
|
+
level,
|
|
389
661
|
period: breach.period,
|
|
390
662
|
limit_usd: usdcToDecimalString(breach.limitUsdc),
|
|
391
663
|
spent_usd: usdcToDecimalString(breach.spentUsdc),
|
|
@@ -393,6 +665,13 @@ function spendLimitError(breach) {
|
|
|
393
665
|
},
|
|
394
666
|
};
|
|
395
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
|
+
}
|
|
396
675
|
function sendJson(res, status, payload) {
|
|
397
676
|
res.writeHead(status, { 'content-type': 'application/json' });
|
|
398
677
|
res.end(JSON.stringify(payload));
|
|
@@ -400,6 +679,10 @@ function sendJson(res, status, payload) {
|
|
|
400
679
|
function sendError(res, status, type, code, message) {
|
|
401
680
|
sendJson(res, status, { error: { message, type, code } });
|
|
402
681
|
}
|
|
682
|
+
function sendUnauthorized(res, code, message) {
|
|
683
|
+
res.setHeader('www-authenticate', 'Bearer');
|
|
684
|
+
sendError(res, 401, 'authentication_error', code, message);
|
|
685
|
+
}
|
|
403
686
|
/** The request body, or null once it exceeds MAX_BODY_BYTES (the rest is drained, not kept). */
|
|
404
687
|
async function readBody(req) {
|
|
405
688
|
if (Number(req.headers['content-length']) > MAX_BODY_BYTES) {
|
|
@@ -418,19 +701,132 @@ async function readBody(req) {
|
|
|
418
701
|
function sendBodyTooLarge(res) {
|
|
419
702
|
sendError(res, 413, 'invalid_request_error', 'request_too_large', `Request bodies are limited to ${MAX_BODY_BYTES / 1024 / 1024} MiB`);
|
|
420
703
|
}
|
|
421
|
-
|
|
704
|
+
/** A JSON object body, or null (empty, too large to inspect, not JSON, not an object). */
|
|
705
|
+
function parseJsonBody(body, contentType) {
|
|
422
706
|
if (body.length === 0 || body.length > MAX_MODEL_SNIFF_BYTES)
|
|
423
707
|
return null;
|
|
424
708
|
if (contentType && !contentType.includes('json'))
|
|
425
709
|
return null;
|
|
426
710
|
try {
|
|
427
|
-
|
|
428
|
-
return typeof parsed.model === 'string' ? parsed.model.slice(0, 200) : null;
|
|
711
|
+
return jsonObject(JSON.parse(body.toString('utf8')));
|
|
429
712
|
}
|
|
430
713
|
catch {
|
|
431
714
|
return null;
|
|
432
715
|
}
|
|
433
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
|
+
}
|
|
434
830
|
function tunnelRequestSource(headers) {
|
|
435
831
|
const originator = normalizeSource(firstHeader(headers.originator));
|
|
436
832
|
if (originator)
|
|
@@ -442,12 +838,32 @@ function tunnelRequestSource(headers) {
|
|
|
442
838
|
const product = normalizeSource(userAgent.split(/[/\s]/, 1)[0] ?? '');
|
|
443
839
|
return product.startsWith('cursor') ? 'cursor' : 'public-tunnel';
|
|
444
840
|
}
|
|
841
|
+
function isLoopback(address) {
|
|
842
|
+
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
843
|
+
}
|
|
445
844
|
function firstHeader(value) {
|
|
446
845
|
return Array.isArray(value) ? value[0] ?? '' : value ?? '';
|
|
447
846
|
}
|
|
448
847
|
function normalizeSource(value) {
|
|
449
848
|
return value.trim().toLowerCase().replace(/[^a-z0-9.]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64);
|
|
450
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
|
+
}
|
|
451
867
|
function canonicalizeRoute(method, path) {
|
|
452
868
|
const queryIndex = path.indexOf('?');
|
|
453
869
|
const pathname = (queryIndex === -1 ? path : path.slice(0, queryIndex)).toLowerCase();
|