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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ConsoleAccessResolver } from "../auth/access";
|
|
2
2
|
import type { AuditRecorder } from "../auth/audit-recorder";
|
|
3
|
-
import { markClineApiKeyCredential } from "../../providers/integrations/cline/cline-quota";
|
|
4
3
|
import { type QuotaRefreshDeps } from "../../providers/quota/refresh";
|
|
5
4
|
import type { AccountTestEgressDeps } from "./account-test-egress";
|
|
6
5
|
|
|
@@ -31,8 +30,16 @@ export type AccountStatus = (typeof ACCOUNT_STATUSES)[number];
|
|
|
31
30
|
* omitted it, so a working account was cooled with `quota_fetch_failed` every
|
|
32
31
|
* minute while refreshing fine from the console.
|
|
33
32
|
*/
|
|
34
|
-
export function markProviderApiKeyCredential(providerId: string, credential: string): string {
|
|
35
|
-
|
|
33
|
+
export async function markProviderApiKeyCredential(providerId: string, credential: string): Promise<string> {
|
|
34
|
+
if (providerId !== "cline") return credential;
|
|
35
|
+
// dynamic-import: B-02 lazy graph — cline-only marker, kept off the boot graph.
|
|
36
|
+
// The cline-quota graph is loaded lazily: only `cline` accounts ever need
|
|
37
|
+
// the marker, so a deployment without cline must not pull it into the boot
|
|
38
|
+
// graph (B-02).
|
|
39
|
+
const { markClineApiKeyCredential } = await import(
|
|
40
|
+
"../../providers/integrations/cline/cline-quota"
|
|
41
|
+
);
|
|
42
|
+
return markClineApiKeyCredential(credential);
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
/**
|
|
@@ -4,17 +4,22 @@ import type { Elysia } from "elysia";
|
|
|
4
4
|
import { and, eq, inArray } from "drizzle-orm";
|
|
5
5
|
import { providerAccounts, providers } from "../../persistence/schema";
|
|
6
6
|
import { providerDisplayName } from "../../providers/provider-metadata";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
invalidateCredentialCache,
|
|
9
|
+
invalidateCredentialCaches,
|
|
10
|
+
} from "../../providers/operations/provider-credential-service";
|
|
8
11
|
import { requireTenantScope } from "../shared/errors";
|
|
9
12
|
import { BUDDY_PROVIDER_IDS } from "../../providers/provider-metadata";
|
|
10
|
-
import { readBuddyUsageSnapshots } from "../../providers/integrations/buddy/buddy-usage-store";
|
|
11
13
|
import { GatewayError } from "../../protocol/gateway-error";
|
|
12
14
|
import {
|
|
13
15
|
GLOBAL_QUOTA_LENS,
|
|
14
16
|
getCachedQuotaEntries,
|
|
15
17
|
getCachedQuotaEntry,
|
|
16
18
|
invalidateQuotaCache,
|
|
19
|
+
invalidateQuotaCaches,
|
|
20
|
+
invalidateQuotaCacheForAccount,
|
|
17
21
|
} from "../../providers/quota/cache";
|
|
22
|
+
import { readQuotaSnapshot, readQuotaSnapshots } from "../../providers/quota/snapshot";
|
|
18
23
|
import {
|
|
19
24
|
QUOTA_REFRESH_TIMEOUT_MS,
|
|
20
25
|
refreshAccountQuota,
|
|
@@ -47,10 +52,12 @@ import {
|
|
|
47
52
|
DrizzleQoderNativeIdentityStore,
|
|
48
53
|
type QoderNativeIdentityStore,
|
|
49
54
|
} from "../../providers/integrations/qoder/qoder-native-identity-store";
|
|
50
|
-
import {
|
|
55
|
+
import { claimZcodeGifts, type ZcodeGiftResult } from "../../providers/integrations/zcode-start-plan/gifts";
|
|
56
|
+
import { ZCODE_START_PLAN_PROVIDER_ID } from "../../providers/integrations/zcode-start-plan/provider";
|
|
51
57
|
import {
|
|
52
58
|
supportsAccountReset,
|
|
53
59
|
consumeAccountResetCredit,
|
|
60
|
+
getCachedResetCredits,
|
|
54
61
|
listAccountResetCredits,
|
|
55
62
|
} from "../../providers/operations/account-reset-service";
|
|
56
63
|
import {
|
|
@@ -64,6 +71,14 @@ import {
|
|
|
64
71
|
type AccountQuotaRoutesDeps,
|
|
65
72
|
type AccountStatus,
|
|
66
73
|
} from "./account-quota-shared";
|
|
74
|
+
import {
|
|
75
|
+
DAILY_GROWTH_LEG_TIMEOUT_MS,
|
|
76
|
+
enqueueDailyGrowthJob,
|
|
77
|
+
getDailyGrowthJob,
|
|
78
|
+
withLegBudget,
|
|
79
|
+
type DailyGrowthJobAccount,
|
|
80
|
+
type DailyGrowthJobDeps,
|
|
81
|
+
} from "./daily-growth-job";
|
|
67
82
|
|
|
68
83
|
/** Daily check-in only exists on the buddy billing facade; everything else 400s with intent. */
|
|
69
84
|
function supportsAccountCheckin(providerId: string): boolean {
|
|
@@ -133,10 +148,6 @@ async function runAccountCheckin(
|
|
|
133
148
|
});
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
/** Bound on accounts one manual daily-growth batch may cover. */
|
|
137
|
-
/** Concurrent accounts inside one manual daily-growth batch. */
|
|
138
|
-
const DAILY_GROWTH_CONCURRENCY = 3;
|
|
139
|
-
|
|
140
151
|
/**
|
|
141
152
|
* One account's daily growth pass, report first then claim.
|
|
142
153
|
*
|
|
@@ -175,6 +186,12 @@ async function runDailyGrowthForAccount(
|
|
|
175
186
|
// fails closed instead of reporting under another account's identity. Qoder
|
|
176
187
|
// has no activity-report leg — its daily grant is purely the check-in.
|
|
177
188
|
const qoderAccount = isQoderCheckinProvider(String(providerId));
|
|
189
|
+
// dynamic-import: B-02 lazy graph — buddy uid decoder, only for buddy report legs.
|
|
190
|
+
// The buddy-oauth-shared graph is lazy-loaded: the uid decoder is only
|
|
191
|
+
// needed for buddy accounts' report leg (B-02).
|
|
192
|
+
const { buddyAccountUid } = await import(
|
|
193
|
+
"../../providers/integrations/buddy/buddy-oauth-shared"
|
|
194
|
+
);
|
|
178
195
|
const userId = buddyAccountUid(credential);
|
|
179
196
|
let report: { ok: boolean; message: string };
|
|
180
197
|
if (qoderAccount) {
|
|
@@ -353,6 +370,13 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
353
370
|
getCachedQuotaEntries(access.tenantId, ownedIds, redis),
|
|
354
371
|
getCachedQuotaEntries(GLOBAL_QUOTA_LENS, globalIds, redis),
|
|
355
372
|
]);
|
|
373
|
+
// A page open right after a restart finds the in-process cache empty.
|
|
374
|
+
// Fall back to the persisted snapshots (which survive a restart) so the
|
|
375
|
+
// page still renders the last known balance; the sweep refreshes it.
|
|
376
|
+
const snapshots = await readQuotaSnapshots(
|
|
377
|
+
db,
|
|
378
|
+
rows.filter((row) => !globalCache.has(row.id) && !ownedCache.has(row.id)).map((row) => row.id),
|
|
379
|
+
);
|
|
356
380
|
|
|
357
381
|
const pending = pendingQuotaRefreshes();
|
|
358
382
|
const providerIds = [...new Set(rows.map((row) => row.providerId))];
|
|
@@ -395,6 +419,12 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
395
419
|
// the upstream: the page renders every account at once, and re-hitting the
|
|
396
420
|
// billing endpoint per account would make opening it scale with the
|
|
397
421
|
// account count. One batch read for every buddy row.
|
|
422
|
+
// dynamic-import: B-02 lazy graph — buddy usage snapshots, only when the page renders buddy accounts.
|
|
423
|
+
// The buddy-usage-store graph is lazy-loaded: it is only needed when the
|
|
424
|
+
// page actually renders buddy accounts (B-02).
|
|
425
|
+
const { readBuddyUsageSnapshots } = await import(
|
|
426
|
+
"../../providers/integrations/buddy/buddy-usage-store"
|
|
427
|
+
);
|
|
398
428
|
const usageByAccount = await readBuddyUsageSnapshots(
|
|
399
429
|
db,
|
|
400
430
|
rows.filter((row) => isBuddyProvider(row.providerId)).map((row) => row.id),
|
|
@@ -402,6 +432,9 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
402
432
|
const accounts = rows.map((row) => {
|
|
403
433
|
const entry =
|
|
404
434
|
row.tenantId === null ? globalCache.get(row.id) : ownedCache.get(row.id);
|
|
435
|
+
const snapshot = entry ?? snapshots.get(row.id);
|
|
436
|
+
const entryQuota = snapshot ? snapshot.quota : null;
|
|
437
|
+
const entryFetchedAt = snapshot ? snapshot.fetchedAt : null;
|
|
405
438
|
// No background refresh is enqueued here: enqueuing one for every
|
|
406
439
|
// account whose cached value had aged out means a single page open hits
|
|
407
440
|
// every provider's quota endpoint at once — and because the page also
|
|
@@ -435,13 +468,13 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
435
468
|
name: row.label || row.id,
|
|
436
469
|
credentialHint: row.credentialKind,
|
|
437
470
|
active: row.status === "active",
|
|
438
|
-
quota:
|
|
439
|
-
? toQuotaView(
|
|
440
|
-
fetchedAt:
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
471
|
+
quota: entryQuota
|
|
472
|
+
? toQuotaView(entryQuota, row, {
|
|
473
|
+
fetchedAt: entryFetchedAt,
|
|
474
|
+
lastAttemptAt: entry?.lastAttemptAt ?? null,
|
|
475
|
+
refreshError: entry?.refreshError ?? null,
|
|
476
|
+
...(isRefreshing ? { status: "refreshing" as const } : {}),
|
|
477
|
+
})
|
|
445
478
|
: null,
|
|
446
479
|
pending: isRefreshing,
|
|
447
480
|
health: toQuotaAccountHealth(row),
|
|
@@ -503,13 +536,33 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
503
536
|
health: toQuotaAccountHealth(account),
|
|
504
537
|
};
|
|
505
538
|
}
|
|
539
|
+
// Cache is cold (e.g. right after a restart): render the last persisted
|
|
540
|
+
// snapshot instead of hitting upstream on every page open. The sweep
|
|
541
|
+
// refreshes it; a page open does not need to pay the upstream cost.
|
|
542
|
+
const snapshot = await readQuotaSnapshot(db, accountId);
|
|
543
|
+
if (snapshot) {
|
|
544
|
+
return {
|
|
545
|
+
accountId,
|
|
546
|
+
quota: toQuotaView(snapshot.quota, account, {
|
|
547
|
+
fetchedAt: snapshot.fetchedAt,
|
|
548
|
+
lastAttemptAt: snapshot.fetchedAt,
|
|
549
|
+
}),
|
|
550
|
+
health: toQuotaAccountHealth(account),
|
|
551
|
+
};
|
|
552
|
+
}
|
|
506
553
|
|
|
507
554
|
// Cold read: this is the one path that legitimately waits on upstream, and
|
|
508
555
|
// it shares the in-flight fetch with any queued background fill so a cold
|
|
509
556
|
// page open never issues two requests for the same account.
|
|
510
557
|
const outcome = await refreshAccountQuota(
|
|
511
558
|
refreshDeps,
|
|
512
|
-
{
|
|
559
|
+
{
|
|
560
|
+
accountId,
|
|
561
|
+
providerId: account.providerId,
|
|
562
|
+
tenantId: account.tenantId,
|
|
563
|
+
credentialKind: account.credentialKind,
|
|
564
|
+
authState: account.authState,
|
|
565
|
+
},
|
|
513
566
|
signalFetch(timeoutSignal(request.signal, QUOTA_REFRESH_TIMEOUT_MS)),
|
|
514
567
|
);
|
|
515
568
|
const fresh = await getCachedQuotaEntry(access.tenantId, accountId, redis);
|
|
@@ -571,7 +624,16 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
571
624
|
try {
|
|
572
625
|
outcome = await refreshAccountQuota(
|
|
573
626
|
refreshDeps,
|
|
574
|
-
{
|
|
627
|
+
{
|
|
628
|
+
accountId,
|
|
629
|
+
providerId: account.providerId,
|
|
630
|
+
tenantId: account.tenantId,
|
|
631
|
+
credentialKind: account.credentialKind,
|
|
632
|
+
// Kiro's usage surface is profile-scoped: without the account's auth
|
|
633
|
+
// state the collector cannot resolve a `profileArn`, and the GET is
|
|
634
|
+
// refused with `400 Invalid profileArn.`.
|
|
635
|
+
authState: account.authState,
|
|
636
|
+
},
|
|
575
637
|
egress.fetch,
|
|
576
638
|
);
|
|
577
639
|
} finally {
|
|
@@ -616,6 +678,7 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
616
678
|
providerId: providerAccounts.providerId,
|
|
617
679
|
tenantId: providerAccounts.tenantId,
|
|
618
680
|
credentialKind: providerAccounts.credentialKind,
|
|
681
|
+
authState: providerAccounts.authState,
|
|
619
682
|
})
|
|
620
683
|
.from(providerAccounts)
|
|
621
684
|
.where(
|
|
@@ -776,17 +839,60 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
776
839
|
});
|
|
777
840
|
return { success: true };
|
|
778
841
|
})
|
|
842
|
+
.post(
|
|
843
|
+
"/accounts/batch-delete",
|
|
844
|
+
{
|
|
845
|
+
body: t.Object({
|
|
846
|
+
accountIds: t.Array(t.String()),
|
|
847
|
+
}),
|
|
848
|
+
},
|
|
849
|
+
async ({ request, body }) => {
|
|
850
|
+
const access = requireTenantScope(accessResolver(request), "dashboard:write");
|
|
851
|
+
const accountIds = [...new Set(body.accountIds)];
|
|
852
|
+
if (accountIds.length === 0) {
|
|
853
|
+
return { ok: true, deleted: [], missing: [] };
|
|
854
|
+
}
|
|
855
|
+
// One DELETE statement for the whole batch, scoped to the tenant: a
|
|
856
|
+
// global/shared account (`tenant_id IS NULL`) is never matchable, so
|
|
857
|
+
// it lands in `missing` rather than being deleted by a tenant.
|
|
858
|
+
const deleted = await db
|
|
859
|
+
.delete(providerAccounts)
|
|
860
|
+
.where(
|
|
861
|
+
and(
|
|
862
|
+
inArray(providerAccounts.id, accountIds),
|
|
863
|
+
eq(providerAccounts.tenantId, access.tenantId),
|
|
864
|
+
),
|
|
865
|
+
)
|
|
866
|
+
.returning({ id: providerAccounts.id });
|
|
867
|
+
const deletedIds = deleted.map((row) => row.id);
|
|
868
|
+
const deletedSet = new Set(deletedIds);
|
|
869
|
+
const missing = accountIds.filter((id) => !deletedSet.has(id));
|
|
870
|
+
// One credential-cache pass, one quota-cache pass, one snapshot
|
|
871
|
+
// invalidation, one audit row — never one per deleted account.
|
|
872
|
+
invalidateCredentialCaches(deletedIds);
|
|
873
|
+
await invalidateQuotaCaches(access.tenantId, deletedIds, redis);
|
|
874
|
+
await snapshotInvalidator?.invalidate();
|
|
875
|
+
await auditRecorder?.record({
|
|
876
|
+
access,
|
|
877
|
+
action: "provider_account.batch_deleted",
|
|
878
|
+
target: access.tenantId,
|
|
879
|
+
detail: { deleted: deletedIds, missing },
|
|
880
|
+
});
|
|
881
|
+
return { ok: true, deleted: deletedIds, missing };
|
|
882
|
+
},
|
|
883
|
+
)
|
|
779
884
|
/**
|
|
780
|
-
*
|
|
781
|
-
*
|
|
885
|
+
* Enqueues a background daily-growth job over a provider's accounts: the
|
|
886
|
+
* growth-activity report first, then the check-in claim — the order the
|
|
782
887
|
* sweep uses — with egress rotated per account the same way the worker
|
|
783
888
|
* does, so a batch leaves from more than one address.
|
|
784
889
|
*
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
890
|
+
* Running the whole batch in the request held it open for every account's
|
|
891
|
+
* upstream calls; the route now returns `{ jobId }` immediately and the
|
|
892
|
+
* work drains through a bounded background worker (see the job status
|
|
893
|
+
* route below). A manual trigger is the operator asserting "try now", so
|
|
894
|
+
* it bypasses the sweep's once-per-day ledger; the upstream stays
|
|
895
|
+
* idempotent either way.
|
|
790
896
|
*/
|
|
791
897
|
.post(
|
|
792
898
|
"/quota/daily-growth",
|
|
@@ -832,59 +938,66 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
832
938
|
};
|
|
833
939
|
}
|
|
834
940
|
// No size cap, for the same reason as the quota refresh: the work is
|
|
835
|
-
// already drained through a bounded worker pool
|
|
836
|
-
// protected nothing and just forced the operator
|
|
837
|
-
//
|
|
838
|
-
//
|
|
941
|
+
// already drained through a bounded worker pool behind the job, so
|
|
942
|
+
// refusing the request protected nothing and just forced the operator
|
|
943
|
+
// to batch by hand.
|
|
944
|
+
//
|
|
945
|
+
// One egress rotator for the whole job, exactly as the sweep builds it,
|
|
946
|
+
// so consecutive accounts leave from consecutive pools. The job carries
|
|
947
|
+
// the per-account run (report then claim) through the injected runner.
|
|
839
948
|
const rotator =
|
|
840
949
|
networkBindingFactory !== undefined
|
|
841
950
|
? dailyCheckinEgressForPass({ db, networkBindingFactory })
|
|
842
951
|
: undefined;
|
|
952
|
+
// One leg budget for the whole job: every upstream fetch the per-account
|
|
953
|
+
// run issues carries it on top of the helpers' own per-request timeouts.
|
|
954
|
+
const legSignal = AbortSignal.timeout(DAILY_GROWTH_LEG_TIMEOUT_MS);
|
|
955
|
+
const rotatorWithBudget =
|
|
956
|
+
rotator === undefined
|
|
957
|
+
? undefined
|
|
958
|
+
: async (accountId: string, tenantId?: string | null) => {
|
|
959
|
+
const base = await rotator(accountId, tenantId);
|
|
960
|
+
return withLegBudget(base, legSignal) as unknown as ValidatedFetch;
|
|
961
|
+
};
|
|
843
962
|
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
for (let offset = 0; offset < accounts.length; offset += DAILY_GROWTH_CONCURRENCY) {
|
|
852
|
-
const batch = accounts.slice(offset, offset + DAILY_GROWTH_CONCURRENCY);
|
|
853
|
-
const settled = await Promise.all(
|
|
854
|
-
batch.map(async (account) => {
|
|
855
|
-
const outcome = await runDailyGrowthForAccount(
|
|
856
|
-
providerId as ProviderId,
|
|
857
|
-
account,
|
|
858
|
-
refreshDeps,
|
|
859
|
-
rotator,
|
|
860
|
-
);
|
|
861
|
-
return { account, outcome };
|
|
862
|
-
}),
|
|
963
|
+
const runAccount = async (account: DailyGrowthJobAccount) => {
|
|
964
|
+
const outcome = await runDailyGrowthForAccount(
|
|
965
|
+
providerId as ProviderId,
|
|
966
|
+
account,
|
|
967
|
+
refreshDeps,
|
|
968
|
+
rotatorWithBudget,
|
|
863
969
|
);
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
accountId: account.id,
|
|
867
|
-
label: account.label || account.id,
|
|
868
|
-
report: outcome.report,
|
|
869
|
-
checkin: outcome.checkin,
|
|
870
|
-
});
|
|
970
|
+
if (!outcome.checkin.ok) {
|
|
971
|
+
return { ok: false, error: outcome.checkin.message };
|
|
871
972
|
}
|
|
872
|
-
|
|
973
|
+
return { ok: true };
|
|
974
|
+
};
|
|
873
975
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
return {
|
|
880
|
-
ok: true,
|
|
881
|
-
status: 200,
|
|
882
|
-
providerId,
|
|
883
|
-
data: results,
|
|
884
|
-
message: `${results.length} account${results.length === 1 ? "" : "s"} · report ${reportsOk}/${results.length} · check-in ${claimed}/${results.length}`,
|
|
976
|
+
const jobDeps: DailyGrowthJobDeps = {
|
|
977
|
+
db,
|
|
978
|
+
redis,
|
|
979
|
+
runAccount,
|
|
980
|
+
...(snapshotInvalidator ? { snapshotInvalidator } : {}),
|
|
885
981
|
};
|
|
982
|
+
const jobId = enqueueDailyGrowthJob({
|
|
983
|
+
deps: jobDeps,
|
|
984
|
+
tenantId: access.tenantId,
|
|
985
|
+
providerId,
|
|
986
|
+
accounts,
|
|
987
|
+
});
|
|
988
|
+
set.status = 202;
|
|
989
|
+
return { jobId, status: 202 };
|
|
886
990
|
},
|
|
887
991
|
)
|
|
992
|
+
.get("/quota/daily-growth/status/:jobId", async ({ request, params, set }) => {
|
|
993
|
+
const access = requireTenantScope(accessResolver(request), "dashboard:read");
|
|
994
|
+
const job = getDailyGrowthJob(params.jobId, access.tenantId);
|
|
995
|
+
if (job === null) {
|
|
996
|
+
set.status = 404;
|
|
997
|
+
return { error: `Job ${params.jobId} not found`, code: "not_found" };
|
|
998
|
+
}
|
|
999
|
+
return job;
|
|
1000
|
+
})
|
|
888
1001
|
.post("/accounts/:id/checkin", async ({ request, params, set }) => {
|
|
889
1002
|
const access = requireTenantScope(accessResolver(request), "dashboard:write");
|
|
890
1003
|
const rows = await db
|
|
@@ -954,6 +1067,75 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
954
1067
|
message: checkinStateMessage(result),
|
|
955
1068
|
};
|
|
956
1069
|
})
|
|
1070
|
+
// Gift grants are an explicit action, not a side effect of a quota read.
|
|
1071
|
+
.post("/accounts/:id/claim-gifts", async ({ request, params, set }) => {
|
|
1072
|
+
const access = requireTenantScope(accessResolver(request), "dashboard:write");
|
|
1073
|
+
const rows = await db
|
|
1074
|
+
.select()
|
|
1075
|
+
.from(providerAccounts)
|
|
1076
|
+
.where(
|
|
1077
|
+
and(eq(providerAccounts.id, params.id), eq(providerAccounts.tenantId, access.tenantId)),
|
|
1078
|
+
)
|
|
1079
|
+
.limit(1);
|
|
1080
|
+
const account = rows[0];
|
|
1081
|
+
if (!account) {
|
|
1082
|
+
set.status = 404;
|
|
1083
|
+
return { error: `Account ${params.id} not found`, code: "not_found" };
|
|
1084
|
+
}
|
|
1085
|
+
if (account.providerId !== ZCODE_START_PLAN_PROVIDER_ID) {
|
|
1086
|
+
set.status = 400;
|
|
1087
|
+
return {
|
|
1088
|
+
error: `Gift plans are only claimable for ${ZCODE_START_PLAN_PROVIDER_ID}`,
|
|
1089
|
+
code: "gifts_unsupported",
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
let result: ZcodeGiftResult;
|
|
1093
|
+
try {
|
|
1094
|
+
const credential = await refreshDeps.resolveCredential(account.providerId as ProviderId, account.id);
|
|
1095
|
+
const fetcher = networkBindingFactory
|
|
1096
|
+
? await dailyCheckinEgressForPass({ db, networkBindingFactory })(account.id, access.tenantId)
|
|
1097
|
+
: globalThis.fetch;
|
|
1098
|
+
result = await claimZcodeGifts({ accountId: account.id, credential, fetcher });
|
|
1099
|
+
} catch {
|
|
1100
|
+
set.status = 502;
|
|
1101
|
+
return {
|
|
1102
|
+
ok: false, status: 502,
|
|
1103
|
+
data: { id: account.id, state: "error", claimed: [], detail: "Gift claim request failed" },
|
|
1104
|
+
message: "Gift claim request failed", code: "gift_claim_failed",
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
if (result.claimed.length > 0) {
|
|
1108
|
+
// Cold readers must not resurrect the balance from before the grant.
|
|
1109
|
+
await db.update(providerAccounts).set({ quotaSnapshot: null }).where(
|
|
1110
|
+
and(eq(providerAccounts.id, account.id), eq(providerAccounts.tenantId, access.tenantId)),
|
|
1111
|
+
);
|
|
1112
|
+
await invalidateQuotaCacheForAccount(account.id, redis);
|
|
1113
|
+
await snapshotInvalidator?.invalidate();
|
|
1114
|
+
}
|
|
1115
|
+
if (result.state === "error") {
|
|
1116
|
+
set.status = 502;
|
|
1117
|
+
return {
|
|
1118
|
+
ok: false,
|
|
1119
|
+
status: 502,
|
|
1120
|
+
data: { id: account.id, ...result },
|
|
1121
|
+
message: result.detail ?? "Gift claim failed",
|
|
1122
|
+
code: "gift_claim_failed",
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
return {
|
|
1126
|
+
ok: true,
|
|
1127
|
+
status: 200,
|
|
1128
|
+
data: { id: account.id, ...result },
|
|
1129
|
+
message:
|
|
1130
|
+
result.state === "nothing"
|
|
1131
|
+
? "No gift plan to claim"
|
|
1132
|
+
: result.state === "claimed"
|
|
1133
|
+
? `Claimed ${result.claimed.join(", ")}`
|
|
1134
|
+
: result.state === "already_claimed"
|
|
1135
|
+
? "Every gift plan was claimed before"
|
|
1136
|
+
: (result.detail ?? "Claim it in the ZCode app"),
|
|
1137
|
+
};
|
|
1138
|
+
})
|
|
957
1139
|
.post("/accounts/:id/activity-report", async ({ request, params, set }) => {
|
|
958
1140
|
const access = requireTenantScope(accessResolver(request), "dashboard:write");
|
|
959
1141
|
const rows = await db
|
|
@@ -1002,6 +1184,12 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
1002
1184
|
// The growth event scores by uid, and only a JWT carries one. An
|
|
1003
1185
|
// opaque API key must fail closed here — reporting it under another
|
|
1004
1186
|
// account's uid would poison someone else's streak.
|
|
1187
|
+
// dynamic-import: B-02 lazy graph — buddy uid decoder on this buddy-only surface.
|
|
1188
|
+
// The buddy-oauth-shared graph is lazy-loaded: the uid decoder is only
|
|
1189
|
+
// needed on this buddy-only surface (B-02).
|
|
1190
|
+
const { buddyAccountUid } = await import(
|
|
1191
|
+
"../../providers/integrations/buddy/buddy-oauth-shared"
|
|
1192
|
+
);
|
|
1005
1193
|
const userId = buddyAccountUid(credential);
|
|
1006
1194
|
if (!userId) {
|
|
1007
1195
|
set.status = 400;
|
|
@@ -1068,7 +1256,12 @@ export function registerAccountQuotaTenantRoutes(
|
|
|
1068
1256
|
account.providerId as ProviderId,
|
|
1069
1257
|
account.id,
|
|
1070
1258
|
);
|
|
1071
|
-
|
|
1259
|
+
// Cached per account for a short TTL: every dialog open was hitting the
|
|
1260
|
+
// upstream live. The cache is cleared on a successful redemption, so a
|
|
1261
|
+
// consumed credit is not shown again for the rest of the TTL.
|
|
1262
|
+
const list = await getCachedResetCredits(account.providerId, account.id, () =>
|
|
1263
|
+
listAccountResetCredits(account.providerId, credential),
|
|
1264
|
+
);
|
|
1072
1265
|
return list ?? { availableCount: 0, credits: [] };
|
|
1073
1266
|
} catch (err) {
|
|
1074
1267
|
return { availableCount: 0, credits: [] };
|