cartethyia 2.5.4 → 2.5.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 +13 -4
- package/README.md +2 -2
- package/dist/dashboard/assets/{BannedPage-C2orBsI2.js → BannedPage-CADDq4IU.js} +1 -1
- package/dist/dashboard/assets/BannedPage-CADDq4IU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js +1 -0
- package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-DuO1Z7dq.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DuO1Z7dq.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DNEPi3xU.js +1 -0
- package/dist/dashboard/assets/CombosPage-DNEPi3xU.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-BVdpfiz1.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-BVdpfiz1.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-BR5HHvbi.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-BR5HHvbi.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-mUfcknqm.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-V5faV9V2.js} +1 -1
- package/dist/dashboard/assets/LoginPage-V5faV9V2.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C7pDb41R.js +1 -0
- package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-uPiGVTTK.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js +7 -0
- package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js +1 -0
- package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-UB690SE2.js} +1 -1
- package/dist/dashboard/assets/SetupPage-UB690SE2.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-BLujdX7N.js} +1 -1
- package/dist/dashboard/assets/SortableList-BLujdX7N.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-D5C2raAc.js} +3 -3
- package/dist/dashboard/assets/StudioPage-D5C2raAc.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-8uIcxa1W.js +56 -0
- package/dist/dashboard/assets/UsagePage-8uIcxa1W.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js +1 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css +2 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
- package/dist/dashboard/assets/{assert-Chi7pCnt.js → assert-C9FD_JwJ.js} +1 -1
- package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D4pQapKj.js → badge-CR72dasT.js} +1 -1
- package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DH6cg-_B.js → banner-CI9_eSfO.js} +1 -1
- package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
- package/dist/dashboard/assets/{card-BKqlUOe4.js → card-DS7CQEsO.js} +1 -1
- package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-fTgljTGA.js → cli-tools-CNqzrfdb.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-D5Ys_sM0.js → clipboard-button-611pSsaX.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
- package/dist/dashboard/assets/{fingerprint-pattern-BWuHtbW4.js → concurrency-BDF0ok7y.js} +1 -1
- package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
- package/dist/dashboard/assets/dialog-k37exjNt.js +1 -0
- package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CX7N8ucR.js +1 -0
- package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CQBr6U9c.js → entry-B9Xvtnfj.js} +1 -1
- package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
- package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
- package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
- package/dist/dashboard/assets/entry-DxBHnauy.js +4 -0
- package/dist/dashboard/assets/entry-DxBHnauy.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-BlptL8Uf.js → github-badge-sltk1qUi.js} +1 -1
- package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
- package/dist/dashboard/assets/{index-js6TJvdr.js → index-CmxZr14F.js} +2 -2
- package/dist/dashboard/assets/index-CmxZr14F.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DUWDSmDV.js → inline-BhY2sSnO.js} +1 -1
- package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
- package/dist/dashboard/assets/{input-LVjgZq4f.js → input-V1umFiBk.js} +1 -1
- package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
- package/dist/dashboard/assets/layout-BBOYycyS.js +1 -0
- package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DupvLfDx.js → list-row-1zzZYM0B.js} +1 -1
- package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
- package/dist/dashboard/assets/{live-C4pEJUqI.js → live-BivGfuUs.js} +1 -1
- package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-BRiuufkB.js → model-bans-CmffjLuG.js} +1 -1
- package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-B4ROwk8L.js → mutation-46P0oWMe.js} +1 -1
- package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
- package/dist/dashboard/assets/numbers-DkfMR5Qs.js +2 -0
- package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-gmjzC3RS.js → query-keys-BFhGpwR1.js} +1 -1
- package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
- package/dist/dashboard/assets/{routing-C7tBT5o-.js → routing-CAb4F37R.js} +1 -1
- package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
- package/dist/dashboard/assets/{select-WUCXorXw.js → select-BYR_5K2c.js} +1 -1
- package/dist/dashboard/assets/select-BYR_5K2c.js.gz +0 -0
- package/dist/dashboard/assets/{settings-C_zKl1GS.js → settings-DNX9sydi.js} +1 -1
- package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
- package/dist/dashboard/assets/{stack-_3O0F8Xn.js → stack-BHTfXdz_.js} +1 -1
- package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
- package/dist/dashboard/assets/{state-BgTxHcJS.js → state-mPDRlQkl.js} +1 -1
- package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DEjTtOWf.js → switch-DOmJxg7H.js} +1 -1
- package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
- package/dist/dashboard/assets/tokens-COzario9.js +1 -0
- package/dist/dashboard/assets/tokens-COzario9.js.gz +0 -0
- package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js +1 -0
- package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BWSC0UAS.js → useMutation-Dem0lXQj.js} +1 -1
- package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -54
- package/migrations/README.md +52 -52
- package/migrations/lite-sqlite3/0000_baseline.sql +2 -2
- package/package.json +96 -95
- package/scripts/cli/admin.ts +125 -0
- package/scripts/cli/{ui/background.ts → background.ts} +1 -1
- package/scripts/cli/{command/console-menu.ts → console-menu.ts} +275 -244
- package/scripts/cli/doctor.ts +37 -0
- package/scripts/cli/{support/env.ts → env.ts} +99 -99
- package/scripts/cli/{gateway/spawn.ts → gateway.ts} +112 -24
- package/scripts/cli/instance.ts +224 -0
- package/scripts/cli/main.ts +61 -18
- package/scripts/cli/{support/platform.ts → platform.ts} +64 -64
- package/scripts/cli/port.ts +100 -0
- package/scripts/cli/{support/services.ts → services.ts} +88 -88
- package/scripts/cli/{command/setup.ts → setup.ts} +35 -34
- package/scripts/cli/{command/start.ts → start.ts} +10 -5
- package/scripts/cli/{support/startup-signal.ts → startup-signal.ts} +23 -23
- package/scripts/cli/tray/index.ts +62 -12
- package/scripts/cli/{command/tray.ts → tray.ts} +208 -208
- package/scripts/cli/{command/update.ts → update.ts} +39 -39
- package/scripts/cli/version.ts +67 -0
- package/scripts/cli/{ui/wordmark.ts → wordmark.ts} +58 -58
- package/src/boot/app.ts +697 -693
- package/src/boot/dependencies.ts +647 -646
- package/src/boot/timeout.ts +2 -13
- package/src/config/cooldowns.ts +186 -138
- package/src/config/network.ts +8 -14
- package/src/config/providers.ts +7 -10
- package/src/config/runtime.ts +76 -76
- package/src/config/security.ts +15 -0
- package/src/config/spec.ts +20 -30
- package/src/config/telemetry.ts +0 -20
- package/src/config/timeouts.ts +0 -6
- package/src/console/admin/model-abuse/contracts.ts +28 -6
- package/src/console/admin/model-abuse/routes.ts +56 -3
- package/src/console/api-keys/contracts.ts +410 -414
- package/src/console/api-keys/routes.ts +881 -880
- package/src/console/auth/credentials.ts +3 -3
- package/src/console/auth/setup-service.ts +2 -2
- package/src/console/backup/export-endpoint.ts +6 -2
- package/src/console/backup/nine-router.ts +2 -5
- package/src/console/backup/service.ts +4 -0
- package/src/console/backup/store.ts +192 -29
- package/src/console/backup/validate.ts +3 -45
- package/src/console/cli-tools/fs-ops.ts +487 -487
- package/src/console/console-router-guards.ts +1 -1
- package/src/console/data-management/contracts.ts +13 -6
- package/src/console/data-management/operations.ts +23 -18
- package/src/console/data-management/routes.ts +0 -1
- package/src/console/domain-registration.ts +10 -5
- package/src/console/observability/live.ts +22 -0
- package/src/console/observability/store.ts +39 -16
- package/src/console/observability/usage-dimensions.ts +4 -4
- package/src/console/providers/catalog/catalog-projections.ts +6 -7
- package/src/console/providers/catalog/model-operations.ts +5 -2
- package/src/console/providers/catalog/provider-operations.ts +4 -4
- package/src/console/providers/catalog/public-model-store.ts +8 -11
- package/src/console/providers/catalog/store.ts +1553 -1553
- package/src/console/providers/oauth/routes.ts +8 -12
- package/src/console/quota/account-quota-tenant.ts +6 -6
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/contracts.ts +61 -0
- package/src/console/remote-support/routes.ts +65 -0
- package/src/console/remote-support/service.ts +207 -0
- package/src/console/response-compression.ts +0 -3
- package/src/console/routing/pools/probe-result.ts +3 -2
- package/src/console/routing/pools/probe-verdict.ts +132 -132
- package/src/console/routing/pools/store.ts +8 -8
- package/src/console/settings/contracts.ts +58 -2
- package/src/console/settings/store.ts +30 -3
- package/src/console/shared/cursor.ts +8 -8
- package/src/console/shared/errors.ts +1 -3
- package/src/network/http2-bidi.ts +2 -4
- package/src/network/pool/agent.ts +478 -478
- package/src/network/pool/selector.ts +5 -4
- package/src/network/retry.ts +1 -2
- package/src/network/ssrf.ts +5 -4
- package/src/observability/event-compaction.ts +80 -78
- package/src/observability/event-day-index.ts +13 -15
- package/src/observability/event-log.ts +4 -4
- package/src/observability/logger.ts +6 -6
- package/src/observability/payload-capture.ts +151 -33
- package/src/observability/payload-store.ts +397 -440
- package/src/observability/redaction.ts +5 -6
- package/src/observability/request-notify.ts +43 -0
- package/src/observability/telemetry-status.ts +8 -9
- package/src/observability/token-speed.ts +5 -4
- package/src/persistence/db-mode.ts +7 -7
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/schema.ts +1406 -1402
- package/src/persistence/shared-cache.ts +1 -2
- package/src/persistence/stores/api-key-store.ts +18 -6
- package/src/persistence/stores/share-store.ts +4 -3
- package/src/persistence/stores/telemetry-store.ts +236 -237
- package/src/protocol/canonical-model.ts +11 -3
- package/src/protocol/codecs.ts +138 -4
- package/src/protocol/gateway-error.ts +6 -4
- package/src/protocol/request/chat.ts +21 -1
- package/src/protocol/request/codex.ts +10 -1
- package/src/protocol/request/messages.ts +4 -5
- package/src/protocol/request/responses.ts +9 -1
- package/src/protocol/response/chat.ts +34 -4
- package/src/protocol/response/codex.ts +7 -4
- package/src/protocol/response/dsml.ts +140 -28
- package/src/protocol/response/responses.ts +11 -5
- package/src/protocol/stream-error-frames.ts +4 -5
- package/src/providers/authentication/jwt-validator.ts +9 -10
- package/src/providers/authentication/oauth-refresh-service.ts +9 -11
- package/src/providers/configured-openai-providers.ts +134 -136
- package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
- package/src/providers/discovery/catalog/catalog-format.ts +3 -6
- package/src/providers/discovery/models-dev-catalog.ts +354 -354
- package/src/providers/discovery/probe-phases.ts +4 -4
- package/src/providers/discovery/probe-wire.ts +6 -13
- package/src/providers/discovery/probing-service.ts +1117 -1045
- package/src/providers/integrations/alibabacp/alibabacp.ts +1 -1
- package/src/providers/integrations/antigravity/antigravity-quota.ts +5 -7
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +23 -2
- package/src/providers/integrations/buddy/buddy-checkin.ts +1 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +23 -6
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -1
- package/src/providers/integrations/buddy/buddy-identity.ts +52 -0
- package/src/providers/integrations/buddy/buddy-media.ts +2 -2
- package/src/providers/integrations/buddy/buddy-usage-store.ts +3 -4
- package/src/providers/integrations/buddy/codebuddy/quota.ts +2 -13
- package/src/providers/integrations/buddy/codebuddy/shared.ts +118 -115
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -11
- package/src/providers/integrations/buddy/workbuddy/shared.ts +5 -2
- package/src/providers/integrations/claude/claude.ts +608 -608
- package/src/providers/integrations/cline/cline-quota.ts +132 -132
- package/src/providers/integrations/cline/cline.ts +537 -539
- package/src/providers/integrations/codex/codex-oauth.ts +1 -1
- package/src/providers/integrations/commandcode/commandcode.ts +674 -675
- package/src/providers/integrations/commandcode/discovery.ts +117 -116
- package/src/providers/integrations/cursor/cursor-auth.ts +418 -418
- package/src/providers/integrations/cursor/cursor-quota.ts +309 -310
- package/src/providers/integrations/cursor/cursor.ts +11 -163
- package/src/providers/integrations/factory/factory-models.ts +3 -5
- package/src/providers/integrations/grok/grok-install-id.ts +2 -3
- package/src/providers/integrations/grok/grok.ts +6 -7
- package/src/providers/integrations/hermes.ts +14 -18
- package/src/providers/integrations/kiro/kiro-discovery.ts +1 -1
- package/src/providers/integrations/kiro/kiro.ts +1 -1
- package/src/providers/integrations/mistral.ts +6 -6
- package/src/providers/integrations/opencode/fingerprint.ts +3 -3
- package/src/providers/integrations/opencode/provider.ts +8 -8
- package/src/providers/integrations/qoder/qoder-catalog.ts +450 -450
- package/src/providers/integrations/qoder/qoder-oauth.ts +388 -310
- package/src/providers/integrations/qoder/qoder.ts +884 -865
- package/src/providers/integrations/shared/connect.ts +6 -6
- package/src/providers/integrations/trae/trae-catalog.ts +1 -2
- package/src/providers/integrations/trae/trae.ts +2 -2
- package/src/providers/integrations/zcode/oauth.ts +6 -1
- package/src/providers/operations/account-health-service.ts +1528 -1523
- package/src/providers/operations/account-reset-service.ts +1 -1
- package/src/providers/operations/client-versions.ts +6 -6
- package/src/providers/operations/custom-cli-headers.ts +3 -4
- package/src/providers/operations/provider-catalog-seeder.ts +95 -95
- package/src/providers/operations/provider-catalog-service.ts +3 -4
- package/src/providers/provider-metadata.ts +4 -8
- package/src/providers/provider-registry.ts +6 -7
- package/src/providers/provider-usage.ts +1 -1
- package/src/security/abuse.ts +15 -10
- package/src/security/access-control.ts +144 -146
- package/src/security/admission/contracts.ts +11 -0
- package/src/security/admission/in-memory-store.ts +4 -3
- package/src/security/admission/lease-sweep.ts +6 -6
- package/src/security/admission/reasons.ts +5 -1
- package/src/security/admission/redis-store.ts +211 -210
- package/src/security/admission/service.ts +4 -0
- package/src/security/api-key-auth.ts +504 -504
- package/src/security/ip-boundary.ts +155 -15
- package/src/security/model-abuse.ts +366 -94
- package/src/security/outbound-headers.ts +3 -4
- package/src/shared/sleep.ts +4 -0
- package/src/transport/dispatch/attempt-finalize.ts +47 -5
- package/src/transport/dispatch/attempt-loop.ts +531 -530
- package/src/transport/dispatch/stream-bridge.ts +1 -3
- package/src/transport/dispatch/streaming/finalize.ts +1 -1
- package/src/transport/dispatch/streaming/stream.ts +5 -6
- package/src/transport/failure-policy.ts +162 -8
- package/src/transport/guards/auth-guard.ts +7 -4
- package/src/transport/guards/concurrency-guard.ts +0 -5
- package/src/transport/guards/error-lifecycle.ts +13 -6
- package/src/transport/guards/pipeline.ts +15 -3
- package/src/transport/guards/request-context.ts +8 -2
- package/src/transport/request/inflight.ts +5 -6
- package/src/transport/request/preparer.ts +2 -2
- package/src/transport/request/state.ts +12 -8
- package/src/transport/routing/admission.ts +4 -0
- package/src/transport/routing/route-catalog.ts +8 -1
- package/src/transport/routing/route-model.ts +46 -14
- package/src/transport/routing/router.ts +21 -14
- package/src/transport/surface/completion.ts +2 -3
- package/src/transport/surface/dialects.ts +5 -6
- package/src/transport/surface/responses/encode.ts +38 -0
- package/src/transport/surface/responses/parse.ts +4 -0
- package/src/transport/translation/capabilities.ts +2 -3
- package/src/transport/translation/quirks.ts +3 -3
- package/src/workers/buddy-growth-tasks.ts +5 -10
- package/src/workers/daily-checkin.ts +17 -23
- package/src/workers/quota-refresh-sweep.ts +26 -26
- package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-Bsan4679.js +0 -1
- package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js +0 -1
- package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +0 -1
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +0 -7
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +0 -1
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Cnae9SWA.js +0 -56
- package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-VY68Mhd1.js +0 -1
- package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
- package/dist/dashboard/assets/app-COlK95oi.css +0 -2
- package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
- package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
- package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
- package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
- package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BYj-8WuK.js +0 -1
- package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CmXIZ6H1.js +0 -1
- package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js +0 -1
- package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js +0 -4
- package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
- package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
- package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
- package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
- package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
- package/dist/dashboard/assets/layout-CPfxpsfy.js +0 -1
- package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
- package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
- package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
- package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js +0 -2
- package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-gmjzC3RS.js.gz +0 -0
- package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
- package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
- package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
- package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
- package/dist/dashboard/assets/tokens-DDxMbSRL.js +0 -1
- package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
- package/dist/dashboard/assets/use-presence-BSZEBx7U.js +0 -1
- package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
- package/scripts/cli/command/admin.ts +0 -65
- package/scripts/cli/command/doctor.ts +0 -257
- package/scripts/cli/gateway/drain-token.ts +0 -78
- package/scripts/cli/gateway/instance-lock.ts +0 -105
- package/scripts/cli/gateway/stop.ts +0 -51
- package/scripts/cli/support/bun.ts +0 -27
- package/scripts/cli/support/version.ts +0 -37
- /package/dist/dashboard/assets/{app-DCQZRmHY.js → app-BIt446yE.js} +0 -0
- /package/dist/dashboard/assets/{app-DCQZRmHY.js.gz → app-BIt446yE.js.gz} +0 -0
- /package/scripts/cli/{ui/prompt.ts → prompt.ts} +0 -0
|
@@ -1,146 +1,144 @@
|
|
|
1
|
-
// Shared authorization primitives: closed scope model and immutable access decisions.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Closed set of authorization scopes.
|
|
5
|
-
* - `routing:invoke`: May call only /v1/* gateway routes within holder's tenant.
|
|
6
|
-
* - `routing:cli_mapping`: May use persisted CLI source→target model mappings.
|
|
7
|
-
* - `dashboard:read`: Reads only holder's tenant configuration and usage.
|
|
8
|
-
* - `dashboard:write`: Modifies only holder's tenant configuration.
|
|
9
|
-
* - `providers:read` / `providers:write`: Reads or modifies provider rows —
|
|
10
|
-
* including registering a BYOK upstream and its credential.
|
|
11
|
-
* - `models:read` / `models:write`: Reads or modifies catalog model rows.
|
|
12
|
-
* - `platform:admin`: Cross-tenant operator actions (account health, kill-switch, catalog sync).
|
|
13
|
-
*
|
|
14
|
-
* Catalog mutation is deliberately separate from `dashboard:write`. A key
|
|
15
|
-
* minted to read usage, or to change a display setting, must not thereby be
|
|
16
|
-
* able to add an upstream or delete a model: those writes change where traffic
|
|
17
|
-
* is sent and which credentials are used, so they are granted explicitly.
|
|
18
|
-
*/
|
|
19
|
-
export type AccessScope =
|
|
20
|
-
| "routing:invoke"
|
|
21
|
-
| "routing:cli_mapping"
|
|
22
|
-
| "search:invoke"
|
|
23
|
-
| "dashboard:read"
|
|
24
|
-
| "dashboard:write"
|
|
25
|
-
| "providers:read"
|
|
26
|
-
| "providers:write"
|
|
27
|
-
| "models:read"
|
|
28
|
-
| "models:write"
|
|
29
|
-
| "platform:admin";
|
|
30
|
-
|
|
31
|
-
/** Scopes a tenant API key may hold; `platform:admin` is never assignable. */
|
|
32
|
-
export type TenantScope = Exclude<AccessScope, "platform:admin">;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* The scopes a signed-in console session holds, per principal kind.
|
|
36
|
-
*
|
|
37
|
-
* Stated here rather than inline at the session resolver so the dashboard's
|
|
38
|
-
* authority has one home, and so the catalog scopes are granted by name.
|
|
39
|
-
*
|
|
40
|
-
* They must be granted by name because `dashboard:write` deliberately does not
|
|
41
|
-
* imply them: a tenant API key can hold `dashboard:write`, and such a key must
|
|
42
|
-
* not be able to add an upstream or delete a model. The session is the operator
|
|
43
|
-
* and needs the catalog routes to work, so it holds the catalog scopes
|
|
44
|
-
* explicitly instead — which keeps the separation honest without narrowing the
|
|
45
|
-
* dashboard.
|
|
46
|
-
*
|
|
47
|
-
* A regular console user reads their tenant's configuration and catalog but
|
|
48
|
-
* writes nothing; that read-only ceiling is the pre-existing behaviour and is
|
|
49
|
-
* preserved exactly, just spelled with the catalog read scopes the routes now
|
|
50
|
-
* require.
|
|
51
|
-
*/
|
|
52
|
-
export function consoleSessionScopes(isPlatformAdmin: boolean): readonly AccessScope[] {
|
|
53
|
-
if (isPlatformAdmin) {
|
|
54
|
-
return [
|
|
55
|
-
"dashboard:read",
|
|
56
|
-
"dashboard:write",
|
|
57
|
-
"providers:read",
|
|
58
|
-
"providers:write",
|
|
59
|
-
"models:read",
|
|
60
|
-
"models:write",
|
|
61
|
-
"platform:admin",
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
return ["dashboard:read", "providers:read", "models:read"];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Immutable authorization decision snapshot.
|
|
69
|
-
* Contains the principal identity, tenant binding, and scopes.
|
|
70
|
-
* Created at authentication boundary and passed unchanged through routing and provider dispatch.
|
|
71
|
-
*
|
|
72
|
-
* `tenantId` is null for platform:admin cross-tenant operator sessions.
|
|
73
|
-
*/
|
|
74
|
-
export interface AccessDecision {
|
|
75
|
-
readonly id: string;
|
|
76
|
-
readonly tenantId: string | null;
|
|
77
|
-
/** Scopes present on this key/user. */
|
|
78
|
-
readonly scopes: readonly AccessScope[];
|
|
79
|
-
/** Identity recorded for audit attribution; defaults to `id` if absent. */
|
|
80
|
-
readonly admissionIdentity: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Every scope a tenant API key may be granted, in display order.
|
|
85
|
-
*
|
|
86
|
-
* The single source of truth for what the API-key editor offers: the predicate
|
|
87
|
-
* below is derived from it, and the dashboard renders it directly. Keeping the
|
|
88
|
-
* two in step by hand is how the editor came to offer only the four
|
|
89
|
-
* routing/dashboard scopes while the backend accepted eight — a `providers:write`
|
|
90
|
-
* key could be created through the API but not through the UI.
|
|
91
|
-
*
|
|
92
|
-
* `platform:admin` is deliberately absent: it is a console-session scope for
|
|
93
|
-
* cross-tenant operator actions and is never assignable to a tenant key.
|
|
94
|
-
*/
|
|
95
|
-
export const TENANT_KEY_SCOPES = [
|
|
96
|
-
"routing:invoke",
|
|
97
|
-
"routing:cli_mapping",
|
|
98
|
-
"search:invoke",
|
|
99
|
-
"dashboard:read",
|
|
100
|
-
"dashboard:write",
|
|
101
|
-
"providers:read",
|
|
102
|
-
"providers:write",
|
|
103
|
-
"models:read",
|
|
104
|
-
"models:write",
|
|
105
|
-
] as const satisfies readonly TenantScope[];
|
|
106
|
-
/**
|
|
107
|
-
* Determine if a scope is valid for a tenant API key.
|
|
108
|
-
*
|
|
109
|
-
* Tenant keys default to routing:invoke only.
|
|
110
|
-
* platform:admin is never assignable to tenant keys.
|
|
111
|
-
*/
|
|
112
|
-
export const isValidTenantKeyScope = (scope: AccessScope): scope is TenantScope =>
|
|
113
|
-
(TENANT_KEY_SCOPES as readonly AccessScope[]).includes(scope);
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Create an immutable frozen AccessDecision.
|
|
117
|
-
* Default tenant keys to routing:invoke scope if scopes are empty.
|
|
118
|
-
*/
|
|
119
|
-
export function createAccessDecision(input: {
|
|
120
|
-
readonly id: string;
|
|
121
|
-
readonly tenantId: string | null;
|
|
122
|
-
readonly scopes: readonly AccessScope[];
|
|
123
|
-
readonly admissionIdentity?: string;
|
|
124
|
-
}): AccessDecision {
|
|
125
|
-
// What was persisted is what the key holds
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
});
|
|
146
|
-
}
|
|
1
|
+
// Shared authorization primitives: closed scope model and immutable access decisions.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Closed set of authorization scopes.
|
|
5
|
+
* - `routing:invoke`: May call only /v1/* gateway routes within holder's tenant.
|
|
6
|
+
* - `routing:cli_mapping`: May use persisted CLI source→target model mappings.
|
|
7
|
+
* - `dashboard:read`: Reads only holder's tenant configuration and usage.
|
|
8
|
+
* - `dashboard:write`: Modifies only holder's tenant configuration.
|
|
9
|
+
* - `providers:read` / `providers:write`: Reads or modifies provider rows —
|
|
10
|
+
* including registering a BYOK upstream and its credential.
|
|
11
|
+
* - `models:read` / `models:write`: Reads or modifies catalog model rows.
|
|
12
|
+
* - `platform:admin`: Cross-tenant operator actions (account health, kill-switch, catalog sync).
|
|
13
|
+
*
|
|
14
|
+
* Catalog mutation is deliberately separate from `dashboard:write`. A key
|
|
15
|
+
* minted to read usage, or to change a display setting, must not thereby be
|
|
16
|
+
* able to add an upstream or delete a model: those writes change where traffic
|
|
17
|
+
* is sent and which credentials are used, so they are granted explicitly.
|
|
18
|
+
*/
|
|
19
|
+
export type AccessScope =
|
|
20
|
+
| "routing:invoke"
|
|
21
|
+
| "routing:cli_mapping"
|
|
22
|
+
| "search:invoke"
|
|
23
|
+
| "dashboard:read"
|
|
24
|
+
| "dashboard:write"
|
|
25
|
+
| "providers:read"
|
|
26
|
+
| "providers:write"
|
|
27
|
+
| "models:read"
|
|
28
|
+
| "models:write"
|
|
29
|
+
| "platform:admin";
|
|
30
|
+
|
|
31
|
+
/** Scopes a tenant API key may hold; `platform:admin` is never assignable. */
|
|
32
|
+
export type TenantScope = Exclude<AccessScope, "platform:admin">;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The scopes a signed-in console session holds, per principal kind.
|
|
36
|
+
*
|
|
37
|
+
* Stated here rather than inline at the session resolver so the dashboard's
|
|
38
|
+
* authority has one home, and so the catalog scopes are granted by name.
|
|
39
|
+
*
|
|
40
|
+
* They must be granted by name because `dashboard:write` deliberately does not
|
|
41
|
+
* imply them: a tenant API key can hold `dashboard:write`, and such a key must
|
|
42
|
+
* not be able to add an upstream or delete a model. The session is the operator
|
|
43
|
+
* and needs the catalog routes to work, so it holds the catalog scopes
|
|
44
|
+
* explicitly instead — which keeps the separation honest without narrowing the
|
|
45
|
+
* dashboard.
|
|
46
|
+
*
|
|
47
|
+
* A regular console user reads their tenant's configuration and catalog but
|
|
48
|
+
* writes nothing; that read-only ceiling is the pre-existing behaviour and is
|
|
49
|
+
* preserved exactly, just spelled with the catalog read scopes the routes now
|
|
50
|
+
* require.
|
|
51
|
+
*/
|
|
52
|
+
export function consoleSessionScopes(isPlatformAdmin: boolean): readonly AccessScope[] {
|
|
53
|
+
if (isPlatformAdmin) {
|
|
54
|
+
return [
|
|
55
|
+
"dashboard:read",
|
|
56
|
+
"dashboard:write",
|
|
57
|
+
"providers:read",
|
|
58
|
+
"providers:write",
|
|
59
|
+
"models:read",
|
|
60
|
+
"models:write",
|
|
61
|
+
"platform:admin",
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
return ["dashboard:read", "providers:read", "models:read"];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Immutable authorization decision snapshot.
|
|
69
|
+
* Contains the principal identity, tenant binding, and scopes.
|
|
70
|
+
* Created at authentication boundary and passed unchanged through routing and provider dispatch.
|
|
71
|
+
*
|
|
72
|
+
* `tenantId` is null for platform:admin cross-tenant operator sessions.
|
|
73
|
+
*/
|
|
74
|
+
export interface AccessDecision {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly tenantId: string | null;
|
|
77
|
+
/** Scopes present on this key/user. */
|
|
78
|
+
readonly scopes: readonly AccessScope[];
|
|
79
|
+
/** Identity recorded for audit attribution; defaults to `id` if absent. */
|
|
80
|
+
readonly admissionIdentity: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Every scope a tenant API key may be granted, in display order.
|
|
85
|
+
*
|
|
86
|
+
* The single source of truth for what the API-key editor offers: the predicate
|
|
87
|
+
* below is derived from it, and the dashboard renders it directly. Keeping the
|
|
88
|
+
* two in step by hand is how the editor came to offer only the four
|
|
89
|
+
* routing/dashboard scopes while the backend accepted eight — a `providers:write`
|
|
90
|
+
* key could be created through the API but not through the UI.
|
|
91
|
+
*
|
|
92
|
+
* `platform:admin` is deliberately absent: it is a console-session scope for
|
|
93
|
+
* cross-tenant operator actions and is never assignable to a tenant key.
|
|
94
|
+
*/
|
|
95
|
+
export const TENANT_KEY_SCOPES = [
|
|
96
|
+
"routing:invoke",
|
|
97
|
+
"routing:cli_mapping",
|
|
98
|
+
"search:invoke",
|
|
99
|
+
"dashboard:read",
|
|
100
|
+
"dashboard:write",
|
|
101
|
+
"providers:read",
|
|
102
|
+
"providers:write",
|
|
103
|
+
"models:read",
|
|
104
|
+
"models:write",
|
|
105
|
+
] as const satisfies readonly TenantScope[];
|
|
106
|
+
/**
|
|
107
|
+
* Determine if a scope is valid for a tenant API key.
|
|
108
|
+
*
|
|
109
|
+
* Tenant keys default to routing:invoke only.
|
|
110
|
+
* platform:admin is never assignable to tenant keys.
|
|
111
|
+
*/
|
|
112
|
+
export const isValidTenantKeyScope = (scope: AccessScope): scope is TenantScope =>
|
|
113
|
+
(TENANT_KEY_SCOPES as readonly AccessScope[]).includes(scope);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create an immutable frozen AccessDecision.
|
|
117
|
+
* Default tenant keys to routing:invoke scope if scopes are empty.
|
|
118
|
+
*/
|
|
119
|
+
export function createAccessDecision(input: {
|
|
120
|
+
readonly id: string;
|
|
121
|
+
readonly tenantId: string | null;
|
|
122
|
+
readonly scopes: readonly AccessScope[];
|
|
123
|
+
readonly admissionIdentity?: string;
|
|
124
|
+
}): AccessDecision {
|
|
125
|
+
// What was persisted is what the key holds: no scope is re-granted here, so
|
|
126
|
+
// unchecking a scope in the console saves a revocation that survives the next
|
|
127
|
+
// read. The stored array is the whole truth.
|
|
128
|
+
const scopes =
|
|
129
|
+
input.scopes.length === 0 && input.tenantId !== null
|
|
130
|
+
? (["routing:invoke"] as readonly AccessScope[])
|
|
131
|
+
: (Array.from(input.scopes) as readonly AccessScope[]);
|
|
132
|
+
const decision: AccessDecision = {
|
|
133
|
+
id: input.id,
|
|
134
|
+
tenantId: input.tenantId,
|
|
135
|
+
scopes,
|
|
136
|
+
admissionIdentity: input.admissionIdentity ?? input.id,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Deep freeze the decision
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
...decision,
|
|
142
|
+
scopes: Object.freeze([...decision.scopes]),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -25,6 +25,17 @@ export interface ApiKeyAdmissionRequest {
|
|
|
25
25
|
export interface AdmissionReserveRequest {
|
|
26
26
|
readonly reservationId: string;
|
|
27
27
|
readonly apiKeyId: string;
|
|
28
|
+
/**
|
|
29
|
+
* The key whose rpm and concurrency counters are charged.
|
|
30
|
+
*
|
|
31
|
+
* Share child keys set this to their own id so each child has an independent
|
|
32
|
+
* rpm window and concurrency slot. Token budgets (daily / monthly / lifetime)
|
|
33
|
+
* are still charged to `apiKeyId` — the parent — so the shared pool is
|
|
34
|
+
* enforced globally across all children.
|
|
35
|
+
*
|
|
36
|
+
* Defaults to `apiKeyId` when absent (non-share keys, backward compat).
|
|
37
|
+
*/
|
|
38
|
+
readonly rpmConcurrencyKeyId?: string;
|
|
28
39
|
readonly now: number;
|
|
29
40
|
readonly estimatedTokens: number;
|
|
30
41
|
readonly rpmLimit: number | null;
|
|
@@ -94,12 +94,13 @@ export class InMemoryAdmissionCounterStore implements AdmissionCounterStore {
|
|
|
94
94
|
) {
|
|
95
95
|
throw reasonToGatewayError("admission-unavailable", { reason: "invalid_counter" });
|
|
96
96
|
}
|
|
97
|
-
const
|
|
97
|
+
const rpmConcId = request.rpmConcurrencyKeyId ?? request.apiKeyId;
|
|
98
|
+
const rpm = this.pruneRpm(rpmConcId, request.now);
|
|
98
99
|
const dailyKey = bucketKey(request.apiKeyId, dailyBucket(request.now));
|
|
99
100
|
const monthlyKey = bucketKey(request.apiKeyId, monthlyBucket(request.now));
|
|
100
101
|
const daily = this.value(this.daily, dailyKey);
|
|
101
102
|
const monthly = this.value(this.monthly, monthlyKey);
|
|
102
|
-
const concurrent = this.value(this.concurrent,
|
|
103
|
+
const concurrent = this.value(this.concurrent, rpmConcId);
|
|
103
104
|
const tenantConcurrent = this.value(this.tenantConcurrent, request.tenantId);
|
|
104
105
|
// A missing counter is the only path that seeds from the snapshot; on
|
|
105
106
|
// that path prefer a fresh persisted read over the ≤3s-stale snapshot,
|
|
@@ -165,7 +166,7 @@ export class InMemoryAdmissionCounterStore implements AdmissionCounterStore {
|
|
|
165
166
|
this.evictCounter(this.lifetime);
|
|
166
167
|
}
|
|
167
168
|
if (request.concurrencyLimit != null) {
|
|
168
|
-
this.concurrent.set(
|
|
169
|
+
this.concurrent.set(rpmConcId, concurrent + 1);
|
|
169
170
|
this.evictCounter(this.concurrent);
|
|
170
171
|
}
|
|
171
172
|
if (request.tenantConcurrencyLimit != null) {
|
|
@@ -14,12 +14,12 @@ const ADMISSION_LEASE_PATTERN = "admission:lease:*";
|
|
|
14
14
|
/**
|
|
15
15
|
* Bounds for one pass.
|
|
16
16
|
*
|
|
17
|
-
* The scan walks the whole keyspace
|
|
18
|
-
*
|
|
19
|
-
* has grown for months
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* The scan walks the whole keyspace, so following the cursor until it wraps and
|
|
18
|
+
* reaping every expired lease it finds is one pass with no ceiling on a
|
|
19
|
+
* keyspace that has grown for months: it would hold the timer slot for as long
|
|
20
|
+
* as the backlog takes and starve every other sweep. A backlog drains over
|
|
21
|
+
* successive passes instead; leases the cap leaves behind are still expired on
|
|
22
|
+
* the next tick.
|
|
23
23
|
*/
|
|
24
24
|
export const MAX_LEASE_SCAN_ITERATIONS = 50;
|
|
25
25
|
export const MAX_LEASE_REAPS_PER_PASS = 500;
|
|
@@ -43,7 +43,11 @@ const REASON_META: Record<
|
|
|
43
43
|
metricLabel: "lifetime",
|
|
44
44
|
},
|
|
45
45
|
"concurrency-limit": {
|
|
46
|
-
|
|
46
|
+
// This ceiling is the API key's own `max_concurrent`, not the provider's
|
|
47
|
+
// max-inflight. The two used to be indistinguishable and both named the
|
|
48
|
+
// provider, sending operators to the wrong setting after a rejection. The
|
|
49
|
+
// `details` carry the limit so a client can tell which one fired.
|
|
50
|
+
message: "This API key is already serving its maximum number of concurrent requests. Retry shortly, or raise the key's concurrency limit.",
|
|
47
51
|
code: "capacity_exhausted",
|
|
48
52
|
status: 429,
|
|
49
53
|
metricLabel: "concurrency",
|