cartethyia 2.7.4 → 2.7.5
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/.env.example +2 -0
- package/README.md +17 -5
- package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
- package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
- package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
- package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
- package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
- package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
- package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
- package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
- package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
- package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
- package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +56 -55
- package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
- package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
- package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
- package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
- package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
- package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
- package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
- package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
- package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
- package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
- package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
- package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
- package/package.json +4 -6
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +58 -2
- package/src/boot/dependencies.ts +786 -732
- package/src/boot/lifecycle.ts +11 -12
- package/src/config/cooldowns.ts +34 -55
- package/src/config/network.ts +1 -1
- package/src/config/package-paths.ts +1 -1
- package/src/config/providers.ts +13 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +26 -6
- package/src/console/api-keys/ban-constants.ts +38 -0
- package/src/console/api-keys/contracts.ts +71 -62
- package/src/console/api-keys/routes.ts +48 -12
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +1 -1
- package/src/console/auth/audit-recorder.ts +1 -1
- package/src/console/auth/lockout.ts +7 -3
- package/src/console/auth/row-coercion.ts +57 -12
- package/src/console/auth/session-resolver.ts +1 -1
- package/src/console/auth/session-service.ts +8 -2
- package/src/console/auth/session.ts +37 -31
- package/src/console/auth/setup-service.ts +4 -3
- package/src/console/auth/user-store.ts +1 -1
- package/src/console/backup/9router-map.ts +0 -3
- package/src/console/backup/contracts.ts +9 -9
- package/src/console/backup/export-endpoint.ts +5 -6
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +29 -33
- package/src/console/backup/service.ts +468 -468
- package/src/console/backup/store.ts +47 -29
- package/src/console/backup/validate.ts +11 -1
- package/src/console/cli-tools/contracts.ts +7 -7
- package/src/console/cli-tools/injectors/cline.ts +110 -110
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/copilot.ts +108 -108
- package/src/console/cli-tools/injectors/driver.ts +247 -247
- package/src/console/cli-tools/injectors/jcode.ts +115 -115
- package/src/console/cli-tools/injectors/openclaw.ts +161 -161
- package/src/console/cli-tools/injectors/opencode.ts +153 -153
- package/src/console/cli-tools/routes.ts +1 -1
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router.ts +32 -0
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/domain-registration.ts +16 -2
- package/src/console/inferhub/client.ts +0 -7
- package/src/console/inferhub/key-store.ts +1 -1
- package/src/console/inferhub/normalize.ts +2 -2
- package/src/console/inferhub/routes.ts +1 -1
- package/src/console/inferhub/types.ts +1 -1
- package/src/console/observability/contracts.ts +1 -1
- package/src/console/observability/live.ts +31 -18
- package/src/console/observability/logs.ts +1 -1
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +20 -4
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +39 -0
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +95 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +27 -3
- package/src/console/providers/catalog/store.ts +147 -8
- package/src/console/providers/detail/routes.ts +1 -1
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +92 -13
- package/src/console/quota/account-quota-global.ts +41 -3
- package/src/console/quota/account-quota-shared.ts +10 -3
- package/src/console/quota/account-quota-tenant.ts +259 -66
- package/src/console/quota/daily-growth-job.ts +308 -0
- package/src/console/quota/native-identity.ts +2 -2
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/routes.ts +1 -1
- package/src/console/remote-support/service.ts +2 -2
- package/src/console/routing/model/contracts.ts +1 -1
- package/src/console/routing/pools/contracts.ts +2 -2
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/relay-deploy.ts +3 -3
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +100 -32
- package/src/console/share/share-stats.ts +4 -4
- package/src/console/share/share-usage.ts +1 -1
- package/src/console/shared/errors.ts +2 -2
- package/src/console/shared/object.ts +18 -0
- package/src/console/shared/read-through-cache.ts +4 -4
- package/src/console/shared/transaction.ts +14 -0
- package/src/console/system-prompt/contracts.ts +89 -12
- package/src/console/system-prompt/routes.ts +98 -45
- package/src/console/updates/apply-update.ts +244 -0
- package/src/console/updates/routes.ts +252 -97
- package/src/main.ts +11 -5
- package/src/network/http2-bidi.ts +1 -1
- package/src/network/ip-utils.ts +298 -0
- package/src/network/outbound-fetch.ts +1 -1
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +16 -12
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-health-machine.ts +1 -1
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +20 -71
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +59 -291
- package/src/observability/log-sanitize.ts +1 -1
- package/src/observability/metrics.ts +4 -4
- package/src/observability/payload-capture.ts +6 -5
- package/src/observability/payload-store.ts +1 -1
- package/src/observability/runtime-metrics.ts +1 -1
- package/src/observability/telemetry-buffer.ts +12 -3
- package/src/observability/telemetry-reconciliation.ts +3 -3
- package/src/observability/token-speed.ts +1 -1
- package/src/persistence/connection-url.ts +1 -1
- package/src/persistence/db-handle.ts +1 -1
- package/src/persistence/db-pg.ts +2 -2
- package/src/persistence/db-sqlite.ts +3 -3
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +113 -40
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +10 -1
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/system-prompt-store.ts +63 -18
- package/src/persistence/tenant-preferences.ts +1 -1
- package/src/persistence/ttl-cache.ts +3 -3
- package/src/persistence/usage-flush.ts +7 -2
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/codecs.ts +6 -10
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/reasoning-text.ts +1 -1
- package/src/protocol/reasoning.ts +7 -52
- package/src/protocol/registry.ts +50 -15
- package/src/protocol/request/chat.ts +46 -19
- package/src/protocol/request/codex.ts +1 -1
- package/src/protocol/request/messages.ts +46 -14
- package/src/protocol/request/responses.ts +19 -10
- package/src/protocol/response/chat.ts +25 -10
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/messages.ts +1 -1
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +1 -1
- package/src/protocol/sse-decoder.ts +50 -1
- package/src/protocol/stop-reason.ts +2 -2
- package/src/protocol/think-split.ts +347 -0
- package/src/protocol/translation/attachment-integrity.ts +3 -3
- package/src/protocol/translation/cache-controls.ts +8 -20
- package/src/protocol/translation/capabilities.ts +6 -6
- package/src/protocol/translation/dialect/deepseek.ts +10 -0
- package/src/protocol/translation/dialect/inband.ts +39 -0
- package/src/protocol/translation/dialect/model-thinking.ts +89 -0
- package/src/protocol/translation/dialect/qwen.ts +114 -0
- package/src/protocol/translation/dialect/resolver.ts +83 -0
- package/src/protocol/translation/dialect/rules.ts +93 -0
- package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
- package/src/protocol/translation/dialect/types.ts +58 -0
- package/src/protocol/translation/quirks.ts +18 -4
- package/src/protocol/translation/thinking.ts +12 -252
- package/src/protocol/translation/tool-id.ts +3 -3
- package/src/protocol/translation/tool-repair.ts +1 -1
- package/src/protocol/upstream/post-json.ts +6 -1
- package/src/providers/adapters/compatible-adapter.ts +42 -3
- package/src/providers/authentication/jwt-validator.ts +0 -5
- package/src/providers/authentication/oauth-client.ts +254 -253
- package/src/providers/authentication/oauth-flow-store.ts +42 -7
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/default-registry.ts +23 -35
- package/src/providers/discovery/catalog/catalog-format.ts +13 -2
- package/src/providers/discovery/discovery-types.ts +0 -1
- package/src/providers/discovery/openai-model-discovery.ts +2 -2
- package/src/providers/discovery/probe-phases.ts +48 -13
- package/src/providers/discovery/probing-service.ts +6 -8
- package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
- package/src/providers/integrations/antigravity/antigravity.ts +2 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
- package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +1 -1
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/commandcode/commandcode.ts +75 -115
- package/src/providers/integrations/commandcode/quota.ts +131 -51
- package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
- package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
- package/src/providers/integrations/cursor/cursor-request.ts +0 -87
- package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
- package/src/providers/integrations/cursor/cursor.ts +38 -5
- package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
- package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
- package/src/providers/integrations/factory/factory.ts +9 -9
- package/src/providers/integrations/github/github-discovery.ts +55 -10
- package/src/providers/integrations/github/github-oauth.ts +6 -5
- package/src/providers/integrations/github/github.ts +41 -14
- package/src/providers/integrations/grok/grok-oauth.ts +261 -261
- package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
- package/src/providers/integrations/grok/grok-quota.ts +16 -7
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
- package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
- package/src/providers/integrations/grok/grok.ts +86 -36
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
- package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
- package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
- package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
- package/src/providers/integrations/kiro/kiro-request.ts +8 -11
- package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
- package/src/providers/integrations/kiro/kiro.ts +81 -68
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
- package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
- package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
- package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
- package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
- package/src/providers/integrations/qoder/qoder.ts +354 -62
- package/src/providers/integrations/shared/connect.ts +0 -54
- package/src/providers/integrations/shared/hash.ts +15 -0
- package/src/providers/integrations/shared/session-cache.ts +136 -0
- package/src/providers/integrations/trae/trae-cache.ts +7 -87
- package/src/providers/integrations/trae/trae-catalog.ts +1 -6
- package/src/providers/integrations/trae/trae-protocol.ts +17 -8
- package/src/providers/integrations/trae/trae-realm.ts +0 -7
- package/src/providers/integrations/trae/trae.ts +53 -10
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
- package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
- package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
- package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
- package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
- package/src/providers/operations/account-error-classification.ts +131 -116
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/cli-platform.ts +31 -5
- package/src/providers/operations/client-version-resolver.ts +4 -6
- package/src/providers/operations/client-versions.ts +10 -7
- package/src/providers/operations/provider-catalog-seeder.ts +2 -0
- package/src/providers/operations/provider-catalog-service.ts +18 -2
- package/src/providers/operations/provider-credential-service.ts +19 -2
- package/src/providers/provider-contracts.ts +18 -7
- package/src/providers/provider-metadata.ts +17 -2
- package/src/providers/provider-model-definition.ts +22 -1
- package/src/providers/provider-probe.ts +4 -2
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +4 -0
- package/src/providers/quota/refresh.ts +27 -4
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +1 -3
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +16 -4
- package/src/security/client-router-fingerprint.ts +4 -4
- package/src/security/credential-codec.ts +3 -3
- package/src/security/csrf.ts +2 -2
- package/src/security/ip-boundary.ts +16 -189
- package/src/security/model-access-rule.ts +1 -1
- package/src/security/outbound-headers.ts +18 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +23 -20
- package/src/transport/dispatch/generation.ts +25 -45
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +3 -1
- package/src/transport/dispatch/responses-compact.ts +25 -46
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +7 -3
- package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
- package/src/transport/dispatch/systemone.ts +20 -48
- package/src/transport/dispatch/token-count.ts +41 -38
- package/src/transport/dispatch/websearch.ts +19 -45
- package/src/transport/drain-endpoint.ts +1 -1
- package/src/transport/failure-policy.ts +6 -0
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/headroom-guard.ts +1 -1
- package/src/transport/guards/pipeline.ts +1 -1
- package/src/transport/guards/request-context.ts +12 -17
- package/src/transport/request/preparer.ts +286 -7
- package/src/transport/request/rtk/compress-request.ts +3 -3
- package/src/transport/request/rtk/rtk-constants.ts +2 -2
- package/src/transport/request/rtk/rtk-filters.ts +8 -8
- package/src/transport/request/state.ts +1 -13
- package/src/transport/request/system-prompt-injection.ts +74 -11
- package/src/transport/request/tenant-preferences.ts +22 -0
- package/src/transport/routing/candidate-index.ts +2 -2
- package/src/transport/routing/round-robin.ts +1 -1
- package/src/transport/routing/route-catalog.ts +17 -18
- package/src/transport/routing/route-model.ts +126 -33
- package/src/transport/routing/router.ts +152 -37
- package/src/transport/shutdown-notice.ts +2 -2
- package/src/transport/surface/adapters.ts +3 -3
- package/src/transport/surface/chat/encode.ts +7 -7
- package/src/transport/surface/chat/parse.ts +7 -7
- package/src/transport/surface/completion.ts +2 -2
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/parse.ts +3 -3
- package/src/transport/surface/responses/adapter.ts +1 -1
- package/src/transport/surface/responses/errors.ts +0 -9
- package/src/transport/vision-handoff-cache.ts +58 -0
- package/src/transport/vision-handoff.ts +376 -0
- package/src/workers/account-identity-sweep.ts +2 -2
- package/src/workers/buddy-growth-tasks.ts +392 -346
- package/src/workers/daily-checkin.ts +102 -49
- package/src/workers/maintenance-lease.ts +2 -35
- package/src/workers/oauth-refresh-sweep.ts +8 -1
- package/src/workers/quota-refresh-sweep.ts +120 -82
- package/src/workers/scheduler.ts +67 -4
- package/src/workers/sweep-runner.ts +24 -5
- package/src/workers/zcode-gift-claim.ts +108 -0
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +0 -2
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
- package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/src/network/response-headers.ts +0 -39
- package/src/protocol/response/dsml.ts +0 -38
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
- /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
- /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
package/src/boot/lifecycle.ts
CHANGED
|
@@ -4,12 +4,13 @@ import { buildProductionDeps } from "./dependencies";
|
|
|
4
4
|
import type { ProductionDeps } from "./dependencies";
|
|
5
5
|
import { withTimeout } from "./timeout";
|
|
6
6
|
import { resolveShutdownDrainWindowMs } from "../config/runtime";
|
|
7
|
+
import { log } from "../observability/logger";
|
|
7
8
|
|
|
8
9
|
export type ShutdownReason = "SIGTERM" | "SIGINT" | "reload" | "update";
|
|
9
|
-
|
|
10
|
+
type ShutdownState =
|
|
10
11
|
"idle" | "stop_admitting" | "bounded_drain_wait" | "flush_telemetry" | "close_pools" | "done";
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
interface ShutdownHooks {
|
|
13
14
|
flushTelemetry?: (deadlineMs: number) => Promise<void>;
|
|
14
15
|
closePools?: () => Promise<void>;
|
|
15
16
|
abortInflight?: () => void;
|
|
@@ -107,7 +108,10 @@ export class ShutdownCoordinator {
|
|
|
107
108
|
if (this.inflight.size > 0) {
|
|
108
109
|
try {
|
|
109
110
|
this.hooks.abortInflight?.();
|
|
110
|
-
} catch {
|
|
111
|
+
} catch (error) {
|
|
112
|
+
// A failed abort must not be silent: it leaks in-flight work into
|
|
113
|
+
// close_pools, which then closes pools under live requests.
|
|
114
|
+
log.warn("[shutdown] abort in-flight failed", error as Error);
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
await this.waitForDrain(Date.now() + this.drainTimeoutMs);
|
|
@@ -156,14 +160,9 @@ export class ShutdownCoordinator {
|
|
|
156
160
|
const remaining = Math.max(0, deadlineMs - Date.now());
|
|
157
161
|
// No budget left: invoking the hook would start work with zero deadline
|
|
158
162
|
// that withTimeout immediately cancels; skip straight to pool close.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const wait = Math.min(remaining, 5);
|
|
163
|
-
await new Promise<void>((r) => setTimeout(r, wait));
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
163
|
+
// Without a hook there is nothing to flush either — both cases return
|
|
164
|
+
// here and the drain proceeds to pool close.
|
|
165
|
+
if (remaining <= 0 || !this.hooks.flushTelemetry) return;
|
|
167
166
|
try {
|
|
168
167
|
await withTimeout(
|
|
169
168
|
this.hooks.flushTelemetry(deadlineMs),
|
|
@@ -189,7 +188,7 @@ export class ShutdownCoordinator {
|
|
|
189
188
|
}
|
|
190
189
|
}
|
|
191
190
|
|
|
192
|
-
|
|
191
|
+
interface ElyxiaServer {
|
|
193
192
|
stop(closeActiveConnections?: boolean): unknown;
|
|
194
193
|
}
|
|
195
194
|
|
package/src/config/cooldowns.ts
CHANGED
|
@@ -4,63 +4,67 @@
|
|
|
4
4
|
|
|
5
5
|
import { CONFIG_SPEC, readInt } from "./spec";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** The spec row shape every cooldown resolver reads. */
|
|
8
|
+
type CooldownSpecEntry = {
|
|
9
|
+
readonly kind: "int";
|
|
10
|
+
readonly default: number;
|
|
11
|
+
readonly min: number;
|
|
12
|
+
readonly max: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/** Shared cache keyed by env-var name, so one resolver per knob stays warm. */
|
|
16
|
+
const cooldownCache = new Map<string, number>();
|
|
17
|
+
|
|
18
|
+
function cachedCooldownMs(name: string, entry: CooldownSpecEntry): number {
|
|
19
|
+
const cached = cooldownCache.get(name);
|
|
20
|
+
if (cached !== undefined) return cached;
|
|
21
|
+
const value = readInt(name, entry);
|
|
22
|
+
cooldownCache.set(name, value);
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
|
|
8
26
|
/** Fallback cooldown for a provider rate limit (default 15m). */
|
|
9
27
|
export function resolveAccountRateLimitCooldownMs(): number {
|
|
10
|
-
|
|
11
|
-
_rateLimitCooldown = readInt(
|
|
28
|
+
return cachedCooldownMs(
|
|
12
29
|
"CARTETHYIA_ACCOUNT_RATE_LIMIT_COOLDOWN_MS",
|
|
13
30
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_RATE_LIMIT_COOLDOWN_MS,
|
|
14
31
|
);
|
|
15
|
-
return _rateLimitCooldown;
|
|
16
32
|
}
|
|
17
33
|
|
|
18
|
-
let _quotaCooldown: number | undefined;
|
|
19
34
|
/**
|
|
20
35
|
* Fallback cooldown for provider quota exhaustion when the error states no
|
|
21
36
|
* reset window (default 1h). A provider-specific rule (xAI Grok Build's
|
|
22
37
|
* rolling 24-hour free-tier window) overrides it inside the classifier.
|
|
23
38
|
*/
|
|
24
39
|
export function resolveAccountQuotaCooldownMs(): number {
|
|
25
|
-
|
|
26
|
-
_quotaCooldown = readInt(
|
|
40
|
+
return cachedCooldownMs(
|
|
27
41
|
"CARTETHYIA_ACCOUNT_QUOTA_COOLDOWN_MS",
|
|
28
42
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_QUOTA_COOLDOWN_MS,
|
|
29
43
|
);
|
|
30
|
-
return _quotaCooldown;
|
|
31
44
|
}
|
|
32
45
|
|
|
33
|
-
let _modelCapacityCooldown: number | undefined;
|
|
34
46
|
/** Fallback cooldown for model-capacity overload (default 2m). */
|
|
35
47
|
export function resolveAccountModelCapacityCooldownMs(): number {
|
|
36
|
-
|
|
37
|
-
_modelCapacityCooldown = readInt(
|
|
48
|
+
return cachedCooldownMs(
|
|
38
49
|
"CARTETHYIA_ACCOUNT_MODEL_CAPACITY_COOLDOWN_MS",
|
|
39
50
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_MODEL_CAPACITY_COOLDOWN_MS,
|
|
40
51
|
);
|
|
41
|
-
return _modelCapacityCooldown;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
let _transientCooldown: number | undefined;
|
|
45
54
|
/** Backoff for a transient 5xx/network fault, recorded as `cooldown` (default 30s). */
|
|
46
55
|
export function resolveAccountTransientCooldownMs(): number {
|
|
47
|
-
|
|
48
|
-
_transientCooldown = readInt(
|
|
56
|
+
return cachedCooldownMs(
|
|
49
57
|
"CARTETHYIA_ACCOUNT_TRANSIENT_COOLDOWN_MS",
|
|
50
58
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_TRANSIENT_COOLDOWN_MS,
|
|
51
59
|
);
|
|
52
|
-
return _transientCooldown;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
let _unclassifiedCooldown: number | undefined;
|
|
56
62
|
/** Backoff for a failure no rule matched, recorded as `cooldown` (default 1m). */
|
|
57
63
|
export function resolveAccountUnclassifiedCooldownMs(): number {
|
|
58
|
-
|
|
59
|
-
_unclassifiedCooldown = readInt(
|
|
64
|
+
return cachedCooldownMs(
|
|
60
65
|
"CARTETHYIA_ACCOUNT_UNCLASSIFIED_COOLDOWN_MS",
|
|
61
66
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_UNCLASSIFIED_COOLDOWN_MS,
|
|
62
67
|
);
|
|
63
|
-
return _unclassifiedCooldown;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
/**
|
|
@@ -71,25 +75,21 @@ export function resolveAccountUnclassifiedCooldownMs(): number {
|
|
|
71
75
|
* window: an account that recovers on its own must not sit parked for a day
|
|
72
76
|
* because a burst of 5xx happened to arrive while it was already cooling.
|
|
73
77
|
*/
|
|
74
|
-
let _escalationMaxCooldown: number | undefined;
|
|
75
78
|
export function resolveAccountCooldownEscalationMaxMs(): number {
|
|
76
|
-
|
|
77
|
-
_escalationMaxCooldown = readInt(
|
|
79
|
+
return cachedCooldownMs(
|
|
78
80
|
"CARTETHYIA_ACCOUNT_COOLDOWN_ESCALATION_MAX_MS",
|
|
79
81
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_COOLDOWN_ESCALATION_MAX_MS,
|
|
80
82
|
);
|
|
81
|
-
return _escalationMaxCooldown;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
let _poolCooldown: number | undefined;
|
|
85
85
|
/** How long a proxy pool stays `cooldown` after a transport fault (default 2m). */
|
|
86
86
|
export function resolvePoolCooldownMs(): number {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
return cachedCooldownMs(
|
|
88
|
+
"CARTETHYIA_POOL_COOLDOWN_MS",
|
|
89
|
+
CONFIG_SPEC.CARTETHYIA_POOL_COOLDOWN_MS,
|
|
90
|
+
);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
let _authRejectedCooldown: number | undefined;
|
|
93
93
|
/**
|
|
94
94
|
* Backoff for an auth rejection that names no revocation (default 5m).
|
|
95
95
|
*
|
|
@@ -107,15 +107,12 @@ let _authRejectedCooldown: number | undefined;
|
|
|
107
107
|
* rotation immediately, with no backoff to wait out.
|
|
108
108
|
*/
|
|
109
109
|
export function resolveAccountAuthRejectedCooldownMs(): number {
|
|
110
|
-
|
|
111
|
-
_authRejectedCooldown = readInt(
|
|
110
|
+
return cachedCooldownMs(
|
|
112
111
|
"CARTETHYIA_ACCOUNT_AUTH_REJECTED_COOLDOWN_MS",
|
|
113
112
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_AUTH_REJECTED_COOLDOWN_MS,
|
|
114
113
|
);
|
|
115
|
-
return _authRejectedCooldown;
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
let _policyBlockCooldown: number | undefined;
|
|
119
116
|
/**
|
|
120
117
|
* Base backoff for the buddy policy/channel block (default 5m).
|
|
121
118
|
*
|
|
@@ -132,15 +129,12 @@ let _policyBlockCooldown: number | undefined;
|
|
|
132
129
|
* while a single bad prompt costs five minutes.
|
|
133
130
|
*/
|
|
134
131
|
export function resolveAccountPolicyBlockCooldownMs(): number {
|
|
135
|
-
|
|
136
|
-
_policyBlockCooldown = readInt(
|
|
132
|
+
return cachedCooldownMs(
|
|
137
133
|
"CARTETHYIA_ACCOUNT_POLICY_BLOCK_COOLDOWN_MS",
|
|
138
134
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_POLICY_BLOCK_COOLDOWN_MS,
|
|
139
135
|
);
|
|
140
|
-
return _policyBlockCooldown;
|
|
141
136
|
}
|
|
142
137
|
|
|
143
|
-
let _disabledRecovery: number | undefined;
|
|
144
138
|
/**
|
|
145
139
|
* How long an **automatically** disabled account stays out of rotation (default 24h).
|
|
146
140
|
*
|
|
@@ -160,27 +154,22 @@ let _disabledRecovery: number | undefined;
|
|
|
160
154
|
* only reproduces the refusal. Set to `0` to make an automatic disable terminal.
|
|
161
155
|
*/
|
|
162
156
|
export function resolveAccountDisabledRecoveryMs(): number {
|
|
163
|
-
|
|
164
|
-
_disabledRecovery = readInt(
|
|
157
|
+
return cachedCooldownMs(
|
|
165
158
|
"CARTETHYIA_ACCOUNT_DISABLED_RECOVERY_MS",
|
|
166
159
|
CONFIG_SPEC.CARTETHYIA_ACCOUNT_DISABLED_RECOVERY_MS,
|
|
167
160
|
);
|
|
168
|
-
return _disabledRecovery;
|
|
169
161
|
}
|
|
170
162
|
|
|
171
|
-
let _poolProviderRateLimitCooldown: number | undefined;
|
|
172
163
|
/**
|
|
173
164
|
* Fallback cooldown for a provider-scoped egress 429 when the upstream named no
|
|
174
165
|
* window (default 1h). See `CARTETHYIA_POOL_PROVIDER_RATE_LIMIT_COOLDOWN_MS`.
|
|
175
166
|
* An upstream `retryAfterMs` always wins over this.
|
|
176
167
|
*/
|
|
177
168
|
export function resolvePoolProviderRateLimitCooldownMs(): number {
|
|
178
|
-
|
|
179
|
-
_poolProviderRateLimitCooldown = readInt(
|
|
169
|
+
return cachedCooldownMs(
|
|
180
170
|
"CARTETHYIA_POOL_PROVIDER_RATE_LIMIT_COOLDOWN_MS",
|
|
181
171
|
CONFIG_SPEC.CARTETHYIA_POOL_PROVIDER_RATE_LIMIT_COOLDOWN_MS,
|
|
182
172
|
);
|
|
183
|
-
return _poolProviderRateLimitCooldown;
|
|
184
173
|
}
|
|
185
174
|
|
|
186
175
|
/**
|
|
@@ -188,15 +177,5 @@ export function resolvePoolProviderRateLimitCooldownMs(): number {
|
|
|
188
177
|
* cooldown env-vars between test cases.
|
|
189
178
|
*/
|
|
190
179
|
export function resetCooldownCacheForTests(): void {
|
|
191
|
-
|
|
192
|
-
_quotaCooldown = undefined;
|
|
193
|
-
_modelCapacityCooldown = undefined;
|
|
194
|
-
_transientCooldown = undefined;
|
|
195
|
-
_unclassifiedCooldown = undefined;
|
|
196
|
-
_escalationMaxCooldown = undefined;
|
|
197
|
-
_poolCooldown = undefined;
|
|
198
|
-
_poolProviderRateLimitCooldown = undefined;
|
|
199
|
-
_authRejectedCooldown = undefined;
|
|
200
|
-
_policyBlockCooldown = undefined;
|
|
201
|
-
_disabledRecovery = undefined;
|
|
180
|
+
cooldownCache.clear();
|
|
202
181
|
}
|
package/src/config/network.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type TrustedProxyMode = "disabled" | "trusted" | "platform";
|
|
|
24
24
|
* naming CIDRs. It cannot be mistaken for an address, so the list form stays
|
|
25
25
|
* unambiguous.
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
const TRUSTED_PROXY_PLATFORM_TOKEN = "platform";
|
|
28
28
|
|
|
29
29
|
/** Trusted reverse-proxy boundary used for forwarded client addresses. */
|
|
30
30
|
export interface TrustedProxyBoundary {
|
|
@@ -6,7 +6,7 @@ import { resolve } from "node:path";
|
|
|
6
6
|
* virtual `import.meta.dir`, so deployments can point this at the shipped
|
|
7
7
|
* assets directory explicitly.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
function resolvePackageRoot(
|
|
10
10
|
moduleDir: string,
|
|
11
11
|
configuredRoot: string | undefined,
|
|
12
12
|
): string {
|
package/src/config/providers.ts
CHANGED
|
@@ -4,20 +4,7 @@
|
|
|
4
4
|
* public origin.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { CONFIG_SPEC, readInt, readOptionalText,
|
|
8
|
-
|
|
9
|
-
/** Reads and normalizes the public OAuth origin. */
|
|
10
|
-
export function requirePublicOrigin(): string {
|
|
11
|
-
return readRequired("CARTETHYIA_PUBLIC_ORIGIN", CONFIG_SPEC.CARTETHYIA_PUBLIC_ORIGIN).replace(
|
|
12
|
-
/\/+$/,
|
|
13
|
-
"",
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Builds the fixed OAuth callback URL for a provider id. */
|
|
18
|
-
export function oauthCallbackUrl(providerId: string): string {
|
|
19
|
-
return `${requirePublicOrigin()}/console/api/providers/${providerId}/oauth/callback`;
|
|
20
|
-
}
|
|
7
|
+
import { CONFIG_SPEC, readInt, readOptionalText, readText } from "./spec";
|
|
21
8
|
|
|
22
9
|
/**
|
|
23
10
|
* Browser-authorize redirect URI for a provider.
|
|
@@ -103,3 +90,15 @@ export function resolveGithubEnterpriseDomain(): string {
|
|
|
103
90
|
return "";
|
|
104
91
|
}
|
|
105
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* How cached prompt tokens are accounted. Unknown values fall back to `real`
|
|
96
|
+
* so a typo cannot silently flip every provider to simplified accounting.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveCacheMode(): "simplified" | "real" {
|
|
99
|
+
const raw = readText(
|
|
100
|
+
"CARTETHYIA_CACHE_MODE",
|
|
101
|
+
CONFIG_SPEC.CARTETHYIA_CACHE_MODE,
|
|
102
|
+
).toLowerCase();
|
|
103
|
+
return raw === "simplified" ? "simplified" : "real";
|
|
104
|
+
}
|
package/src/config/resources.ts
CHANGED
|
@@ -21,7 +21,6 @@ import { CONFIG_SPEC, readOptionalInt } from "./spec";
|
|
|
21
21
|
/** Used when no limit is discoverable at all (native dev, macOS, Windows). */
|
|
22
22
|
export const FALLBACK_MEMORY_LIMIT_BYTES = 512 * 1024 * 1024;
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
/**
|
|
26
25
|
* How many copies of a request body are resident at once.
|
|
27
26
|
*
|
|
@@ -30,15 +29,12 @@ export const FALLBACK_MEMORY_LIMIT_BYTES = 512 * 1024 * 1024;
|
|
|
30
29
|
* collection lags rather than keeping them to one. Budgeting one copy halves
|
|
31
30
|
* the real peak and lets the process admit twice the concurrency it can hold.
|
|
32
31
|
*/
|
|
33
|
-
export const REQUEST_BODY_TRANSIENT_COPIES = 2;
|
|
34
32
|
|
|
35
33
|
/** Share of the memory limit all in-flight request bodies together may hold. */
|
|
36
|
-
export const REQUEST_BODY_BUDGET_FRACTION = 0.25;
|
|
37
34
|
|
|
38
35
|
/** Share of the memory limit kept free for allocation spikes and GC slack. */
|
|
39
36
|
export const MEMORY_HEADROOM_FRACTION = 0.2;
|
|
40
37
|
|
|
41
|
-
|
|
42
38
|
/**
|
|
43
39
|
* Bytes kept free below the memory limit.
|
|
44
40
|
*
|
|
@@ -51,7 +47,6 @@ export function deriveMemoryHeadroomBytes(memoryLimitBytes: number): number {
|
|
|
51
47
|
return Math.ceil(memoryLimitBytes * MEMORY_HEADROOM_FRACTION);
|
|
52
48
|
}
|
|
53
49
|
|
|
54
|
-
|
|
55
50
|
/**
|
|
56
51
|
* Slack added on top of every key's concurrency limit.
|
|
57
52
|
*
|
package/src/config/runtime.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* HTTP listener, dashboard runtime, and graceful-shutdown drain resolvers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { CONFIG_SPEC, readInt, readOptionalText } from "./spec";
|
|
6
|
-
import { resolvePackagePath } from "./package-paths";
|
|
5
|
+
import { CONFIG_SPEC, readInt, readOptionalText, readText } from "./spec";
|
|
7
6
|
|
|
8
7
|
/** Resolves the HTTP listener port from the process environment. */
|
|
9
8
|
export function resolvePort(): number {
|
|
@@ -12,9 +11,7 @@ export function resolvePort(): number {
|
|
|
12
11
|
|
|
13
12
|
/** Resolves the dashboard static asset directory. */
|
|
14
13
|
export function resolveDashboardDist(): string {
|
|
15
|
-
|
|
16
|
-
if (!raw) return resolvePackagePath("dist", "dashboard");
|
|
17
|
-
return raw;
|
|
14
|
+
return readText("DASHBOARD_DIST", CONFIG_SPEC.DASHBOARD_DIST);
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
/**
|
package/src/config/spec.ts
CHANGED
|
@@ -297,6 +297,20 @@ export const CONFIG_SPEC = {
|
|
|
297
297
|
* an operator on one has no other way to point the login at it.
|
|
298
298
|
*/
|
|
299
299
|
CARTETHYIA_GITHUB_ENTERPRISE_DOMAIN: { kind: "text", default: "" },
|
|
300
|
+
// Only the literal true opts active ZCode accounts into daily gift claims.
|
|
301
|
+
CARTETHYIA_ZCODE_AUTO_CLAIM: { kind: "text", default: "false" },
|
|
302
|
+
/**
|
|
303
|
+
* How cached prompt tokens are accounted.
|
|
304
|
+
*
|
|
305
|
+
* - `simplified` (default): the request is cache-eligible when the provider
|
|
306
|
+
* reports a cache hit (`cached_input_tokens > 0`); every input token is
|
|
307
|
+
* then counted as cached. A reported `0` or an absent report are both a
|
|
308
|
+
* cache miss and stay uncached.
|
|
309
|
+
* - `real`: the provider's reported cache numbers are kept as-is (the
|
|
310
|
+
* pre-2.7.6 behavior). Use it when the exact per-provider split matters
|
|
311
|
+
* more than a uniform hit-rate reading.
|
|
312
|
+
*/
|
|
313
|
+
CARTETHYIA_CACHE_MODE: { kind: "text", default: "simplified" },
|
|
300
314
|
/**
|
|
301
315
|
* Free-tier OpenCode ids the listing still advertises but upstream refuses.
|
|
302
316
|
* Replaces the bundled list outright; the single token `none` trusts the
|
|
@@ -330,8 +344,10 @@ export function readText(name: string, entry: TextConfigEntry): string {
|
|
|
330
344
|
}
|
|
331
345
|
|
|
332
346
|
/** Reads an optional string; empty or whitespace reads as absent. */
|
|
333
|
-
export function readOptionalText(name: string, entry:
|
|
334
|
-
|
|
347
|
+
export function readOptionalText(name: string, entry: ConfigEntry): string | undefined {
|
|
348
|
+
if (entry.kind !== "optional-text") {
|
|
349
|
+
throw new Error(`${name} must be declared optional-text in CONFIG_SPEC`);
|
|
350
|
+
}
|
|
335
351
|
const raw = process.env[name]?.trim();
|
|
336
352
|
return raw && raw.length > 0 ? raw : undefined;
|
|
337
353
|
}
|
|
@@ -355,14 +371,18 @@ export function readRequired(name: string, entry: RequiredTextConfigEntry): stri
|
|
|
355
371
|
}
|
|
356
372
|
|
|
357
373
|
/** Reads a flag: enabled unless the literal `"false"` is set. */
|
|
358
|
-
export function readFlag(name: string, entry:
|
|
359
|
-
|
|
374
|
+
export function readFlag(name: string, entry: ConfigEntry): boolean {
|
|
375
|
+
if (entry.kind !== "flag") {
|
|
376
|
+
throw new Error(`${name} must be declared flag in CONFIG_SPEC`);
|
|
377
|
+
}
|
|
360
378
|
return process.env[name] !== "false";
|
|
361
379
|
}
|
|
362
380
|
|
|
363
381
|
/** Reads a comma-separated list, dropping empty entries. */
|
|
364
|
-
export function readList(name: string, entry:
|
|
365
|
-
|
|
382
|
+
export function readList(name: string, entry: ConfigEntry): readonly string[] | undefined {
|
|
383
|
+
if (entry.kind !== "list") {
|
|
384
|
+
throw new Error(`${name} must be declared list in CONFIG_SPEC`);
|
|
385
|
+
}
|
|
366
386
|
const entries = process.env[name]
|
|
367
387
|
?.split(",")
|
|
368
388
|
.map((value) => value.trim())
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure ban dropdown constants (reasons + durations), kept free of any `node:*`
|
|
3
|
+
* import so the dashboard can import them without evaluating Node-only modules.
|
|
4
|
+
*
|
|
5
|
+
* The dashboard mirrors these into its UI; the console API validates against
|
|
6
|
+
* the same lists. They used to live in `contracts.ts`, which also imports
|
|
7
|
+
* `hashSecret` (→ `security/crypto` → `node:crypto`) and `randomBytes` — so a
|
|
8
|
+
* browser bundle that imported any value from `contracts.ts` dragged the whole
|
|
9
|
+
* Node crypto chain along and blew up in the client (module externalized).
|
|
10
|
+
* Moving the pure lists here keeps one source of truth for the values while
|
|
11
|
+
* keeping the browser bundle clean.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Ban reasons offered by the console dropdown. The first two are the operator's
|
|
15
|
+
* own: "Instant Ban — Suka suka Gw" for the arbitrary ban, and a template for
|
|
16
|
+
* suspicious traffic. The rest are generic, and an operator can still type a
|
|
17
|
+
* custom reason — the dropdown is a convenience, not a closed set. */
|
|
18
|
+
export const API_KEY_BAN_REASONS: readonly { readonly value: string; readonly label: string }[] = [
|
|
19
|
+
{ value: "instant_arbitrary", label: "Instant Ban — Suka suka Gw" },
|
|
20
|
+
{ value: "traffic_suspicious", label: "Your traffic looks suspicious" },
|
|
21
|
+
{ value: "abuse", label: "Abuse of the gateway" },
|
|
22
|
+
{ value: "policy_violation", label: "Policy violation" },
|
|
23
|
+
{ value: "compromised", label: "Key may be compromised" },
|
|
24
|
+
{ value: "quota_exceeded", label: "Quota abused" },
|
|
25
|
+
{ value: "other", label: "Other / custom" },
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
/** Ban durations the console offers, in whole minutes. `null` is permanent.
|
|
29
|
+
* Mirrored by the dashboard (`dashboard/src/lib/ban-durations.ts`) so the UI
|
|
30
|
+
* and the API agree on one list. */
|
|
31
|
+
export const BAN_DURATION_CHOICES: readonly { readonly minutes: number | null; readonly label: string }[] = [
|
|
32
|
+
{ minutes: 60, label: "1 hour" },
|
|
33
|
+
{ minutes: 6 * 60, label: "6 hours" },
|
|
34
|
+
{ minutes: 12 * 60, label: "12 hours" },
|
|
35
|
+
{ minutes: 24 * 60, label: "1 day" },
|
|
36
|
+
{ minutes: 7 * 24 * 60, label: "7 days" },
|
|
37
|
+
{ minutes: null, label: "Permanent" },
|
|
38
|
+
] as const;
|
|
@@ -8,11 +8,12 @@ import { randomBytes } from "node:crypto";
|
|
|
8
8
|
import type { ApiKeyRecord, ApiKeyStore } from "../../persistence/stores/api-key-store";
|
|
9
9
|
import { hashSecret } from "../../security/crypto";
|
|
10
10
|
import { type ShareLinkStore, type ShareLinkSummary } from "../../persistence/stores/share-store";
|
|
11
|
-
import { API_KEY_MODES, type ApiKeyMode, type ApiKeyModelAccessMode, type ShareLinkKind } from "../../persistence/schema";
|
|
11
|
+
import { API_KEY_MODES, API_KEY_CONCURRENCY_SCOPES, type ApiKeyMode, type ApiKeyModelAccessMode, type ShareLinkKind } from "../../persistence/schema";
|
|
12
12
|
import { isValidTenantKeyScope, type AccessScope } from "../../security/access-control";
|
|
13
13
|
import { normalizeClientRouterId } from "../../security/client-router-fingerprint";
|
|
14
14
|
import type { ShareActivityPort } from "../share/share-usage";
|
|
15
15
|
import { ConsoleDomainError } from "../shared/errors";
|
|
16
|
+
import { pickDefined } from "../shared/object";
|
|
16
17
|
import type { ConsoleAccessResolver } from "../auth/access";
|
|
17
18
|
import type { ApiKeyAdmissionService } from "../../security/admission/service";
|
|
18
19
|
import {
|
|
@@ -34,6 +35,9 @@ export type {
|
|
|
34
35
|
SharedKeySummary,
|
|
35
36
|
SharedKeyActivityDetail,
|
|
36
37
|
} from "../share/share-usage";
|
|
38
|
+
/** How a share template's concurrency cap applies to its recipients. */
|
|
39
|
+
export type ConcurrencyScope = (typeof API_KEY_CONCURRENCY_SCOPES)[number];
|
|
40
|
+
|
|
37
41
|
/** Input accepted when creating or editing a key. Null limits mean unlimited. */
|
|
38
42
|
export interface CreateApiKeyRequest {
|
|
39
43
|
enabled?: boolean;
|
|
@@ -49,6 +53,13 @@ export interface CreateApiKeyRequest {
|
|
|
49
53
|
monthlyTokenLimit?: number | null;
|
|
50
54
|
lifetimeTokenBudget?: number | null;
|
|
51
55
|
maxConcurrentRequests?: number | null;
|
|
56
|
+
/**
|
|
57
|
+
* How `maxConcurrentRequests` applies to a share template's family:
|
|
58
|
+
* `family` (default) = one cap across all recipient keys (a single shared
|
|
59
|
+
* admission counter); `per_key` = each recipient key gets its own cap and
|
|
60
|
+
* independent counter. Ignored/meaningless for personal keys.
|
|
61
|
+
*/
|
|
62
|
+
concurrencyScope?: ConcurrencyScope;
|
|
52
63
|
/** Share-template slot cap; only meaningful when keyMode === "share". */
|
|
53
64
|
maxChildren?: number | null;
|
|
54
65
|
modelPrefix?: string;
|
|
@@ -90,6 +101,7 @@ export interface ApiKeyResponse {
|
|
|
90
101
|
readonly modelList?: readonly string[];
|
|
91
102
|
readonly clientRouterDenylist?: readonly string[];
|
|
92
103
|
readonly maxConcurrentRequests?: number;
|
|
104
|
+
readonly concurrencyScope?: ConcurrencyScope;
|
|
93
105
|
readonly maxChildren?: number;
|
|
94
106
|
readonly notesTitle?: string;
|
|
95
107
|
readonly notesSubtitle?: string;
|
|
@@ -119,34 +131,16 @@ export interface UpdateApiKeyResponse extends ApiKeyResponse {
|
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
/**
|
|
122
|
-
* Ban reasons offered by the console dropdown
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
export const API_KEY_BAN_REASONS: readonly { readonly value: string; readonly label: string }[] = [
|
|
128
|
-
{ value: "instant_arbitrary", label: "Instant Ban — Suka suka Gw" },
|
|
129
|
-
{ value: "traffic_suspicious", label: "Your traffic looks suspicious" },
|
|
130
|
-
{ value: "abuse", label: "Abuse of the gateway" },
|
|
131
|
-
{ value: "policy_violation", label: "Policy violation" },
|
|
132
|
-
{ value: "compromised", label: "Key may be compromised" },
|
|
133
|
-
{ value: "quota_exceeded", label: "Quota abused" },
|
|
134
|
-
{ value: "other", label: "Other / custom" },
|
|
135
|
-
] as const;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Ban durations the console offers, in whole minutes. `null` is permanent.
|
|
139
|
-
* Mirrored by the dashboard (`dashboard/src/lib/ban-durations.ts`) so the UI
|
|
140
|
-
* and the API agree on one list.
|
|
134
|
+
* Ban reasons offered by the console dropdown, and the durations the ban
|
|
135
|
+
* endpoint accepts. These are pure lists, kept in `ban-constants.ts` (no
|
|
136
|
+
* `node:*` imports) so the dashboard can import them without dragging Node
|
|
137
|
+
* crypto into the browser bundle. Re-exported here for backend consumers
|
|
138
|
+
* (`routes.ts` validates against `BAN_DURATION_CHOICES`).
|
|
141
139
|
*/
|
|
142
|
-
export
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{ minutes: 24 * 60, label: "1 day" },
|
|
147
|
-
{ minutes: 7 * 24 * 60, label: "7 days" },
|
|
148
|
-
{ minutes: null, label: "Permanent" },
|
|
149
|
-
];
|
|
140
|
+
export {
|
|
141
|
+
API_KEY_BAN_REASONS,
|
|
142
|
+
BAN_DURATION_CHOICES,
|
|
143
|
+
} from "./ban-constants";
|
|
150
144
|
|
|
151
145
|
/** What a bare "ban this key" click uses: the shortest, most reversible choice. */
|
|
152
146
|
export const DEFAULT_BAN_MINUTES: number = 60;
|
|
@@ -154,7 +148,6 @@ export const DEFAULT_BAN_MINUTES: number = 60;
|
|
|
154
148
|
/** Body accepted by the ban endpoint. */
|
|
155
149
|
export interface BanApiKeyRequest {
|
|
156
150
|
readonly reason: string;
|
|
157
|
-
readonly reasonLabel?: string;
|
|
158
151
|
/**
|
|
159
152
|
* Ban duration in whole minutes from {@link BAN_DURATION_CHOICES}; `null`
|
|
160
153
|
* means permanent. Absent = {@link DEFAULT_BAN_MINUTES}.
|
|
@@ -255,16 +248,20 @@ export function generateApiKeySecret(prefix = DEFAULT_API_KEY_PREFIX): {
|
|
|
255
248
|
return { secret, hash: hashSecret(secret), prefix };
|
|
256
249
|
}
|
|
257
250
|
|
|
258
|
-
/** Normalizes a caller-supplied prefix; falls back to
|
|
259
|
-
|
|
251
|
+
/** Normalizes a caller-supplied prefix; falls back to `fallback`. */
|
|
252
|
+
function resolvePrefix(raw: string | undefined, fallback: string): string {
|
|
260
253
|
const trimmed = raw?.trim();
|
|
261
|
-
return trimmed && trimmed.length > 0 ? trimmed :
|
|
254
|
+
return trimmed && trimmed.length > 0 ? trimmed : fallback;
|
|
262
255
|
}
|
|
263
256
|
|
|
264
|
-
/**
|
|
257
|
+
/** Normalizes a caller-supplied prefix; falls back to the personal default. */
|
|
258
|
+
export function resolveKeyPrefix(raw: string | undefined): string {
|
|
259
|
+
return resolvePrefix(raw, DEFAULT_API_KEY_PREFIX);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Resolves the share-key prefix; falls back to the share default. */
|
|
265
263
|
export function resolveShareKeyPrefix(raw: string | undefined): string {
|
|
266
|
-
|
|
267
|
-
return !trimmed ? DEFAULT_SHARE_API_KEY_PREFIX : trimmed;
|
|
264
|
+
return resolvePrefix(raw, DEFAULT_SHARE_API_KEY_PREFIX);
|
|
268
265
|
}
|
|
269
266
|
|
|
270
267
|
/** Maximum hint the enroll page accepts; the dashboard caps its input there. */
|
|
@@ -349,6 +346,19 @@ export function validateApiKeyRequest(request: CreateApiKeyRequest): readonly Ac
|
|
|
349
346
|
finitePositive(request.monthlyTokenLimit, "monthlyTokenLimit");
|
|
350
347
|
finitePositive(request.lifetimeTokenBudget, "lifetimeTokenBudget");
|
|
351
348
|
finitePositive(request.maxConcurrentRequests, "maxConcurrentRequests");
|
|
349
|
+
if (
|
|
350
|
+
request.concurrencyScope !== undefined &&
|
|
351
|
+
!(API_KEY_CONCURRENCY_SCOPES as readonly string[]).includes(request.concurrencyScope)
|
|
352
|
+
) {
|
|
353
|
+
throw new ConsoleDomainError("invalid_limits", 400, "concurrencyScope must be family or per_key");
|
|
354
|
+
}
|
|
355
|
+
if (request.concurrencyScope !== undefined && keyMode !== "share") {
|
|
356
|
+
throw new ConsoleDomainError(
|
|
357
|
+
"invalid_limits",
|
|
358
|
+
400,
|
|
359
|
+
"concurrencyScope is only valid for share templates",
|
|
360
|
+
);
|
|
361
|
+
}
|
|
352
362
|
if (request.maxChildren !== undefined && request.maxChildren !== null) {
|
|
353
363
|
finitePositive(request.maxChildren, "maxChildren");
|
|
354
364
|
if (request.maxChildren > 10_000) {
|
|
@@ -424,34 +434,33 @@ export function sanitizeApiKeyResponse(record: ApiKeyRecord): ApiKeyResponse {
|
|
|
424
434
|
* renaming the key cannot change which key is the default.
|
|
425
435
|
*/
|
|
426
436
|
isDefault: isDefaultGatewayApiKey(record),
|
|
427
|
-
...(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
:
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
:
|
|
437
|
+
...pickDefined({
|
|
438
|
+
keyPrefix,
|
|
439
|
+
parentKeyId: record.parentKeyId,
|
|
440
|
+
notesTitle: record.notesTitle,
|
|
441
|
+
notesSubtitle: record.notesSubtitle,
|
|
442
|
+
notesBody: record.notesBody,
|
|
443
|
+
sharePopupEnabled: record.sharePopupEnabled,
|
|
444
|
+
sharePopupImageMime: record.sharePopupImageMime,
|
|
445
|
+
sharePopupTitle: record.sharePopupTitle,
|
|
446
|
+
sharePopupBody: record.sharePopupBody,
|
|
447
|
+
requestsPerMinute: record.requestsPerMinute,
|
|
448
|
+
dailyTokenLimit: record.dailyTokenLimit,
|
|
449
|
+
monthlyTokenLimit: record.monthlyTokenLimit,
|
|
450
|
+
lifetimeTokenBudget: record.lifetimeTokenBudget,
|
|
451
|
+
maxConcurrentRequests: record.maxConcurrentRequests,
|
|
452
|
+
concurrencyScope: record.concurrencyScope,
|
|
453
|
+
maxChildren: record.maxChildren,
|
|
454
|
+
modelPrefix: record.modelPrefix,
|
|
455
|
+
modelAccessMode: record.modelAccessMode,
|
|
456
|
+
modelList: record.modelList,
|
|
457
|
+
clientRouterDenylist: record.clientRouterDenylist,
|
|
458
|
+
revokedAt: record.revokedAt?.toISOString(),
|
|
459
|
+
bannedAt: record.bannedAt?.toISOString(),
|
|
460
|
+
banReason: record.banReason,
|
|
461
|
+
bannedUntil: record.bannedUntil?.toISOString(),
|
|
462
|
+
}),
|
|
450
463
|
createdAt: record.createdAt.toISOString(),
|
|
451
|
-
...(record.revokedAt === undefined ? {} : { revokedAt: record.revokedAt.toISOString() }),
|
|
452
|
-
...(record.bannedAt === undefined ? {} : { bannedAt: record.bannedAt.toISOString() }),
|
|
453
|
-
...(record.banReason === undefined ? {} : { banReason: record.banReason }),
|
|
454
|
-
...(record.bannedUntil === undefined ? {} : { bannedUntil: record.bannedUntil.toISOString() }),
|
|
455
464
|
tokensConsumed: record.tokensConsumed,
|
|
456
465
|
};
|
|
457
466
|
}
|