cartethyia 2.7.4 → 2.7.6
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 +5 -0
- package/README.md +18 -6
- package/dist/dashboard/assets/BannedPage-B1N603cM.js +1 -0
- package/dist/dashboard/assets/BannedPage-B1N603cM.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js +1 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js +899 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js +1 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-DxjvUzSD.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-DxjvUzSD.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js +1 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-DRPavCdU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DRPavCdU.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js +56 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +1 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.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-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.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/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +1 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js +4 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-u7JPB5BX.js} +1 -1
- package/dist/dashboard/assets/formatters-u7JPB5BX.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js +1 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js +1 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js +1 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +1 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +1 -0
- package/dist/dashboard/assets/settings-BxslsErn.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-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.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 +60 -59
- 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/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -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/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -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 +794 -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 +19 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +33 -6
- package/src/config/usage.ts +27 -0
- 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 +56 -24
- 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 +43 -299
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/driver.ts +150 -247
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +176 -153
- package/src/console/cli-tools/routes.ts +7 -1
- package/src/console/cli-tools/service.ts +8 -7
- 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 +7 -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 +23 -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 +11 -13
- 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 +9 -2
- package/src/observability/event-query.ts +61 -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 +19 -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 +121 -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 +29 -2
- 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 +8 -125
- 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 +71 -4
- 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 +35 -37
- 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 +88 -28
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +22 -13
- 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 +35 -3
- 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 +70 -12
- package/src/providers/integrations/github/github-oauth.ts +184 -14
- package/src/providers/integrations/github/github.ts +134 -26
- 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 +80 -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 +94 -11
- 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 +422 -71
- 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 +51 -8
- 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 +198 -133
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- 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 +50 -19
- 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 +13 -6
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +17 -3
- 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 +70 -22
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- 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 +21 -1
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/error-lifecycle.ts +4 -0
- 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 +7 -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 +159 -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/reasoning-summary.ts +9 -14
- 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 +431 -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 +0 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.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-BayTTy01.js +0 -9
- package/dist/dashboard/assets/app-BayTTy01.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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/mutation-Rr0TIvcj.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/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.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/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- 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/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -13,12 +13,13 @@ import type { FirstBootSetupService } from "./setup-service";
|
|
|
13
13
|
import { isTrustedProxyPeer, resolveClientIdentity } from "../../security/ip-boundary";
|
|
14
14
|
import type { TrustedProxyBoundary } from "../../config/network";
|
|
15
15
|
import { readSessionCookie } from "./session-resolver";
|
|
16
|
-
|
|
16
|
+
import { asConsoleDb } from "../shared/transaction";
|
|
17
|
+
interface LoginRequest {
|
|
17
18
|
readonly username: string;
|
|
18
19
|
readonly password: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
interface LoginResponse {
|
|
22
23
|
readonly status: "success" | "failed";
|
|
23
24
|
/** Session secrets are cookie-only and are never returned in JSON. */
|
|
24
25
|
readonly session_id?: never;
|
|
@@ -47,13 +48,13 @@ export type SessionStatusResponse =
|
|
|
47
48
|
}
|
|
48
49
|
| { readonly status: "unauthenticated" };
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
interface SetupRequest {
|
|
51
52
|
readonly password: string;
|
|
52
53
|
readonly username?: string;
|
|
53
54
|
readonly display_name?: string;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
interface SetupResponse {
|
|
57
58
|
readonly status: "success" | "failed";
|
|
58
59
|
readonly message?: string;
|
|
59
60
|
}
|
|
@@ -65,7 +66,7 @@ export interface SetupResponse {
|
|
|
65
66
|
* report that instead of only "it worked".
|
|
66
67
|
*/
|
|
67
68
|
/** A backup's cover, so the wizard can show what a file holds before restoring. */
|
|
68
|
-
|
|
69
|
+
interface SetupInspectResponse extends SetupResponse {
|
|
69
70
|
readonly format?: "native" | "nine_router";
|
|
70
71
|
readonly version?: number;
|
|
71
72
|
readonly exportedAt?: string;
|
|
@@ -79,18 +80,18 @@ export interface SetupInspectResponse extends SetupResponse {
|
|
|
79
80
|
readonly warnings?: readonly { readonly table?: string; readonly column?: string; readonly reason: string }[];
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
interface SetupRestoreResponse extends SetupResponse {
|
|
83
84
|
readonly restored?: Record<string, number>;
|
|
84
85
|
readonly warnings?: readonly { readonly table?: string; readonly column?: string; readonly reason: string }[];
|
|
85
86
|
/** The administrator this install was given, since the file carries none. */
|
|
86
87
|
readonly createdAdmin?: boolean;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
interface LogoutResponse {
|
|
90
91
|
readonly status: "success";
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
interface ChangePasswordResponse {
|
|
94
95
|
readonly status: "success" | "failed";
|
|
95
96
|
readonly message?: string;
|
|
96
97
|
}
|
|
@@ -183,6 +184,31 @@ async function lockedOutMessage(
|
|
|
183
184
|
};
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Records one failed login and answers with the 429/401 result, including the
|
|
189
|
+
* `retry-after` header when the failure took the lock. Shared by the unknown /
|
|
190
|
+
* inactive-user and wrong-password branches, which differ only in the audit
|
|
191
|
+
* reason string.
|
|
192
|
+
*/
|
|
193
|
+
async function rejectLogin(
|
|
194
|
+
lockoutService: ConsoleLockoutService,
|
|
195
|
+
lockoutKey: string,
|
|
196
|
+
reason: string,
|
|
197
|
+
set: { status?: number | string; headers: Record<string, string | number | string[]> },
|
|
198
|
+
): Promise<LoginResponse> {
|
|
199
|
+
const isBanned = await lockoutService.recordFailure(lockoutKey, reason);
|
|
200
|
+
if (isBanned) {
|
|
201
|
+
set.status = 429;
|
|
202
|
+
set.headers["retry-after"] = String(await lockoutService.remainingLockSeconds(lockoutKey));
|
|
203
|
+
return lockedOutMessage(lockoutService, lockoutKey);
|
|
204
|
+
}
|
|
205
|
+
set.status = 401;
|
|
206
|
+
return {
|
|
207
|
+
status: "failed",
|
|
208
|
+
message: await failedLoginMessage(lockoutService, lockoutKey),
|
|
209
|
+
} satisfies LoginResponse;
|
|
210
|
+
}
|
|
211
|
+
|
|
186
212
|
function parseLoginRequest(body: unknown): LoginRequest | undefined {
|
|
187
213
|
if (!isRecord(body) || typeof body.password !== "string") {
|
|
188
214
|
return undefined;
|
|
@@ -266,32 +292,12 @@ export function createConsoleAuthRoutes(
|
|
|
266
292
|
const rows = await readUsers(database, input.username);
|
|
267
293
|
const user = userRecord(rows[0]);
|
|
268
294
|
if (!user || !user.isActive) {
|
|
269
|
-
|
|
270
|
-
if (isBanned) {
|
|
271
|
-
set.status = 429;
|
|
272
|
-
set.headers["retry-after"] = String(await lockoutService.remainingLockSeconds(lockoutKey));
|
|
273
|
-
return lockedOutMessage(lockoutService, lockoutKey);
|
|
274
|
-
}
|
|
275
|
-
set.status = 401;
|
|
276
|
-
return {
|
|
277
|
-
status: "failed",
|
|
278
|
-
message: await failedLoginMessage(lockoutService, lockoutKey),
|
|
279
|
-
} satisfies LoginResponse;
|
|
295
|
+
return rejectLogin(lockoutService, lockoutKey, "unknown_user", set);
|
|
280
296
|
}
|
|
281
297
|
|
|
282
298
|
const valid = await credentialService.verifyPassword(input.password, user.passwordHash);
|
|
283
299
|
if (!valid) {
|
|
284
|
-
|
|
285
|
-
if (isBanned) {
|
|
286
|
-
set.status = 429;
|
|
287
|
-
set.headers["retry-after"] = String(await lockoutService.remainingLockSeconds(lockoutKey));
|
|
288
|
-
return lockedOutMessage(lockoutService, lockoutKey);
|
|
289
|
-
}
|
|
290
|
-
set.status = 401;
|
|
291
|
-
return {
|
|
292
|
-
status: "failed",
|
|
293
|
-
message: await failedLoginMessage(lockoutService, lockoutKey),
|
|
294
|
-
} satisfies LoginResponse;
|
|
300
|
+
return rejectLogin(lockoutService, lockoutKey, "invalid_password", set);
|
|
295
301
|
}
|
|
296
302
|
|
|
297
303
|
await lockoutService.clearFailures(lockoutKey);
|
|
@@ -526,7 +532,7 @@ export function createConsoleAuthRoutes(
|
|
|
526
532
|
});
|
|
527
533
|
return invalidated;
|
|
528
534
|
};
|
|
529
|
-
await database.transaction((tx) => rotateInScope(tx
|
|
535
|
+
await database.transaction((tx) => rotateInScope(asConsoleDb(tx)));
|
|
530
536
|
set.status = 200;
|
|
531
537
|
return { status: "success" } satisfies ChangePasswordResponse;
|
|
532
538
|
},
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import { resolveDefaultGatewayApiKey } from "../../config/runtime";
|
|
21
21
|
import { TENANT_KEY_SCOPES } from "../../security/access-control";
|
|
22
22
|
import { isRecord } from "../../protocol/codecs";
|
|
23
|
+
import { asConsoleDb } from "../shared/transaction";
|
|
23
24
|
import { BackupService } from "../backup/service";
|
|
24
25
|
import type { BackupInspection } from "../backup/service";
|
|
25
26
|
import type { RestoreWarning } from "../backup/contracts";
|
|
@@ -28,14 +29,14 @@ import type { RestoreWarning } from "../backup/contracts";
|
|
|
28
29
|
// and the mode is read from the environment the process was started with.
|
|
29
30
|
|
|
30
31
|
/** The administrator to create when a restored backup left none to sign in with. */
|
|
31
|
-
|
|
32
|
+
interface AdminBootstrap {
|
|
32
33
|
readonly password: string;
|
|
33
34
|
readonly username?: string;
|
|
34
35
|
readonly displayName?: string;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/** What a first-boot restore did, so the console can report it honestly. */
|
|
38
|
-
|
|
39
|
+
interface RestoreBackupOutcome {
|
|
39
40
|
readonly restored: Record<string, number>;
|
|
40
41
|
readonly skipped: Record<string, number>;
|
|
41
42
|
/** Parts of the file that could not be restored. */
|
|
@@ -171,7 +172,7 @@ export class FirstBootSetupService {
|
|
|
171
172
|
// unserialized lets two boots both pass the check.
|
|
172
173
|
await this.db.transaction(async (transaction) => {
|
|
173
174
|
await transaction.execute(firstBootSetupLock());
|
|
174
|
-
await create(transaction
|
|
175
|
+
await create(asConsoleDb(transaction));
|
|
175
176
|
});
|
|
176
177
|
}
|
|
177
178
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
|
|
7
7
|
import type { CartethyiaDatabase } from "../../persistence/db-handle";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
class ConsoleUserStore {
|
|
10
10
|
constructor(private readonly db: CartethyiaDatabase) {}
|
|
11
11
|
|
|
12
12
|
async findByUsername(username: string): Promise<unknown | undefined> {
|
|
@@ -106,9 +106,6 @@ export const PROXY_KINDS: Readonly<Record<string, "http" | "https" | "socks5">>
|
|
|
106
106
|
workers: "https",
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
-
/** Proxy types we recognize but cannot represent, with the reason. */
|
|
110
|
-
export const REFUSED_PROXY_KINDS: Readonly<Record<string, string>> = {};
|
|
111
|
-
|
|
112
109
|
/**
|
|
113
110
|
* Router combo strategy → ours.
|
|
114
111
|
*
|
|
@@ -170,9 +170,15 @@ const SEALED_COLUMNS: Readonly<Record<string, Readonly<Record<string, string>>>>
|
|
|
170
170
|
share_links: { token_encrypted: "share_token" },
|
|
171
171
|
};
|
|
172
172
|
|
|
173
|
+
const SEALED_COLUMNS_CACHE = new WeakMap<Table, ReadonlySet<string>>();
|
|
174
|
+
|
|
173
175
|
/** The sealed columns of `table`, by column name. */
|
|
174
176
|
export function sealedColumns(table: Table): ReadonlySet<string> {
|
|
175
|
-
|
|
177
|
+
const cached = SEALED_COLUMNS_CACHE.get(table);
|
|
178
|
+
if (cached) return cached;
|
|
179
|
+
const names = new Set(Object.keys(SEALED_COLUMNS[getTableName(table)] ?? {}));
|
|
180
|
+
SEALED_COLUMNS_CACHE.set(table, names);
|
|
181
|
+
return names;
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
/**
|
|
@@ -205,7 +211,6 @@ export function sealedAliases(table: Table): ReadonlyMap<string, string> {
|
|
|
205
211
|
return out;
|
|
206
212
|
}
|
|
207
213
|
|
|
208
|
-
|
|
209
214
|
/**
|
|
210
215
|
* Which rows of a table belong to one tenant, and how a restore replaces them.
|
|
211
216
|
*
|
|
@@ -236,7 +241,7 @@ export function sealedAliases(table: Table): ReadonlyMap<string, string> {
|
|
|
236
241
|
* - `self` — the tenant row itself, matched on its own id, upserted and never
|
|
237
242
|
* deleted.
|
|
238
243
|
*/
|
|
239
|
-
|
|
244
|
+
type TableOwnership =
|
|
240
245
|
| { readonly kind: "direct"; readonly column: Column; readonly replace: "delete" | "upsert" }
|
|
241
246
|
| {
|
|
242
247
|
readonly kind: "viaParent";
|
|
@@ -493,7 +498,7 @@ export function findTable(section: BackupSection, name: string): Table | undefin
|
|
|
493
498
|
return tablesForSection(section).find((table) => tableName(table) === name);
|
|
494
499
|
}
|
|
495
500
|
|
|
496
|
-
export interface
|
|
501
|
+
export interface BackupPayloadExport {
|
|
497
502
|
readonly payload: BackupPayload;
|
|
498
503
|
readonly counts: Record<string, number>;
|
|
499
504
|
}
|
|
@@ -511,11 +516,6 @@ export interface ValidatedTable {
|
|
|
511
516
|
readonly rows: readonly BackupRow[];
|
|
512
517
|
}
|
|
513
518
|
|
|
514
|
-
export interface RestoreResult {
|
|
515
|
-
readonly restored: Record<string, number>;
|
|
516
|
-
readonly skipped: Record<string, number>;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
519
|
/**
|
|
520
520
|
* One part of a backup that could not be restored, and why.
|
|
521
521
|
*
|
|
@@ -23,11 +23,11 @@ import { homedir } from "node:os";
|
|
|
23
23
|
import { join } from "node:path";
|
|
24
24
|
import { GatewayError } from "../../protocol/gateway-error";
|
|
25
25
|
import { isLoopbackPeer, tokenMatches } from "../../transport/drain-endpoint";
|
|
26
|
-
import {
|
|
26
|
+
import { tablesForSection } from "./contracts";
|
|
27
27
|
import { compressBackupStream, exportBackupStream } from "./store";
|
|
28
28
|
import type { CartethyiaDatabase } from "../../persistence/db-handle";
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
interface BackupExportDeps {
|
|
31
31
|
readonly db: CartethyiaDatabase;
|
|
32
32
|
/** Shared secret; the route is registered only when this is set. */
|
|
33
33
|
readonly token: string;
|
|
@@ -37,7 +37,8 @@ export interface BackupExportDeps {
|
|
|
37
37
|
readonly resolvePeerAddress: (request: Request) => string | null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export
|
|
40
|
+
/** The file-write result of an operator export, distinct from the payload shape `BackupPayloadExport` in `contracts.ts`. */
|
|
41
|
+
export interface BackupExportFileResult {
|
|
41
42
|
readonly path: string;
|
|
42
43
|
readonly bytes: number;
|
|
43
44
|
readonly counts: Record<string, number>;
|
|
@@ -89,7 +90,7 @@ export function createBackupExportHandler(
|
|
|
89
90
|
);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
const result:
|
|
93
|
+
const result: BackupExportFileResult = { path, bytes: gzipped.byteLength, counts };
|
|
93
94
|
return new Response(JSON.stringify(result), {
|
|
94
95
|
status: 200,
|
|
95
96
|
headers: { "content-type": "application/json", "cache-control": "no-store" },
|
|
@@ -108,5 +109,3 @@ function downloadDirectory(): string {
|
|
|
108
109
|
: join(process.env.XDG_DOWNLOAD_DIR ?? join(home, "Downloads"));
|
|
109
110
|
return candidate;
|
|
110
111
|
}
|
|
111
|
-
|
|
112
|
-
export { BACKUP_SECTIONS };
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
isNodeProviderId,
|
|
30
30
|
NODE_WIRE_FAMILIES,
|
|
31
31
|
PROXY_KINDS,
|
|
32
|
-
REFUSED_PROXY_KINDS,
|
|
33
32
|
UNSUPPORTED_PROVIDERS,
|
|
34
33
|
UPSTREAM_PROVIDERS,
|
|
35
34
|
} from "./9router-map";
|
|
@@ -50,7 +49,7 @@ export interface ImportReport {
|
|
|
50
49
|
readonly remapped: readonly string[];
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
interface ConversionResult {
|
|
54
53
|
readonly payload: BackupPayload;
|
|
55
54
|
readonly report: ImportReport;
|
|
56
55
|
}
|
|
@@ -479,11 +478,6 @@ export function convert9RouterBackup(input: unknown, tenantId: string): Conversi
|
|
|
479
478
|
return;
|
|
480
479
|
}
|
|
481
480
|
const rawKind = text(entry.type) ?? "http";
|
|
482
|
-
const refused = REFUSED_PROXY_KINDS[rawKind];
|
|
483
|
-
if (refused !== undefined) {
|
|
484
|
-
skipped.push(`proxy pool "${label}": type "${rawKind}" (${refused})`);
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
481
|
const kind = PROXY_KINDS[rawKind];
|
|
488
482
|
if (kind === undefined) {
|
|
489
483
|
skipped.push(`proxy pool "${label}": unknown type "${rawKind}"`);
|
|
@@ -26,7 +26,7 @@ import { DELETE_ALL_SCOPES, compressBackupStream } from "./store";
|
|
|
26
26
|
import type { BackupService } from "./service";
|
|
27
27
|
import type { AuditRecorder } from "../auth/audit-recorder";
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
interface BackupRoutesConfig {
|
|
30
30
|
readonly accessResolver: ConsoleAccessResolver;
|
|
31
31
|
/**
|
|
32
32
|
* Builds the service for one request. A factory rather than an instance
|
|
@@ -118,6 +118,30 @@ function parseSections(raw: string | undefined): readonly BackupSection[] | unde
|
|
|
118
118
|
.filter((part) => part.length > 0) as readonly BackupSection[];
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Enforces the byte bound against actual received bytes, not just the declared
|
|
123
|
+
* header: a missing or spoofed content-length would otherwise bypass the 413
|
|
124
|
+
* and buffer an unbounded file into JSON.parse. Elysia has already parsed the
|
|
125
|
+
* body here, so measure the re-serialized form — an over-limit file still
|
|
126
|
+
* fails closed before any restore/inspection touches the DB. Returns the 413
|
|
127
|
+
* response when over the limit, or `null` when the body is accepted.
|
|
128
|
+
*/
|
|
129
|
+
function enforceBodyLimit(request: Request, body: unknown, set: { status?: number | string }): { error: string; code: string } | null {
|
|
130
|
+
const declared = Number(request.headers.get("content-length") ?? "0");
|
|
131
|
+
const actualBytes = JSON.stringify(body ?? null).length;
|
|
132
|
+
if (
|
|
133
|
+
(Number.isFinite(declared) && declared > MAX_BACKUP_BYTES) ||
|
|
134
|
+
actualBytes > MAX_BACKUP_BYTES
|
|
135
|
+
) {
|
|
136
|
+
set.status = 413;
|
|
137
|
+
return {
|
|
138
|
+
error: `backup exceeds the ${MAX_BACKUP_BYTES} byte limit`,
|
|
139
|
+
code: "request_too_large",
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
121
145
|
/**
|
|
122
146
|
* Streams the export document into the response body as it is written; one
|
|
123
147
|
* row-page of the tenant's data is in memory at a time.
|
|
@@ -194,23 +218,8 @@ export function createBackupRoutes(config: BackupRoutesConfig): AnyElysia {
|
|
|
194
218
|
if (access.tenantId === null) {
|
|
195
219
|
throw new ConsoleDomainError("tenant_required", 403, "Tenant isolation required");
|
|
196
220
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// and buffer an unbounded file into JSON.parse. Elysia has already
|
|
200
|
-
// parsed the body here, so measure the re-serialized form — an
|
|
201
|
-
// over-limit file still fails closed before restore touches the DB.
|
|
202
|
-
const declared = Number(request.headers.get("content-length") ?? "0");
|
|
203
|
-
const actualBytes = JSON.stringify(body ?? null).length;
|
|
204
|
-
if (
|
|
205
|
-
(Number.isFinite(declared) && declared > MAX_BACKUP_BYTES) ||
|
|
206
|
-
actualBytes > MAX_BACKUP_BYTES
|
|
207
|
-
) {
|
|
208
|
-
set.status = 413;
|
|
209
|
-
return {
|
|
210
|
-
error: `backup exceeds the ${MAX_BACKUP_BYTES} byte limit`,
|
|
211
|
-
code: "request_too_large",
|
|
212
|
-
};
|
|
213
|
-
}
|
|
221
|
+
const tooLarge = enforceBodyLimit(request, body, set);
|
|
222
|
+
if (tooLarge !== null) return tooLarge;
|
|
214
223
|
// The restoring tenant comes from the caller's own access decision and
|
|
215
224
|
// from nowhere else. A request body may not name the tenant it writes
|
|
216
225
|
// into: that would let any holder of the scope import into, and
|
|
@@ -283,21 +292,8 @@ export function createBackupRoutes(config: BackupRoutesConfig): AnyElysia {
|
|
|
283
292
|
if (access.tenantId === null) {
|
|
284
293
|
throw new ConsoleDomainError("tenant_required", 403, "Tenant isolation required");
|
|
285
294
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
// validation could refuse it.
|
|
289
|
-
const declared = Number(request.headers.get("content-length") ?? "0");
|
|
290
|
-
const actualBytes = JSON.stringify(body ?? null).length;
|
|
291
|
-
if (
|
|
292
|
-
(Number.isFinite(declared) && declared > MAX_BACKUP_BYTES) ||
|
|
293
|
-
actualBytes > MAX_BACKUP_BYTES
|
|
294
|
-
) {
|
|
295
|
-
set.status = 413;
|
|
296
|
-
return {
|
|
297
|
-
error: `backup exceeds the ${MAX_BACKUP_BYTES} byte limit`,
|
|
298
|
-
code: "request_too_large",
|
|
299
|
-
};
|
|
300
|
-
}
|
|
295
|
+
const tooLarge = enforceBodyLimit(request, body, set);
|
|
296
|
+
if (tooLarge !== null) return tooLarge;
|
|
301
297
|
// Reads nothing and writes nothing: the checklist the restore wizard
|
|
302
298
|
// shows, so an operator can pick sections before typing a password.
|
|
303
299
|
return config.backupFor(request).inspect(body.backup);
|