cartethyia 2.7.3 → 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-2TJD37Hb.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-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.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-BKj_r0rp.js +1 -0
- 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-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BtPcAfot.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-5SnUSy3j.js +9 -0
- 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-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-TP7voAQ0.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-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DMrMPmth.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-Be5Uzamx.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-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-Bm8WKaGY.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-q5HwZ8nN.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-BTScrQpe.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
- package/dist/dashboard/assets/{list-row-CzFvogbj.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/minimize-2-BTmMTK4o.js +1 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
- package/dist/dashboard/assets/mutation-Rr0TIvcj.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/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
- package/dist/dashboard/assets/query-keys-BloKtaXJ.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-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
- 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-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.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 +59 -57
- package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
- package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
- package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
- package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
- 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/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
- package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
- package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
- package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -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 -5
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +67 -10
- 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 +8 -4
- 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 +92 -31
- package/src/console/api-keys/routes.ts +131 -6
- package/src/console/audit/routes.ts +3 -3
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +5 -5
- 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 +40 -34
- 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 +11 -9
- package/src/console/backup/export-endpoint.ts +11 -12
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +32 -36
- 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 +4 -4
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router-guards.ts +2 -2
- package/src/console/console-router.ts +36 -4
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/data-management/routes.ts +3 -3
- package/src/console/domain-registration.ts +18 -4
- 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 +5 -1
- package/src/console/observability/live.ts +34 -21
- package/src/console/observability/logs.ts +4 -4
- package/src/console/observability/performance.ts +3 -3
- package/src/console/observability/routes.ts +3 -3
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +36 -20
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +82 -22
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +110 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +30 -6
- package/src/console/providers/catalog/store-helpers.ts +349 -326
- package/src/console/providers/catalog/store.ts +1662 -1292
- package/src/console/providers/detail/routes.ts +4 -4
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +95 -16
- 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 +285 -67
- package/src/console/quota/account-test-egress.ts +4 -4
- 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/model/routes.ts +3 -3
- package/src/console/routing/pools/contracts.ts +13 -10
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/operations.ts +14 -7
- package/src/console/routing/pools/probe-verdict.ts +8 -3
- package/src/console/routing/pools/relay-deploy.ts +12 -12
- package/src/console/routing/pools/routes.ts +3 -3
- package/src/console/routing/pools/store.ts +21 -1
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/routes.ts +3 -3
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +112 -44
- package/src/console/share/share-stats.ts +109 -39
- 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 +42 -6
- 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 +256 -98
- 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 +76 -5
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +55 -51
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-cooldown-store.ts +71 -16
- package/src/network/pool-health-machine.ts +22 -2
- package/src/network/rate-limit-verdict.ts +68 -0
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +24 -75
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +286 -214
- 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/telemetry-status.ts +1 -1
- 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 +10 -5
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +19 -7
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +177 -45
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +109 -4
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/stores/telemetry-store.ts +1 -1
- 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 +12 -16
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/gateway-error.ts +6 -3
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/image-generation.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 +27 -12
- package/src/protocol/response/codex.ts +2 -2
- package/src/protocol/response/gemini.ts +1 -1
- package/src/protocol/response/messages.ts +6 -6
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +3 -3
- package/src/protocol/sse-decoder.ts +64 -4
- 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 +8 -8
- 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/protocol/upstream/send-claude-messages.ts +3 -3
- package/src/providers/adapters/base-adapter.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +44 -5
- 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/authentication/oauth-refresh-service.ts +2 -2
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/configured-provider.ts +1 -1
- 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 +50 -15
- package/src/providers/discovery/probing-service.ts +18 -20
- package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
- package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
- package/src/providers/integrations/anthropic.ts +4 -11
- 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 +15 -26
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
- 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-discovery-shared.ts +37 -6
- package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
- package/src/providers/integrations/buddy/buddy-media.ts +16 -16
- 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 +5 -16
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-betas.ts +1 -1
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/claude-credentials.ts +1 -1
- package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
- package/src/providers/integrations/claude/claude.ts +3 -10
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-errors.ts +1 -1
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/codex/codex.ts +14 -15
- package/src/providers/integrations/commandcode/commandcode.ts +76 -116
- package/src/providers/integrations/commandcode/quota.ts +132 -48
- package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
- 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 +53 -20
- 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 +13 -13
- package/src/providers/integrations/gemini.ts +11 -11
- 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 +47 -20
- 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 +88 -42
- package/src/providers/integrations/inferhub.ts +4 -11
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kimi/kimi.ts +4 -11
- 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 +91 -78
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/muse/muse.ts +6 -9
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/perplexity.ts +2 -2
- package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
- package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -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 +22 -28
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
- package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
- package/src/providers/integrations/qoder/qoder.ts +521 -63
- 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/tokenharbor.ts +2 -2
- 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 +59 -19
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- 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 +22 -6
- package/src/providers/operations/provider-credential-service.ts +35 -6
- package/src/providers/operations/upstream-deadline.ts +3 -3
- package/src/providers/provider-contracts.ts +65 -10
- package/src/providers/provider-credential-resolver.ts +1 -1
- 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-registry.ts +4 -4
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +28 -10
- package/src/providers/quota/refresh.ts +29 -6
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +6 -8
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +8 -8
- package/src/security/admission/reasons.ts +17 -17
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +20 -8
- 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/coerce.ts +19 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +5 -4
- package/src/transport/dispatch/attempt-loop.ts +10 -7
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +28 -25
- package/src/transport/dispatch/generation.ts +33 -53
- package/src/transport/dispatch/leases.ts +8 -8
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +10 -8
- package/src/transport/dispatch/responses-compact.ts +35 -56
- package/src/transport/dispatch/retry-policy.ts +4 -67
- package/src/transport/dispatch/stream-bridge.ts +1 -1
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +11 -10
- 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 +27 -55
- package/src/transport/dispatch/token-count.ts +49 -46
- package/src/transport/dispatch/websearch.ts +24 -50
- package/src/transport/drain-endpoint.ts +3 -3
- package/src/transport/failure-policy.ts +19 -6
- package/src/transport/guards/auth-guard.ts +6 -11
- package/src/transport/guards/body-policy.ts +7 -7
- package/src/transport/guards/error-lifecycle.ts +18 -3
- package/src/transport/guards/guard-errors.ts +7 -3
- package/src/transport/guards/headroom-guard.ts +2 -2
- package/src/transport/guards/pipeline.ts +7 -7
- package/src/transport/guards/readiness-guard.ts +16 -2
- package/src/transport/guards/request-context.ts +15 -20
- package/src/transport/request/preparer.ts +306 -27
- 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 +5 -20
- 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 +113 -19
- package/src/transport/routing/route-model.ts +131 -38
- package/src/transport/routing/router.ts +154 -39
- package/src/transport/shutdown-notice.ts +21 -9
- 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 +3 -3
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/encode.ts +1 -1
- 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-2TJD37Hb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.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-0OsXRGXe.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
- package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
- package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
- package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
- package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
- package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
- package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
- package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
- package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
- package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
- package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
- package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
- package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
- package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
- package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
- package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
- package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
- package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
- package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
- package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
- package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
- package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
- package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
- package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
- package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
- package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
- package/dist/dashboard/assets/state-DLS7IDMy.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-42ItvbAs.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dmnfh1Ue.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-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-wvwCi4Eh.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
|
@@ -123,42 +123,42 @@ const ADAPTER_OWNED: Record<string, true> = {
|
|
|
123
123
|
export function validateCompatibilityProfile(profile: CompatibilityProfile): void {
|
|
124
124
|
if (profile.cli_identity !== undefined) {
|
|
125
125
|
if (typeof profile.cli_identity !== "boolean") {
|
|
126
|
-
throw new GatewayError("invalid_request", 400, "cli_identity must be boolean");
|
|
126
|
+
throw new GatewayError("invalid_request", 400, "cli_identity must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
if (profile.gateway_user_agent !== undefined) {
|
|
130
130
|
if (typeof profile.gateway_user_agent !== "boolean") {
|
|
131
|
-
throw new GatewayError("invalid_request", 400, "gateway_user_agent must be boolean");
|
|
131
|
+
throw new GatewayError("invalid_request", 400, "gateway_user_agent must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
if (profile.extra_headers) {
|
|
135
135
|
for (const [rawName, rawValue] of Object.entries(profile.extra_headers)) {
|
|
136
136
|
const name = rawName.toLowerCase();
|
|
137
137
|
if (name.length < 1 || name.length > 64 || !TOKEN_REGEX.test(name)) {
|
|
138
|
-
throw new GatewayError("invalid_request", 400, `invalid header name ${rawName}
|
|
138
|
+
throw new GatewayError("invalid_request", 400, `invalid header name ${rawName} (request {requestId}). Check the shape of what you sent — then resend 🪞`);
|
|
139
139
|
}
|
|
140
140
|
if (isProtectedHeader(name, ADAPTER_OWNED)) {
|
|
141
141
|
throw new GatewayError(
|
|
142
142
|
"invalid_request",
|
|
143
143
|
400,
|
|
144
|
-
`header ${rawName} is not allowed as custom header
|
|
144
|
+
`header ${rawName} is not allowed as custom header (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
145
145
|
);
|
|
146
146
|
}
|
|
147
147
|
if (typeof rawValue !== "string") {
|
|
148
148
|
throw new GatewayError(
|
|
149
149
|
"invalid_request",
|
|
150
150
|
400,
|
|
151
|
-
`header value for ${rawName} must be string
|
|
151
|
+
`header value for ${rawName} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
152
152
|
);
|
|
153
153
|
}
|
|
154
154
|
if (Buffer.byteLength(rawValue, "utf8") > 4096) {
|
|
155
|
-
throw new GatewayError("invalid_request", 400, `header value for ${rawName} exceeds 4KiB
|
|
155
|
+
throw new GatewayError("invalid_request", 400, `header value for ${rawName} exceeds 4KiB (request {requestId}). We love long reads, but not that long 📚`);
|
|
156
156
|
}
|
|
157
157
|
if (/[\r\n\x00-\x1f\x7f]/.test(rawValue)) {
|
|
158
158
|
throw new GatewayError(
|
|
159
159
|
"invalid_request",
|
|
160
160
|
400,
|
|
161
|
-
`header value for ${rawName} contains control characters
|
|
161
|
+
`header value for ${rawName} contains control characters (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -166,9 +166,9 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
|
|
|
166
166
|
if (profile.extra_query_params) {
|
|
167
167
|
for (const [k, v] of Object.entries(profile.extra_query_params)) {
|
|
168
168
|
if (typeof v !== "string")
|
|
169
|
-
throw new GatewayError("invalid_request", 400, `query param ${k} must be string
|
|
169
|
+
throw new GatewayError("invalid_request", 400, `query param ${k} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`);
|
|
170
170
|
if (/[\r\n]/.test(k) || /[\r\n]/.test(v))
|
|
171
|
-
throw new GatewayError("invalid_request", 400, `query param contains CRLF
|
|
171
|
+
throw new GatewayError("invalid_request", 400, `query param contains CRLF (request {requestId}). Check the shape of what you sent — then resend 🪞`);
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
if (profile.endpoint_paths_by_wire_family) {
|
|
@@ -177,56 +177,56 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
|
|
|
177
177
|
throw new GatewayError(
|
|
178
178
|
"invalid_request",
|
|
179
179
|
400,
|
|
180
|
-
`endpoint_paths_by_wire_family: unknown wire family ${wf}
|
|
180
|
+
`endpoint_paths_by_wire_family: unknown wire family ${wf} (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
181
181
|
);
|
|
182
182
|
}
|
|
183
183
|
if (typeof path !== "string") {
|
|
184
184
|
throw new GatewayError(
|
|
185
185
|
"invalid_request",
|
|
186
186
|
400,
|
|
187
|
-
`endpoint_paths_by_wire_family.${wf} must be string
|
|
187
|
+
`endpoint_paths_by_wire_family.${wf} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
188
188
|
);
|
|
189
189
|
}
|
|
190
190
|
if (path.length === 0 || path.length > 256) {
|
|
191
191
|
throw new GatewayError(
|
|
192
192
|
"invalid_request",
|
|
193
193
|
400,
|
|
194
|
-
`endpoint_paths_by_wire_family.${wf} path length must be 1-256 chars
|
|
194
|
+
`endpoint_paths_by_wire_family.${wf} path length must be 1-256 chars (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
195
195
|
);
|
|
196
196
|
}
|
|
197
197
|
if (!path.startsWith("/")) {
|
|
198
198
|
throw new GatewayError(
|
|
199
199
|
"invalid_request",
|
|
200
200
|
400,
|
|
201
|
-
`endpoint_paths_by_wire_family.${wf} path must start with
|
|
201
|
+
`endpoint_paths_by_wire_family.${wf} path must start with / (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
202
202
|
);
|
|
203
203
|
}
|
|
204
204
|
if (/[\s\r\n\x00-\x1f\x7f]/.test(path)) {
|
|
205
205
|
throw new GatewayError(
|
|
206
206
|
"invalid_request",
|
|
207
207
|
400,
|
|
208
|
-
`endpoint_paths_by_wire_family.${wf} path contains invalid characters
|
|
208
|
+
`endpoint_paths_by_wire_family.${wf} path contains invalid characters (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
209
209
|
);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
if (profile.model_wire_families) {
|
|
214
214
|
if (!Array.isArray(profile.model_wire_families)) {
|
|
215
|
-
throw new GatewayError("invalid_request", 400, "model_wire_families must be an array");
|
|
215
|
+
throw new GatewayError("invalid_request", 400, "model_wire_families must be an array (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
216
216
|
}
|
|
217
217
|
for (const rule of profile.model_wire_families) {
|
|
218
218
|
if (typeof rule?.pattern !== "string" || rule.pattern.length === 0) {
|
|
219
219
|
throw new GatewayError(
|
|
220
220
|
"invalid_request",
|
|
221
221
|
400,
|
|
222
|
-
"model_wire_families[].pattern must be a non-empty string",
|
|
222
|
+
"model_wire_families[].pattern must be a non-empty string (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
223
223
|
);
|
|
224
224
|
}
|
|
225
225
|
if (rule.pattern.length > 256) {
|
|
226
226
|
throw new GatewayError(
|
|
227
227
|
"invalid_request",
|
|
228
228
|
400,
|
|
229
|
-
"model_wire_families[].pattern must be at most 256 chars",
|
|
229
|
+
"model_wire_families[].pattern must be at most 256 chars (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
230
230
|
);
|
|
231
231
|
}
|
|
232
232
|
try {
|
|
@@ -235,14 +235,14 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
|
|
|
235
235
|
throw new GatewayError(
|
|
236
236
|
"invalid_request",
|
|
237
237
|
400,
|
|
238
|
-
`model_wire_families[].pattern ${rule.pattern} is not a valid regular expression
|
|
238
|
+
`model_wire_families[].pattern ${rule.pattern} is not a valid regular expression (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
239
239
|
);
|
|
240
240
|
}
|
|
241
241
|
if (!isWireFamily(rule.wire_family)) {
|
|
242
242
|
throw new GatewayError(
|
|
243
243
|
"invalid_request",
|
|
244
244
|
400,
|
|
245
|
-
`model_wire_families[].wire_family: unknown wire family ${String(rule.wire_family)}
|
|
245
|
+
`model_wire_families[].wire_family: unknown wire family ${String(rule.wire_family)} (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
246
246
|
);
|
|
247
247
|
}
|
|
248
248
|
}
|
|
@@ -251,10 +251,10 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
|
|
|
251
251
|
profile.streaming_usage_mode &&
|
|
252
252
|
!["include_usage", "none"].includes(profile.streaming_usage_mode)
|
|
253
253
|
) {
|
|
254
|
-
throw new GatewayError("invalid_request", 400, "invalid streaming_usage_mode");
|
|
254
|
+
throw new GatewayError("invalid_request", 400, "invalid streaming_usage_mode (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
255
255
|
}
|
|
256
256
|
if (profile.structured_output && typeof profile.structured_output.enabled !== "boolean") {
|
|
257
|
-
throw new GatewayError("invalid_request", 400, "structured_output.enabled must be boolean");
|
|
257
|
+
throw new GatewayError("invalid_request", 400, "structured_output.enabled must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
258
258
|
}
|
|
259
259
|
// If any field is present but has no runtime reader, our current reader set covers all fields above.
|
|
260
260
|
const allowed: Record<string, true> = {
|
|
@@ -281,7 +281,7 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
|
|
|
281
281
|
throw new GatewayError(
|
|
282
282
|
"invalid_request",
|
|
283
283
|
400,
|
|
284
|
-
`unknown compatibility_profile field ${k} has no runtime reader
|
|
284
|
+
`unknown compatibility_profile field ${k} has no runtime reader (request {requestId}). Check the shape of what you sent — then resend 🪞`,
|
|
285
285
|
);
|
|
286
286
|
}
|
|
287
287
|
}
|
|
@@ -508,6 +508,13 @@ export interface ProviderAccountResponse {
|
|
|
508
508
|
label: string;
|
|
509
509
|
credentialKind: CredentialKind;
|
|
510
510
|
credentialMode?: CredentialMode;
|
|
511
|
+
/**
|
|
512
|
+
* Which sign-in family issued this credential, read from the account's
|
|
513
|
+
* `auth_state` (e.g. `social`/`oidc`/`api_key` for Kiro). Surfaced so the
|
|
514
|
+
* console can badge an account by how it logged in without shipping the
|
|
515
|
+
* whole auth state to the browser.
|
|
516
|
+
*/
|
|
517
|
+
authMethod?: string;
|
|
511
518
|
tokenExpiresAt?: string;
|
|
512
519
|
/**
|
|
513
520
|
* Who issued this credential, read from the JWT `iss` claim at registration
|
|
@@ -539,6 +546,27 @@ export interface ProviderAccountResponse {
|
|
|
539
546
|
staticToken?: boolean;
|
|
540
547
|
/** Stable list position within this provider; the console's "Added" order. */
|
|
541
548
|
sortIndex: number;
|
|
549
|
+
/**
|
|
550
|
+
* Row flavor. `"pool"` marks a pool-as-account entity (see
|
|
551
|
+
* `provider_pool_accounts`): it is an account-equivalent for an
|
|
552
|
+
* ip-scoped, credential-less provider, resolves no credential, and is
|
|
553
|
+
* owned by its pool. Absent means a real `provider_accounts` row.
|
|
554
|
+
*/
|
|
555
|
+
kind?: "pool";
|
|
556
|
+
/** The owning pool row (present for `kind: "pool"`). */
|
|
557
|
+
networkPoolId?: string;
|
|
558
|
+
/**
|
|
559
|
+
* Provider-scoped rate-limit markers on the owning pool, when this is a
|
|
560
|
+
* pool-as-account row. Mirrors `NetworkPoolResponse.providerCooldowns`: a
|
|
561
|
+
* 429 cooldown refills, a block means the upstream retired the egress
|
|
562
|
+
* address. Absent for real accounts and for pools with no markers.
|
|
563
|
+
*/
|
|
564
|
+
providerCooldowns?: Array<{
|
|
565
|
+
providerId: string;
|
|
566
|
+
until: string;
|
|
567
|
+
reason: string;
|
|
568
|
+
blocked: boolean;
|
|
569
|
+
}>;
|
|
542
570
|
}
|
|
543
571
|
/**
|
|
544
572
|
* Plaintext export of one account's decrypted provider tokens.
|
|
@@ -632,6 +660,18 @@ export interface ProviderResponse {
|
|
|
632
660
|
isBuiltIn: boolean;
|
|
633
661
|
/** True when this tenant has any persisted account for the provider. */
|
|
634
662
|
configured?: boolean;
|
|
663
|
+
/**
|
|
664
|
+
* Number of provider accounts this tenant has for the provider. Present on
|
|
665
|
+
* list items (the Providers page overview); absent elsewhere.
|
|
666
|
+
*/
|
|
667
|
+
accountCount?: number;
|
|
668
|
+
/**
|
|
669
|
+
* Accounts whose status is not disabled/revoked — an account parked by the
|
|
670
|
+
* health machine (`cooldown`) still counts. Present on list items.
|
|
671
|
+
*/
|
|
672
|
+
activeAccountCount?: number;
|
|
673
|
+
/** Enabled model rows the tenant can see for the provider. Present on list items. */
|
|
674
|
+
modelCount?: number;
|
|
635
675
|
/** `false` only for a genuinely credential-less provider (OpenCode Free) —
|
|
636
676
|
* the dashboard hides account creation for it since none is usable. */
|
|
637
677
|
requiresAccount: boolean;
|
|
@@ -779,6 +819,26 @@ export interface ProviderCatalogStore {
|
|
|
779
819
|
syncModels(tenantId: string, providerId: string): Promise<{ synced: number }>;
|
|
780
820
|
listAccounts(tenantId: string, providerId: string): Promise<readonly ProviderAccountResponse[]>;
|
|
781
821
|
listAllAccounts(tenantId: string): Promise<readonly ProviderAccountResponse[]>;
|
|
822
|
+
/**
|
|
823
|
+
* Provider-id + status only, for every account the tenant can see. Much
|
|
824
|
+
* cheaper than `listAllAccounts` (which also fetches today/lifetime usage,
|
|
825
|
+
* inflight, pool rows): used by the provider list's "configured" marker and
|
|
826
|
+
* the flat model picker's active-account counts, neither of which reads
|
|
827
|
+
* usage.
|
|
828
|
+
*/
|
|
829
|
+
listAllAccountSummaries(tenantId: string): Promise<readonly { providerId: string; status: string }[]>;
|
|
830
|
+
/**
|
|
831
|
+
* Per-provider account totals for the tenant, from one grouped read. Used by
|
|
832
|
+
* the provider list overview (`accountCount` / `activeAccountCount`).
|
|
833
|
+
*/
|
|
834
|
+
providerAccountCounts(
|
|
835
|
+
tenantId: string,
|
|
836
|
+
): Promise<readonly { providerId: string; total: number; active: number }[]>;
|
|
837
|
+
/**
|
|
838
|
+
* Per-provider enabled model-row counts for the tenant, from one grouped read.
|
|
839
|
+
* Used by the provider list overview (`modelCount`).
|
|
840
|
+
*/
|
|
841
|
+
providerModelCounts(tenantId: string): Promise<readonly { providerId: string; count: number }[]>;
|
|
782
842
|
/**
|
|
783
843
|
* Non-secret upstream auth configuration for the given owned accounts,
|
|
784
844
|
* keyed by account id. Used by the account-export route so a re-import can
|
|
@@ -62,7 +62,7 @@ export function createModelCatalogOperations(config: ProviderCatalogConfig) {
|
|
|
62
62
|
const a = requireTenantAnyScope(access, MODEL_READ_SCOPES);
|
|
63
63
|
const [providers, allAccounts] = await Promise.all([
|
|
64
64
|
config.store.list(a.tenantId),
|
|
65
|
-
config.store.
|
|
65
|
+
config.store.listAllAccountSummaries(a.tenantId),
|
|
66
66
|
]);
|
|
67
67
|
const accountsByProvider = new Map<string, number>();
|
|
68
68
|
for (const account of allAccounts) {
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
requireGlobalAdmin,
|
|
17
17
|
requireTenantAnyScope,
|
|
18
18
|
} from "../../shared/errors";
|
|
19
|
+
import { cachedReadWithEtag, conditionalResponse } from "../../shared/read-through-cache";
|
|
20
|
+
import type { RedisClient } from "../../../persistence/redis";
|
|
19
21
|
import type { AccessDecision } from "../../../security/access-control";
|
|
20
22
|
import type { ProviderUsageDayRow } from "../../../observability/event-query";
|
|
21
23
|
import { isBundledProviderId } from "../../../providers/provider-contracts";
|
|
@@ -128,7 +130,22 @@ export interface ProviderCatalogConfig {
|
|
|
128
130
|
readonly auditSink?: AuditSink;
|
|
129
131
|
/** Registry-backed OAuth login clients; used to compute `oauthFlows` on responses. */
|
|
130
132
|
readonly providerRegistry: ProviderRegistry;
|
|
131
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Shared Redis client for the provider-list read-through cache. Omitted in
|
|
135
|
+
* lite mode / tests, where `cachedReadWithEtag` falls back to its bounded
|
|
136
|
+
* in-process TTL store; the ETag/304 semantics are identical either way.
|
|
137
|
+
*/
|
|
138
|
+
readonly redis?: RedisClient | undefined;
|
|
139
|
+
/**
|
|
140
|
+
* Drops the cached route snapshot after a catalog write. `currentRevision`
|
|
141
|
+
* (when the host exposes it) is folded into the provider-list cache key, so
|
|
142
|
+
* every mutation that already bumps the snapshot — provider, account, and
|
|
143
|
+
* model writes — rotates the cached overview without a per-path delete.
|
|
144
|
+
*/
|
|
145
|
+
readonly snapshotInvalidator?: {
|
|
146
|
+
invalidate(): Promise<number>;
|
|
147
|
+
currentRevision?(): number;
|
|
148
|
+
};
|
|
132
149
|
/**
|
|
133
150
|
* Re-applies one provider's BYOK adapter registration after a create/update
|
|
134
151
|
* so a custom provider is dispatchable without a restart. Optional: tests
|
|
@@ -232,23 +249,81 @@ function toProviderLoginField(field: OAuthLoginField): ProviderLoginField {
|
|
|
232
249
|
: { options: field.options.map((option) => ({ value: option.value, label: option.label })) }),
|
|
233
250
|
};
|
|
234
251
|
}
|
|
252
|
+
/** Provider-list cache TTL: short enough that a 60s poll re-checks the DB
|
|
253
|
+
* occasionally, long enough that a warm page does zero per-card work. */
|
|
254
|
+
const PROVIDER_LIST_CACHE_TTL_SECONDS = 20;
|
|
255
|
+
|
|
256
|
+
/** Cache key namespace + shape version for the provider-list overview. */
|
|
257
|
+
const PROVIDER_LIST_CACHE_SHAPE = "providers:v1:list";
|
|
258
|
+
|
|
259
|
+
/** Version of the read-through cache backend, so a bump is a key rotation. */
|
|
260
|
+
const PROVIDER_LIST_CACHE_REVISION = 1;
|
|
261
|
+
|
|
262
|
+
/** The list projection shared by `listProviders` and its cached wrapper. */
|
|
263
|
+
async function computeProviderList(
|
|
264
|
+
config: ProviderCatalogConfig,
|
|
265
|
+
tenantId: string,
|
|
266
|
+
): Promise<ProviderResponse[]> {
|
|
267
|
+
const [records, accountCounts, modelCounts] = await Promise.all([
|
|
268
|
+
config.store.list(tenantId),
|
|
269
|
+
config.store.providerAccountCounts(tenantId),
|
|
270
|
+
config.store.providerModelCounts(tenantId),
|
|
271
|
+
]);
|
|
272
|
+
const accountsByProvider = new Map(accountCounts.map((row) => [row.providerId, row]));
|
|
273
|
+
const modelsByProvider = new Map(modelCounts.map((row) => [row.providerId, row.count]));
|
|
274
|
+
return Promise.all(
|
|
275
|
+
records.map((r) => {
|
|
276
|
+
const counts = accountsByProvider.get(r.providerId);
|
|
277
|
+
return attachProviderCapabilities(
|
|
278
|
+
{
|
|
279
|
+
...sanitizeProviderResponse(r),
|
|
280
|
+
// A provider with no persisted accounts is not "configured"; the
|
|
281
|
+
// count fields are still present (zero) so the card renders the
|
|
282
|
+
// empty state instead of a loading placeholder.
|
|
283
|
+
configured: counts !== undefined,
|
|
284
|
+
accountCount: counts?.total ?? 0,
|
|
285
|
+
activeAccountCount: counts?.active ?? 0,
|
|
286
|
+
modelCount: modelsByProvider.get(r.providerId) ?? 0,
|
|
287
|
+
},
|
|
288
|
+
config.providerRegistry,
|
|
289
|
+
);
|
|
290
|
+
}),
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
235
294
|
export function createProviderCatalogOperations(config: ProviderCatalogConfig) {
|
|
236
295
|
const operations = {
|
|
237
296
|
async listProviders(access: AccessDecision | undefined): Promise<ProviderResponse[]> {
|
|
238
297
|
const a = requireTenantAnyScope(access, PROVIDER_READ_SCOPES);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
298
|
+
return computeProviderList(config, a.tenantId);
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* The full provider list with overview counts, served through the
|
|
302
|
+
* read-through cache (P-04). A repeated poll answers `304` with the ETag
|
|
303
|
+
* instead of recomputing the two grouped count queries.
|
|
304
|
+
*
|
|
305
|
+
* Returning a `Response` rather than a plain array is what makes the ETag
|
|
306
|
+
* conditional branch possible: a `304` has no body to serialize. The cache
|
|
307
|
+
* key is tenant-scoped and carries the routing revision, so a provider /
|
|
308
|
+
* account / model mutation that bumps the snapshot rotates the key and the
|
|
309
|
+
* next read recomputes fresh counts.
|
|
310
|
+
*/
|
|
311
|
+
async listProvidersCached(
|
|
312
|
+
access: AccessDecision | undefined,
|
|
313
|
+
ifNoneMatch: string | null,
|
|
314
|
+
): Promise<Response> {
|
|
315
|
+
const a = requireTenantAnyScope(access, PROVIDER_READ_SCOPES);
|
|
316
|
+
const revision = config.snapshotInvalidator?.currentRevision?.() ?? 0;
|
|
317
|
+
const key =
|
|
318
|
+
`cartethyia:${PROVIDER_LIST_CACHE_SHAPE}:v${PROVIDER_LIST_CACHE_REVISION}:` +
|
|
319
|
+
`${a.tenantId}:${revision}`;
|
|
320
|
+
const result = await cachedReadWithEtag(
|
|
321
|
+
config.redis,
|
|
322
|
+
key,
|
|
323
|
+
() => computeProviderList(config, a.tenantId),
|
|
324
|
+
PROVIDER_LIST_CACHE_TTL_SECONDS,
|
|
251
325
|
);
|
|
326
|
+
return conditionalResponse(ifNoneMatch, result, result.value);
|
|
252
327
|
},
|
|
253
328
|
async getProviderDetail(
|
|
254
329
|
access: AccessDecision | undefined,
|
|
@@ -693,12 +768,30 @@ export function createProviderCatalogOperations(config: ProviderCatalogConfig) {
|
|
|
693
768
|
// Non-secret auth state is part of the credential export: without
|
|
694
769
|
// it a re-import loses the upstream user id and region that Trae
|
|
695
770
|
// refresh and dispatch are addressed by.
|
|
696
|
-
...(() => {
|
|
771
|
+
...(await (async () => {
|
|
697
772
|
const authState = authStates[account.id];
|
|
698
|
-
|
|
699
|
-
|
|
773
|
+
// Buddy providers bind a per-account device identity
|
|
774
|
+
// (qimei36) that is normally derived from the INTERNAL account
|
|
775
|
+
// id. Export must materialize that raw binding into the
|
|
776
|
+
// exported auth state — otherwise a re-import mints a new
|
|
777
|
+
// account id, the derived binding changes, and the upstream
|
|
778
|
+
// channel check (11128) rejects the imported account.
|
|
779
|
+
const materialized =
|
|
780
|
+
account.providerId === "cb" ||
|
|
781
|
+
account.providerId === "cbcn" ||
|
|
782
|
+
account.providerId === "workbuddy" ||
|
|
783
|
+
account.providerId === "workbuddycn"
|
|
784
|
+
// dynamic-import: B-02 lazy graph — buddy device-binding materializer, buddy-family only.
|
|
785
|
+
// The buddy-identity graph is lazy-loaded: the device-binding
|
|
786
|
+
// materializer only runs for buddy-family accounts (B-02).
|
|
787
|
+
? (await import("../../../providers/integrations/buddy/buddy-identity"))
|
|
788
|
+
.materializeBuddyDeviceBinding(account.id, authState)
|
|
789
|
+
: undefined;
|
|
790
|
+
const effectiveAuthState = materialized ?? authState;
|
|
791
|
+
return effectiveAuthState !== undefined && Object.keys(effectiveAuthState).length > 0
|
|
792
|
+
? { authState: effectiveAuthState }
|
|
700
793
|
: {};
|
|
701
|
-
})(),
|
|
794
|
+
})()),
|
|
702
795
|
...(account.inflight === undefined ? {} : { inflight: account.inflight }),
|
|
703
796
|
createdAt: account.createdAt,
|
|
704
797
|
...(account.cooldownUntil ? { cooldownUntil: account.cooldownUntil } : {}),
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { consoleErrorHandler } from "../../shared/errors";
|
|
2
2
|
import { literalUnion } from "../../shared/elysia-schema";
|
|
3
|
-
import { Elysia, t } from "elysia";
|
|
3
|
+
import { Elysia, t, type AnyElysia } from "elysia";
|
|
4
4
|
import { SERVICE_KINDS, WIRE_FAMILIES } from "../../../protocol/canonical-model";
|
|
5
5
|
import { PROBE_REASONING_EFFORTS } from "../../../providers/discovery/discovery-types";
|
|
6
6
|
import {
|
|
@@ -150,13 +150,37 @@ const bulkDeleteModelsBody = t.Object({
|
|
|
150
150
|
const usageMatrixQuery = t.Object({
|
|
151
151
|
days: t.Optional(t.Integer({ minimum: 1, maximum: 366 })),
|
|
152
152
|
});
|
|
153
|
-
export function createProviderCatalogRoutes(config: ProviderCatalogConfig):
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
export function createProviderCatalogRoutes(config: ProviderCatalogConfig): AnyElysia {
|
|
154
|
+
// One provider-list cache revision shared by both operation factories. Every
|
|
155
|
+
// provider/account/model mutation already funnels through the snapshot
|
|
156
|
+
// invalidator; wrapping it here means any of those writes bumps the revision
|
|
157
|
+
// folded into the provider-list cache key, so the cached overview (P-04)
|
|
158
|
+
// recomputes on the next read without a per-path cache delete. The revision
|
|
159
|
+
// stays per route-group, so a mutation handled by a peer process still
|
|
160
|
+
// converges when its own entry's TTL lapses.
|
|
161
|
+
const underlyingInvalidator = config.snapshotInvalidator;
|
|
162
|
+
let providerListCacheRevision = 0;
|
|
163
|
+
const catalogSnapshotInvalidator = underlyingInvalidator
|
|
164
|
+
? {
|
|
165
|
+
invalidate: async () => {
|
|
166
|
+
providerListCacheRevision += 1;
|
|
167
|
+
return underlyingInvalidator.invalidate();
|
|
168
|
+
},
|
|
169
|
+
currentRevision: () => providerListCacheRevision,
|
|
170
|
+
}
|
|
171
|
+
: undefined;
|
|
172
|
+
const effectiveConfig = catalogSnapshotInvalidator
|
|
173
|
+
? { ...config, snapshotInvalidator: catalogSnapshotInvalidator }
|
|
174
|
+
: config;
|
|
175
|
+
const factory = createProviderCatalogOperations(effectiveConfig);
|
|
176
|
+
const modelFactory = createModelCatalogOperations(effectiveConfig);
|
|
156
177
|
return new Elysia({ prefix: "/providers" })
|
|
157
178
|
.error(consoleErrorHandler("Provider catalog operation failed"))
|
|
158
179
|
.get("/", async ({ request }) => {
|
|
159
|
-
return await factory.
|
|
180
|
+
return await factory.listProvidersCached(
|
|
181
|
+
config.accessResolver(request),
|
|
182
|
+
request.headers.get("if-none-match"),
|
|
183
|
+
);
|
|
160
184
|
})
|
|
161
185
|
.patch(
|
|
162
186
|
"/platform/global/:providerId",
|
|
@@ -394,5 +418,5 @@ export function createProviderCatalogRoutes(config: ProviderCatalogConfig): Elys
|
|
|
394
418
|
body.accountIds,
|
|
395
419
|
);
|
|
396
420
|
},
|
|
397
|
-
)
|
|
421
|
+
);
|
|
398
422
|
}
|