codex-multi-auth 2.3.0-beta.1 → 2.3.0-beta.3
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/.codex-plugin/plugin.json +2 -1
- package/README.md +4 -4
- package/config/schema/config.schema.json +268 -21
- package/dist/index.js +0 -1
- package/dist/lib/account-policy.d.ts.map +1 -1
- package/dist/lib/account-policy.js +2 -2
- package/dist/lib/accounts/rate-limits.js +0 -1
- package/dist/lib/accounts.d.ts +3 -8
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +2 -3
- package/dist/lib/audit.d.ts +0 -9
- package/dist/lib/audit.d.ts.map +1 -1
- package/dist/lib/audit.js +0 -1
- package/dist/lib/auth/auth.js +0 -1
- package/dist/lib/auth/browser.js +0 -1
- package/dist/lib/auth/device-auth.d.ts +1 -6
- package/dist/lib/auth/device-auth.d.ts.map +1 -1
- package/dist/lib/auth/device-auth.js +5 -6
- package/dist/lib/auth/index.js +0 -1
- package/dist/lib/auth/org-override.js +0 -1
- package/dist/lib/auth/server.js +0 -1
- package/dist/lib/auth/token-utils.js +0 -1
- package/dist/lib/auth-rate-limit.js +0 -1
- package/dist/lib/budget-guard.d.ts.map +1 -1
- package/dist/lib/budget-guard.js +2 -2
- package/dist/lib/capability-policy.js +0 -1
- package/dist/lib/circuit-breaker.js +0 -1
- package/dist/lib/cli.js +1 -2
- package/dist/lib/codex-cli/index.js +0 -1
- package/dist/lib/codex-cli/observability.js +0 -1
- package/dist/lib/codex-cli/state.js +0 -1
- package/dist/lib/codex-cli/sync.d.ts +2 -2
- package/dist/lib/codex-cli/sync.d.ts.map +1 -1
- package/dist/lib/codex-cli/sync.js +1 -2
- package/dist/lib/codex-cli/writer.d.ts.map +1 -1
- package/dist/lib/codex-cli/writer.js +2 -2
- package/dist/lib/codex-manager/account-credentials.d.ts +13 -0
- package/dist/lib/codex-manager/account-credentials.d.ts.map +1 -0
- package/dist/lib/codex-manager/account-credentials.js +55 -0
- package/dist/lib/codex-manager/account-manager-commands.js +0 -1
- package/dist/lib/codex-manager/account-pool-write.d.ts +1 -1
- package/dist/lib/codex-manager/account-pool-write.d.ts.map +1 -1
- package/dist/lib/codex-manager/account-pool-write.js +0 -1
- package/dist/lib/codex-manager/backend-category-entry.js +0 -1
- package/dist/lib/codex-manager/backend-category-helpers.js +0 -1
- package/dist/lib/codex-manager/backend-category-prompt.js +0 -1
- package/dist/lib/codex-manager/backend-settings-controller.js +0 -1
- package/dist/lib/codex-manager/backend-settings-entry.js +0 -1
- package/dist/lib/codex-manager/backend-settings-helpers.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-helpers.d.ts.map +1 -1
- package/dist/lib/codex-manager/backend-settings-helpers.js +1 -2
- package/dist/lib/codex-manager/backend-settings-prompt.js +0 -1
- package/dist/lib/codex-manager/backend-settings-schema.js +0 -1
- package/dist/lib/codex-manager/behavior-settings-panel.d.ts +1 -20
- package/dist/lib/codex-manager/behavior-settings-panel.d.ts.map +1 -1
- package/dist/lib/codex-manager/behavior-settings-panel.js +0 -1
- package/dist/lib/codex-manager/commands/account.js +0 -1
- package/dist/lib/codex-manager/commands/best.d.ts +8 -0
- package/dist/lib/codex-manager/commands/best.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/best.js +64 -1
- package/dist/lib/codex-manager/commands/bridge.js +0 -1
- package/dist/lib/codex-manager/commands/budget.js +0 -1
- package/dist/lib/codex-manager/commands/check.js +0 -1
- package/dist/lib/codex-manager/commands/config-explain.js +0 -1
- package/dist/lib/codex-manager/commands/debug-bundle.js +0 -1
- package/dist/lib/codex-manager/commands/forecast.js +0 -1
- package/dist/lib/codex-manager/commands/init-config.js +0 -1
- package/dist/lib/codex-manager/commands/integrations.js +0 -1
- package/dist/lib/codex-manager/commands/models.js +0 -1
- package/dist/lib/codex-manager/commands/monitor.js +0 -1
- package/dist/lib/codex-manager/commands/report.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/report.js +2 -2
- package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.js +1 -4
- package/dist/lib/codex-manager/commands/status.js +0 -1
- package/dist/lib/codex-manager/commands/switch.js +0 -1
- package/dist/lib/codex-manager/commands/uninstall.d.ts +2 -2
- package/dist/lib/codex-manager/commands/uninstall.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/uninstall.js +3 -34
- package/dist/lib/codex-manager/commands/unpin.js +0 -1
- package/dist/lib/codex-manager/commands/usage.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/usage.js +2 -2
- package/dist/lib/codex-manager/commands/verify.d.ts +2 -2
- package/dist/lib/codex-manager/commands/verify.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/verify.js +0 -1
- package/dist/lib/codex-manager/commands/why-selected.d.ts +1 -22
- package/dist/lib/codex-manager/commands/why-selected.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/why-selected.js +0 -1
- package/dist/lib/codex-manager/commands/workspace.js +0 -1
- package/dist/lib/codex-manager/dashboard-display-panel.d.ts +1 -15
- package/dist/lib/codex-manager/dashboard-display-panel.d.ts.map +1 -1
- package/dist/lib/codex-manager/dashboard-display-panel.js +0 -1
- package/dist/lib/codex-manager/dashboard-formatters.js +0 -1
- package/dist/lib/codex-manager/dashboard-settings-controller.js +0 -1
- package/dist/lib/codex-manager/dashboard-settings-data.js +0 -1
- package/dist/lib/codex-manager/dashboard-settings-entry.js +0 -1
- package/dist/lib/codex-manager/experimental-settings-entry.js +0 -1
- package/dist/lib/codex-manager/experimental-settings-prompt.d.ts +2 -1
- package/dist/lib/codex-manager/experimental-settings-prompt.d.ts.map +1 -1
- package/dist/lib/codex-manager/experimental-settings-prompt.js +0 -1
- package/dist/lib/codex-manager/experimental-settings-schema.js +1 -2
- package/dist/lib/codex-manager/experimental-sync-target-entry.js +0 -1
- package/dist/lib/codex-manager/experimental-sync-target.js +0 -1
- package/dist/lib/codex-manager/forecast-report-commands.js +0 -1
- package/dist/lib/codex-manager/forecast-report-shared.d.ts +2 -2
- package/dist/lib/codex-manager/forecast-report-shared.d.ts.map +1 -1
- package/dist/lib/codex-manager/forecast-report-shared.js +5 -21
- package/dist/lib/codex-manager/formatters/account-formatters.d.ts +11 -0
- package/dist/lib/codex-manager/formatters/account-formatters.d.ts.map +1 -0
- package/dist/lib/codex-manager/formatters/account-formatters.js +79 -0
- package/dist/lib/codex-manager/formatters/index.d.ts +5 -0
- package/dist/lib/codex-manager/formatters/index.d.ts.map +1 -0
- package/dist/lib/codex-manager/formatters/index.js +4 -0
- package/dist/lib/codex-manager/formatters/model-formatters.d.ts +12 -0
- package/dist/lib/codex-manager/formatters/model-formatters.d.ts.map +1 -0
- package/dist/lib/codex-manager/formatters/model-formatters.js +23 -0
- package/dist/lib/codex-manager/formatters/quota-formatters.d.ts +9 -0
- package/dist/lib/codex-manager/formatters/quota-formatters.d.ts.map +1 -0
- package/dist/lib/codex-manager/formatters/quota-formatters.js +104 -0
- package/dist/lib/codex-manager/formatters/text-style.d.ts +14 -0
- package/dist/lib/codex-manager/formatters/text-style.d.ts.map +1 -0
- package/dist/lib/codex-manager/formatters/text-style.js +111 -0
- package/dist/lib/codex-manager/health-check.d.ts +14 -0
- package/dist/lib/codex-manager/health-check.d.ts.map +1 -0
- package/dist/lib/codex-manager/health-check.js +278 -0
- package/dist/lib/codex-manager/help.d.ts +2 -1
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +0 -1
- package/dist/lib/codex-manager/login-action-panel.d.ts +4 -0
- package/dist/lib/codex-manager/login-action-panel.d.ts.map +1 -0
- package/dist/lib/codex-manager/login-action-panel.js +238 -0
- package/dist/lib/codex-manager/login-flow.d.ts +17 -0
- package/dist/lib/codex-manager/login-flow.d.ts.map +1 -0
- package/dist/lib/codex-manager/login-flow.js +387 -0
- package/dist/lib/codex-manager/login-menu-actions.d.ts +20 -0
- package/dist/lib/codex-manager/login-menu-actions.d.ts.map +1 -0
- package/dist/lib/codex-manager/login-menu-actions.js +303 -0
- package/dist/lib/codex-manager/login-menu-data.d.ts +19 -0
- package/dist/lib/codex-manager/login-menu-data.d.ts.map +1 -0
- package/dist/lib/codex-manager/login-menu-data.js +378 -0
- package/dist/lib/codex-manager/login-oauth.d.ts +55 -0
- package/dist/lib/codex-manager/login-oauth.d.ts.map +1 -0
- package/dist/lib/codex-manager/login-oauth.js +345 -0
- package/dist/lib/codex-manager/manual-callback.js +0 -1
- package/dist/lib/codex-manager/persist-selected-account.d.ts +24 -0
- package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -0
- package/dist/lib/codex-manager/persist-selected-account.js +107 -0
- package/dist/lib/codex-manager/quota-cache-helpers.d.ts +18 -0
- package/dist/lib/codex-manager/quota-cache-helpers.d.ts.map +1 -0
- package/dist/lib/codex-manager/quota-cache-helpers.js +112 -0
- package/dist/lib/codex-manager/rate-limit-markers.js +0 -1
- package/dist/lib/codex-manager/repair-commands.d.ts +0 -15
- package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/repair-commands.js +5 -6
- package/dist/lib/codex-manager/settings-hub/backend.d.ts +0 -5
- package/dist/lib/codex-manager/settings-hub/backend.d.ts.map +1 -1
- package/dist/lib/codex-manager/settings-hub/backend.js +2 -3
- package/dist/lib/codex-manager/settings-hub/dashboard.d.ts +1 -14
- package/dist/lib/codex-manager/settings-hub/dashboard.d.ts.map +1 -1
- package/dist/lib/codex-manager/settings-hub/dashboard.js +9 -10
- package/dist/lib/codex-manager/settings-hub/experimental.js +1 -2
- package/dist/lib/codex-manager/settings-hub/index.js +1 -2
- package/dist/lib/codex-manager/settings-hub/shared.js +0 -1
- package/dist/lib/codex-manager/settings-hub-entry.js +0 -1
- package/dist/lib/codex-manager/settings-hub-menu.js +0 -1
- package/dist/lib/codex-manager/settings-hub-prompt.js +0 -1
- package/dist/lib/codex-manager/settings-hub.js +0 -1
- package/dist/lib/codex-manager/settings-panels.js +0 -1
- package/dist/lib/codex-manager/settings-persist-utils.js +0 -1
- package/dist/lib/codex-manager/settings-preview.js +0 -1
- package/dist/lib/codex-manager/settings-write-queue.d.ts +0 -10
- package/dist/lib/codex-manager/settings-write-queue.d.ts.map +1 -1
- package/dist/lib/codex-manager/settings-write-queue.js +10 -11
- package/dist/lib/codex-manager/statusline-order.js +0 -1
- package/dist/lib/codex-manager/statusline-settings-panel.d.ts +3 -18
- package/dist/lib/codex-manager/statusline-settings-panel.d.ts.map +1 -1
- package/dist/lib/codex-manager/statusline-settings-panel.js +0 -1
- package/dist/lib/codex-manager/theme-settings-panel.d.ts +1 -14
- package/dist/lib/codex-manager/theme-settings-panel.d.ts.map +1 -1
- package/dist/lib/codex-manager/theme-settings-panel.js +0 -1
- package/dist/lib/codex-manager/unified-settings-controller.js +0 -1
- package/dist/lib/codex-manager/unified-settings-entry.js +0 -1
- package/dist/lib/codex-manager.d.ts +2 -4
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +219 -2570
- package/dist/lib/config-schema.d.ts +32 -0
- package/dist/lib/config-schema.d.ts.map +1 -0
- package/dist/lib/config-schema.js +96 -0
- package/dist/lib/config.d.ts +0 -13
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +82 -123
- package/dist/lib/constants.js +0 -1
- package/dist/lib/context-overflow.js +0 -1
- package/dist/lib/dashboard-settings.d.ts +3 -3
- package/dist/lib/dashboard-settings.d.ts.map +1 -1
- package/dist/lib/dashboard-settings.js +0 -2
- package/dist/lib/entitlement-cache.js +0 -1
- package/dist/lib/env-parsing.js +0 -1
- package/dist/lib/errors.d.ts +0 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +0 -1
- package/dist/lib/forecast.d.ts +4 -3
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +0 -1
- package/dist/lib/fs-retry.d.ts +46 -3
- package/dist/lib/fs-retry.d.ts.map +1 -1
- package/dist/lib/fs-retry.js +77 -9
- package/dist/lib/health.js +0 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/integration-generators.js +0 -1
- package/dist/lib/live-account-sync.js +0 -1
- package/dist/lib/local-bridge.js +0 -1
- package/dist/lib/local-client-tokens.d.ts.map +1 -1
- package/dist/lib/local-client-tokens.js +2 -2
- package/dist/lib/logger.js +0 -1
- package/dist/lib/model-capability-matrix.js +0 -1
- package/dist/lib/named-backup-export.js +0 -1
- package/dist/lib/oc-chatgpt-import-adapter.d.ts +1 -1
- package/dist/lib/oc-chatgpt-import-adapter.d.ts.map +1 -1
- package/dist/lib/oc-chatgpt-import-adapter.js +0 -1
- package/dist/lib/oc-chatgpt-orchestrator.d.ts.map +1 -1
- package/dist/lib/oc-chatgpt-orchestrator.js +2 -2
- package/dist/lib/oc-chatgpt-target-detection.d.ts +1 -1
- package/dist/lib/oc-chatgpt-target-detection.d.ts.map +1 -1
- package/dist/lib/oc-chatgpt-target-detection.js +0 -1
- package/dist/lib/parallel-probe.js +0 -1
- package/dist/lib/policy/runtime-policy.js +0 -1
- package/dist/lib/preemptive-quota-scheduler.js +0 -1
- package/dist/lib/proactive-refresh.js +0 -1
- package/dist/lib/prompts/codex-host-bridge.d.ts +0 -8
- package/dist/lib/prompts/codex-host-bridge.d.ts.map +1 -1
- package/dist/lib/prompts/codex-host-bridge.js +0 -21
- package/dist/lib/prompts/codex.d.ts +3 -11
- package/dist/lib/prompts/codex.d.ts.map +1 -1
- package/dist/lib/prompts/codex.js +6 -13
- package/dist/lib/prompts/fetch-utils.d.ts +0 -2
- package/dist/lib/prompts/fetch-utils.d.ts.map +1 -1
- package/dist/lib/prompts/fetch-utils.js +2 -3
- package/dist/lib/prompts/host-codex-prompt.d.ts.map +1 -1
- package/dist/lib/prompts/host-codex-prompt.js +2 -2
- package/dist/lib/quota-cache.d.ts.map +1 -1
- package/dist/lib/quota-cache.js +17 -44
- package/dist/lib/quota-probe.js +0 -1
- package/dist/lib/quota-readiness.js +0 -1
- package/dist/lib/recovery/constants.js +0 -1
- package/dist/lib/recovery/index.js +0 -1
- package/dist/lib/recovery/storage.d.ts.map +1 -1
- package/dist/lib/recovery/storage.js +35 -54
- package/dist/lib/recovery/storage.js.map +1 -1
- package/dist/lib/recovery/types.d.ts +4 -12
- package/dist/lib/recovery/types.d.ts.map +1 -1
- package/dist/lib/recovery/types.js +0 -1
- package/dist/lib/recovery.d.ts +2 -2
- package/dist/lib/recovery.d.ts.map +1 -1
- package/dist/lib/recovery.js +0 -1
- package/dist/lib/refresh-guardian.js +0 -1
- package/dist/lib/refresh-lease.d.ts.map +1 -1
- package/dist/lib/refresh-lease.js +1 -4
- package/dist/lib/refresh-queue.js +0 -1
- package/dist/lib/request/error-classification.d.ts +75 -0
- package/dist/lib/request/error-classification.d.ts.map +1 -0
- package/dist/lib/request/error-classification.js +295 -0
- package/dist/lib/request/failover-config.js +0 -1
- package/dist/lib/request/failure-policy.js +0 -1
- package/dist/lib/request/fetch-helpers.d.ts +10 -114
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +7 -589
- package/dist/lib/request/headers.d.ts +33 -0
- package/dist/lib/request/headers.d.ts.map +1 -0
- package/dist/lib/request/headers.js +64 -0
- package/dist/lib/request/helpers/input-utils.js +0 -1
- package/dist/lib/request/helpers/model-map.d.ts +10 -0
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
- package/dist/lib/request/helpers/model-map.js +11 -1
- package/dist/lib/request/helpers/tool-utils.js +0 -1
- package/dist/lib/request/index.js +0 -1
- package/dist/lib/request/rate-limit-backoff.js +0 -1
- package/dist/lib/request/rate-limit-decision.d.ts +28 -0
- package/dist/lib/request/rate-limit-decision.d.ts.map +1 -0
- package/dist/lib/request/rate-limit-decision.js +191 -0
- package/dist/lib/request/request-attempt-budget.js +0 -1
- package/dist/lib/request/request-init.js +0 -1
- package/dist/lib/request/request-resilience.js +0 -1
- package/dist/lib/request/request-transformer.js +0 -1
- package/dist/lib/request/response-compaction.d.ts +2 -1
- package/dist/lib/request/response-compaction.d.ts.map +1 -1
- package/dist/lib/request/response-compaction.js +0 -1
- package/dist/lib/request/response-handler.js +0 -1
- package/dist/lib/request/response-metadata.js +0 -1
- package/dist/lib/request/stream-failover-runtime.d.ts +8 -0
- package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -0
- package/dist/lib/request/stream-failover-runtime.js +171 -0
- package/dist/lib/request/stream-failover.js +0 -1
- package/dist/lib/request/token-refresh.d.ts +30 -0
- package/dist/lib/request/token-refresh.d.ts.map +1 -0
- package/dist/lib/request/token-refresh.js +116 -0
- package/dist/lib/request/url-rewriting.d.ts +24 -0
- package/dist/lib/request/url-rewriting.d.ts.map +1 -0
- package/dist/lib/request/url-rewriting.js +153 -0
- package/dist/lib/request/wait-utils.js +0 -1
- package/dist/lib/rotation.d.ts +2 -4
- package/dist/lib/rotation.d.ts.map +1 -1
- package/dist/lib/rotation.js +1 -3
- package/dist/lib/routing-mutex.js +0 -1
- package/dist/lib/routing-profiles.d.ts.map +1 -1
- package/dist/lib/routing-profiles.js +2 -2
- package/dist/lib/runtime/account-check-helpers.js +0 -1
- package/dist/lib/runtime/account-check-types.js +0 -1
- package/dist/lib/runtime/account-check.js +0 -1
- package/dist/lib/runtime/account-health-check.js +0 -1
- package/dist/lib/runtime/account-manager-cache-entry.js +0 -1
- package/dist/lib/runtime/account-manager-cache.js +0 -1
- package/dist/lib/runtime/account-pool.js +0 -1
- package/dist/lib/runtime/account-scope.js +0 -1
- package/dist/lib/runtime/account-select-event.js +0 -1
- package/dist/lib/runtime/account-selection.js +0 -1
- package/dist/lib/runtime/account-state.js +0 -1
- package/dist/lib/runtime/account-status.js +0 -1
- package/dist/lib/runtime/account-storage-scope-entry.js +0 -1
- package/dist/lib/runtime/app-bind.js +0 -1
- package/dist/lib/runtime/auth-facade.js +0 -1
- package/dist/lib/runtime/browser-oauth-flow.js +0 -1
- package/dist/lib/runtime/capability-boost.js +0 -1
- package/dist/lib/runtime/config-toml.d.ts +0 -6
- package/dist/lib/runtime/config-toml.d.ts.map +1 -1
- package/dist/lib/runtime/config-toml.js +6 -7
- package/dist/lib/runtime/event-handler.d.ts +0 -31
- package/dist/lib/runtime/event-handler.d.ts.map +1 -1
- package/dist/lib/runtime/event-handler.js +0 -23
- package/dist/lib/runtime/first-run.d.ts +78 -0
- package/dist/lib/runtime/first-run.d.ts.map +1 -0
- package/dist/lib/runtime/first-run.js +327 -0
- package/dist/lib/runtime/flagged-verify-types.js +0 -1
- package/dist/lib/runtime/hydrate-emails.js +0 -1
- package/dist/lib/runtime/live-sync-entry.js +0 -1
- package/dist/lib/runtime/live-sync.js +0 -1
- package/dist/lib/runtime/loader-setup.js +0 -1
- package/dist/lib/runtime/login-menu-accounts.js +0 -1
- package/dist/lib/runtime/manual-oauth-flow.js +0 -1
- package/dist/lib/runtime/oauth-browser-flow.js +0 -1
- package/dist/lib/runtime/preemptive-quota.js +0 -1
- package/dist/lib/runtime/quota-headers.d.ts +1 -6
- package/dist/lib/runtime/quota-headers.d.ts.map +1 -1
- package/dist/lib/runtime/quota-headers.js +5 -6
- package/dist/lib/runtime/quota-probe.js +0 -1
- package/dist/lib/runtime/quota-settings.js +0 -1
- package/dist/lib/runtime/refresh-guardian-entry.js +0 -1
- package/dist/lib/runtime/refresh-guardian.js +0 -1
- package/dist/lib/runtime/request-init.js +0 -1
- package/dist/lib/runtime/rotation-account-selection.d.ts +38 -0
- package/dist/lib/runtime/rotation-account-selection.d.ts.map +1 -0
- package/dist/lib/runtime/rotation-account-selection.js +172 -0
- package/dist/lib/runtime/rotation-proxy-state.d.ts +54 -0
- package/dist/lib/runtime/rotation-proxy-state.d.ts.map +1 -0
- package/dist/lib/runtime/rotation-proxy-state.js +56 -0
- package/dist/lib/runtime/rotation-server-types.d.ts +57 -0
- package/dist/lib/runtime/rotation-server-types.d.ts.map +1 -0
- package/dist/lib/runtime/rotation-server-types.js +1 -0
- package/dist/lib/runtime/rotation-storage-meta.d.ts +40 -0
- package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -0
- package/dist/lib/runtime/rotation-storage-meta.js +143 -0
- package/dist/lib/runtime/rotation-token-refresh.d.ts +25 -0
- package/dist/lib/runtime/rotation-token-refresh.d.ts.map +1 -0
- package/dist/lib/runtime/rotation-token-refresh.js +99 -0
- package/dist/lib/runtime/runtime-current-account.d.ts +3 -3
- package/dist/lib/runtime/runtime-current-account.d.ts.map +1 -1
- package/dist/lib/runtime/runtime-current-account.js +2 -5
- package/dist/lib/runtime/runtime-observability.d.ts +2 -2
- package/dist/lib/runtime/runtime-observability.d.ts.map +1 -1
- package/dist/lib/runtime/runtime-observability.js +0 -5
- package/dist/lib/runtime/runtime-services.js +0 -1
- package/dist/lib/runtime/session-affinity-entry.js +0 -1
- package/dist/lib/runtime/session-affinity.js +0 -1
- package/dist/lib/runtime/session-recovery.js +0 -1
- package/dist/lib/runtime/status-marker.js +0 -1
- package/dist/lib/runtime/storage-scope.js +0 -1
- package/dist/lib/runtime/toast.js +0 -1
- package/dist/lib/runtime/ui-runtime-entry.js +0 -1
- package/dist/lib/runtime/ui-runtime.js +0 -1
- package/dist/lib/runtime/verify-flagged.js +0 -1
- package/dist/lib/runtime-constants.js +0 -1
- package/dist/lib/runtime-paths.js +0 -1
- package/dist/lib/runtime-rotation-proxy.d.ts +7 -124
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +618 -1356
- package/dist/lib/schemas.d.ts +5 -93
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +9 -10
- package/dist/lib/session-affinity.js +0 -1
- package/dist/lib/shutdown.js +0 -1
- package/dist/lib/storage/account-clear-entry.js +0 -1
- package/dist/lib/storage/account-clear.js +0 -1
- package/dist/lib/storage/account-match-utils.js +0 -1
- package/dist/lib/storage/account-persistence.d.ts +1 -1
- package/dist/lib/storage/account-persistence.d.ts.map +1 -1
- package/dist/lib/storage/account-persistence.js +0 -1
- package/dist/lib/storage/account-port.d.ts +1 -1
- package/dist/lib/storage/account-port.d.ts.map +1 -1
- package/dist/lib/storage/account-port.js +0 -1
- package/dist/lib/storage/account-save-entry.d.ts +1 -1
- package/dist/lib/storage/account-save-entry.d.ts.map +1 -1
- package/dist/lib/storage/account-save-entry.js +0 -1
- package/dist/lib/storage/account-save.d.ts +1 -1
- package/dist/lib/storage/account-save.d.ts.map +1 -1
- package/dist/lib/storage/account-save.js +0 -1
- package/dist/lib/storage/account-snapshot.js +0 -1
- package/dist/lib/storage/backup-metadata-builder.d.ts +1 -1
- package/dist/lib/storage/backup-metadata-builder.d.ts.map +1 -1
- package/dist/lib/storage/backup-metadata-builder.js +0 -1
- package/dist/lib/storage/backup-metadata.d.ts +13 -0
- package/dist/lib/storage/backup-metadata.d.ts.map +1 -1
- package/dist/lib/storage/backup-metadata.js +0 -1
- package/dist/lib/storage/backup-paths.js +0 -1
- package/dist/lib/storage/backup-restore.d.ts +1 -1
- package/dist/lib/storage/backup-restore.d.ts.map +1 -1
- package/dist/lib/storage/backup-restore.js +0 -1
- package/dist/lib/storage/cache-artifacts.js +0 -1
- package/dist/lib/storage/error-hints.js +0 -1
- package/dist/lib/storage/file-paths.d.ts +2 -2
- package/dist/lib/storage/file-paths.d.ts.map +1 -1
- package/dist/lib/storage/file-paths.js +2 -3
- package/dist/lib/storage/fixture-guards.d.ts +1 -1
- package/dist/lib/storage/fixture-guards.d.ts.map +1 -1
- package/dist/lib/storage/fixture-guards.js +0 -1
- package/dist/lib/storage/flagged-entry.js +0 -1
- package/dist/lib/storage/flagged-load-entry.d.ts +1 -1
- package/dist/lib/storage/flagged-load-entry.d.ts.map +1 -1
- package/dist/lib/storage/flagged-load-entry.js +0 -1
- package/dist/lib/storage/flagged-save-entry.d.ts +1 -1
- package/dist/lib/storage/flagged-save-entry.d.ts.map +1 -1
- package/dist/lib/storage/flagged-save-entry.js +0 -1
- package/dist/lib/storage/flagged-storage-file.d.ts +1 -1
- package/dist/lib/storage/flagged-storage-file.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-file.js +0 -1
- package/dist/lib/storage/flagged-storage-io.d.ts +1 -1
- package/dist/lib/storage/flagged-storage-io.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-io.js +2 -3
- package/dist/lib/storage/flagged-storage.d.ts +1 -1
- package/dist/lib/storage/flagged-storage.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage.js +15 -2
- package/dist/lib/storage/flagged-storage.js.map +1 -1
- package/dist/lib/storage/gitignore.js +0 -1
- package/dist/lib/storage/hash.js +0 -1
- package/dist/lib/storage/health.js +0 -1
- package/dist/lib/storage/identity.js +0 -1
- package/dist/lib/storage/import-export.d.ts +1 -1
- package/dist/lib/storage/import-export.d.ts.map +1 -1
- package/dist/lib/storage/import-export.js +2 -3
- package/dist/lib/storage/metadata-section.js +0 -1
- package/dist/lib/storage/migrations.d.ts +7 -49
- package/dist/lib/storage/migrations.d.ts.map +1 -1
- package/dist/lib/storage/migrations.js +5 -2
- package/dist/lib/storage/named-backup-entry.js +0 -1
- package/dist/lib/storage/named-backups-entry.d.ts +1 -1
- package/dist/lib/storage/named-backups-entry.d.ts.map +1 -1
- package/dist/lib/storage/named-backups-entry.js +0 -1
- package/dist/lib/storage/named-backups.js +0 -1
- package/dist/lib/storage/path-state.js +0 -1
- package/dist/lib/storage/paths.js +0 -1
- package/dist/lib/storage/project-migration.d.ts +1 -1
- package/dist/lib/storage/project-migration.d.ts.map +1 -1
- package/dist/lib/storage/project-migration.js +0 -1
- package/dist/lib/storage/public-types.d.ts +70 -0
- package/dist/lib/storage/public-types.d.ts.map +1 -0
- package/dist/lib/storage/public-types.js +6 -0
- package/dist/lib/storage/record-utils.js +0 -1
- package/dist/lib/storage/restore-assessment.d.ts +1 -1
- package/dist/lib/storage/restore-assessment.d.ts.map +1 -1
- package/dist/lib/storage/restore-assessment.js +0 -1
- package/dist/lib/storage/restore-backup-entry.d.ts +1 -1
- package/dist/lib/storage/restore-backup-entry.d.ts.map +1 -1
- package/dist/lib/storage/restore-backup-entry.js +0 -1
- package/dist/lib/storage/restore-metadata.d.ts +1 -1
- package/dist/lib/storage/restore-metadata.d.ts.map +1 -1
- package/dist/lib/storage/restore-metadata.js +0 -1
- package/dist/lib/storage/restore.d.ts +1 -1
- package/dist/lib/storage/restore.d.ts.map +1 -1
- package/dist/lib/storage/restore.js +0 -1
- package/dist/lib/storage/save-retry.d.ts +10 -0
- package/dist/lib/storage/save-retry.d.ts.map +1 -0
- package/dist/lib/storage/save-retry.js +26 -0
- package/dist/lib/storage/snapshot-inspectors.d.ts +1 -1
- package/dist/lib/storage/snapshot-inspectors.d.ts.map +1 -1
- package/dist/lib/storage/snapshot-inspectors.js +0 -1
- package/dist/lib/storage/storage-parser.d.ts +1 -1
- package/dist/lib/storage/storage-parser.d.ts.map +1 -1
- package/dist/lib/storage/storage-parser.js +0 -1
- package/dist/lib/storage/transactions.d.ts +1 -1
- package/dist/lib/storage/transactions.d.ts.map +1 -1
- package/dist/lib/storage/transactions.js +0 -1
- package/dist/lib/storage.d.ts +3 -24
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +47 -55
- package/dist/lib/table-formatter.js +0 -1
- package/dist/lib/temp-path.d.ts +26 -0
- package/dist/lib/temp-path.d.ts.map +1 -0
- package/dist/lib/temp-path.js +30 -0
- package/dist/lib/tools/hashline-tools.js +0 -1
- package/dist/lib/types.js +0 -1
- package/dist/lib/ui/ansi.js +0 -1
- package/dist/lib/ui/auth-menu-builder.d.ts +89 -0
- package/dist/lib/ui/auth-menu-builder.d.ts.map +1 -0
- package/dist/lib/ui/auth-menu-builder.js +350 -0
- package/dist/lib/ui/auth-menu.d.ts +2 -76
- package/dist/lib/ui/auth-menu.d.ts.map +1 -1
- package/dist/lib/ui/auth-menu.js +3 -349
- package/dist/lib/ui/confirm.js +0 -1
- package/dist/lib/ui/display-width.js +0 -1
- package/dist/lib/ui/format.js +0 -1
- package/dist/lib/ui/index.d.ts +10 -0
- package/dist/lib/ui/index.d.ts.map +1 -0
- package/dist/lib/ui/index.js +9 -0
- package/dist/lib/ui/runtime.js +0 -1
- package/dist/lib/ui/select.js +0 -1
- package/dist/lib/ui/theme.d.ts +3 -2
- package/dist/lib/ui/theme.d.ts.map +1 -1
- package/dist/lib/ui/theme.js +0 -1
- package/dist/lib/ui/ui-copy.d.ts +159 -0
- package/dist/lib/ui/ui-copy.d.ts.map +1 -0
- package/dist/lib/ui/ui-copy.js +163 -0
- package/dist/lib/unified-settings.d.ts.map +1 -1
- package/dist/lib/unified-settings.js +2 -2
- package/dist/lib/update-notice.d.ts.map +1 -1
- package/dist/lib/update-notice.js +2 -2
- package/dist/lib/usage/index.js +0 -1
- package/dist/lib/usage/ledger.js +0 -1
- package/dist/lib/usage/pricing.js +0 -1
- package/dist/lib/usage/redaction.js +0 -1
- package/dist/lib/usage/types.js +0 -1
- package/dist/lib/utils.js +0 -1
- package/package.json +8 -9
- package/scripts/postinstall.js +34 -265
- package/scripts/preuninstall.js +2 -2
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chooseAccount` is a SYNC selector that internally advances the rotation
|
|
3
|
+
* cursor (the session-affinity-preferred branch and the round-robin fallback
|
|
4
|
+
* both call `accountManager.markSwitched(...)`, and the hybrid selector advances
|
|
5
|
+
* its own cursor). It does NOT acquire the routing mutex itself.
|
|
6
|
+
*
|
|
7
|
+
* Concurrency (L4): when `routingMutex === "enabled"`, the proxy hot path runs
|
|
8
|
+
* this whole call AND the subsequent `markSwitchedLocked` commit inside a single
|
|
9
|
+
* `withRoutingMutex` acquisition, so concurrent requests serialize selection +
|
|
10
|
+
* cursor advance and cannot stampede the same account. `withRoutingMutex` is
|
|
11
|
+
* reentrant (AsyncLocalStorage), so the nested `markSwitchedLocked` — and the
|
|
12
|
+
* later one in `persistRuntimeActiveAccount` — run inline without re-acquiring
|
|
13
|
+
* the non-reentrant FIFO queue (no deadlock). In legacy mode the inline
|
|
14
|
+
* `markSwitched` calls below are used unchanged and no lock is taken, so default
|
|
15
|
+
* behavior and perf are identical. See the hot-path caller in
|
|
16
|
+
* `startRuntimeRotationProxy` and the regression in
|
|
17
|
+
* `test/runtime-rotation-proxy.test.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export function chooseAccount(params) {
|
|
20
|
+
const { accountManager, sessionAffinityStore, sessionKey, family, model, attemptedIndexes, now, policy, pinnedIndex, skipReasons, stickyBoostByAccount, pidOffsetEnabled, schedulingStrategy, } = params;
|
|
21
|
+
// Manual pin (from `codex-multi-auth switch <n>`) overrides every other
|
|
22
|
+
// selection signal. We do NOT call markSwitched here — the proxy must not
|
|
23
|
+
// clobber the pin set by the CLI. See issue #474.
|
|
24
|
+
if (typeof pinnedIndex === "number") {
|
|
25
|
+
if (attemptedIndexes.has(pinnedIndex)) {
|
|
26
|
+
skipReasons?.set(pinnedIndex, "already-attempted");
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (pinnedIndex < 0 || pinnedIndex >= accountManager.getAccountCount()) {
|
|
30
|
+
skipReasons?.set(pinnedIndex, "missing");
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (policy?.blockedAccountIndexes.has(pinnedIndex)) {
|
|
34
|
+
skipReasons?.set(pinnedIndex, "policy-blocked");
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const pinned = accountManager.getAccountByIndex(pinnedIndex);
|
|
38
|
+
if (!pinned || pinned.enabled === false) {
|
|
39
|
+
skipReasons?.set(pinnedIndex, "disabled");
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const reason = accountManager.getAccountRuntimeSkipReason(pinnedIndex, family, model);
|
|
43
|
+
if (reason) {
|
|
44
|
+
skipReasons?.set(pinnedIndex, reason);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return pinned;
|
|
48
|
+
}
|
|
49
|
+
// Sequential / drain-first mode (issue #509): the active account governs ALL
|
|
50
|
+
// new requests, so we deliberately SKIP the per-session affinity tier — there
|
|
51
|
+
// is no per-chat stickiness, every request follows the single active account.
|
|
52
|
+
// The manual pin above still wins (handled first). When the active account is
|
|
53
|
+
// exhausted the selector advances to the next available account and earlier
|
|
54
|
+
// accounts reclaim the slot once their quota recovers.
|
|
55
|
+
if (schedulingStrategy === "sequential") {
|
|
56
|
+
const selected = accountManager.getCurrentOrNextForFamilySequential(family, model, policy?.blockedAccountIndexes);
|
|
57
|
+
if (selected &&
|
|
58
|
+
!attemptedIndexes.has(selected.index) &&
|
|
59
|
+
!policy?.blockedAccountIndexes.has(selected.index)) {
|
|
60
|
+
const reason = accountManager.getAccountRuntimeSkipReason(selected.index, family, model);
|
|
61
|
+
if (!reason)
|
|
62
|
+
return selected;
|
|
63
|
+
skipReasons?.set(selected.index, reason);
|
|
64
|
+
}
|
|
65
|
+
// Active account was attempted/blocked/skipped this request (e.g. it just
|
|
66
|
+
// rate-limited mid-loop): fall through to the shared linear scan to find
|
|
67
|
+
// the next eligible account to TRY. Pass advanceActivePointer=false so a
|
|
68
|
+
// transient, non-exhausting failure on the active account does not
|
|
69
|
+
// permanently move the drain-first primary — only
|
|
70
|
+
// getCurrentOrNextForFamilySequential advances it, and only on true
|
|
71
|
+
// exhaustion.
|
|
72
|
+
return chooseLinearScanFallback({
|
|
73
|
+
accountManager,
|
|
74
|
+
family,
|
|
75
|
+
model,
|
|
76
|
+
attemptedIndexes,
|
|
77
|
+
policy,
|
|
78
|
+
skipReasons,
|
|
79
|
+
advanceActivePointer: false,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const preferredIndex = sessionAffinityStore?.getPreferredAccountIndex(sessionKey, now);
|
|
83
|
+
if (typeof preferredIndex === "number" &&
|
|
84
|
+
!attemptedIndexes.has(preferredIndex) &&
|
|
85
|
+
!policy?.blockedAccountIndexes.has(preferredIndex)) {
|
|
86
|
+
const preferred = accountManager.getAccountByIndex(preferredIndex);
|
|
87
|
+
if (preferred) {
|
|
88
|
+
const reason = accountManager.getAccountRuntimeSkipReason(preferred.index, family, model);
|
|
89
|
+
if (reason) {
|
|
90
|
+
skipReasons?.set(preferred.index, reason);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// L4 (deferred): unlocked cursor mutation — see chooseAccount header.
|
|
94
|
+
accountManager.markSwitched(preferred, "rotation", family);
|
|
95
|
+
return preferred;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const selected = accountManager.getCurrentOrNextForFamilyHybrid(family, model, {
|
|
100
|
+
scoreBoostByAccount: {
|
|
101
|
+
...(policy?.scoreBoostByAccount ?? {}),
|
|
102
|
+
...(stickyBoostByAccount ?? {}),
|
|
103
|
+
},
|
|
104
|
+
// accounts-05: carry the PID-offset distribution into the default-on proxy
|
|
105
|
+
// path too (index.ts already does). Without it, parallel proxy processes can
|
|
106
|
+
// stampede the same account instead of spreading across the pool.
|
|
107
|
+
pidOffsetEnabled,
|
|
108
|
+
});
|
|
109
|
+
if (selected &&
|
|
110
|
+
!attemptedIndexes.has(selected.index) &&
|
|
111
|
+
!policy?.blockedAccountIndexes.has(selected.index)) {
|
|
112
|
+
const reason = accountManager.getAccountRuntimeSkipReason(selected.index, family, model);
|
|
113
|
+
if (!reason)
|
|
114
|
+
return selected;
|
|
115
|
+
skipReasons?.set(selected.index, reason);
|
|
116
|
+
}
|
|
117
|
+
return chooseLinearScanFallback({
|
|
118
|
+
accountManager,
|
|
119
|
+
family,
|
|
120
|
+
model,
|
|
121
|
+
attemptedIndexes,
|
|
122
|
+
policy,
|
|
123
|
+
skipReasons,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Shared linear-scan fallback used by both the hybrid and sequential selection
|
|
128
|
+
* paths in `chooseAccount`. Walks every account in pool order and returns the
|
|
129
|
+
* first one that is not already attempted, not policy-blocked, and has no
|
|
130
|
+
* runtime skip reason (rate-limited / cooling down / circuit-open), recording a
|
|
131
|
+
* skip reason for each rejected candidate. Returns null when no eligible
|
|
132
|
+
* account remains.
|
|
133
|
+
*
|
|
134
|
+
* `advanceActivePointer` (default `true`) controls whether the winner is
|
|
135
|
+
* committed as the new active/cursor position via `markSwitched`. The hybrid
|
|
136
|
+
* path wants this (round-robin advance). The sequential path passes `false`:
|
|
137
|
+
* its within-request fallback only needs an account to TRY this request, and
|
|
138
|
+
* must NOT move `currentAccountIndexByFamily` — otherwise a transient,
|
|
139
|
+
* non-exhausting failure on the active account (which leaves it `isUsable` but
|
|
140
|
+
* present in `attemptedIndexes`) would permanently switch the drain-first
|
|
141
|
+
* primary even though it was never exhausted (issue #509 regression caught in
|
|
142
|
+
* review). In sequential mode only `getCurrentOrNextForFamilySequential` is
|
|
143
|
+
* allowed to advance the active pointer, and only on true exhaustion.
|
|
144
|
+
*/
|
|
145
|
+
function chooseLinearScanFallback(params) {
|
|
146
|
+
const { accountManager, family, model, attemptedIndexes, policy, skipReasons, advanceActivePointer = true, } = params;
|
|
147
|
+
for (const account of accountManager.getAccountsSnapshot()) {
|
|
148
|
+
if (attemptedIndexes.has(account.index)) {
|
|
149
|
+
skipReasons?.set(account.index, "already-attempted");
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (policy?.blockedAccountIndexes.has(account.index)) {
|
|
153
|
+
skipReasons?.set(account.index, "policy-blocked");
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const reason = accountManager.getAccountRuntimeSkipReason(account.index, family, model);
|
|
157
|
+
if (!reason) {
|
|
158
|
+
const live = accountManager.getAccountByIndex(account.index);
|
|
159
|
+
if (!live)
|
|
160
|
+
continue;
|
|
161
|
+
// L4 (deferred): unlocked cursor mutation — see chooseAccount header.
|
|
162
|
+
// Skipped in sequential mode (advanceActivePointer=false) so a
|
|
163
|
+
// within-request retry never reassigns the drain-first primary.
|
|
164
|
+
if (advanceActivePointer) {
|
|
165
|
+
accountManager.markSwitched(live, "rotation", family);
|
|
166
|
+
}
|
|
167
|
+
return live;
|
|
168
|
+
}
|
|
169
|
+
skipReasons?.set(account.index, reason);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AccountManager } from "../accounts.js";
|
|
2
|
+
import type { RuntimeRotationProxyStatus } from "./rotation-server-types.js";
|
|
3
|
+
import type { SessionAffinityStore } from "../session-affinity.js";
|
|
4
|
+
/**
|
|
5
|
+
* Per-instance configuration resolved once in `startRuntimeRotationProxy`,
|
|
6
|
+
* captured as explicit fields instead of closure variables so the request
|
|
7
|
+
* handler and the stale-reload recovery can be plain functions.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface RotationProxyStateInit {
|
|
12
|
+
activeAccountManager: AccountManager;
|
|
13
|
+
routingMutexMode: "enabled" | "legacy";
|
|
14
|
+
schedulingStrategy: "hybrid" | "sequential";
|
|
15
|
+
fetchImpl: typeof fetch;
|
|
16
|
+
upstreamBaseUrl: string;
|
|
17
|
+
clientApiKey: string;
|
|
18
|
+
now: () => number;
|
|
19
|
+
tokenRefreshSkewMs: number;
|
|
20
|
+
networkErrorCooldownMs: number;
|
|
21
|
+
serverErrorCooldownMs: number;
|
|
22
|
+
tokenInvalidationCooldownMs: number;
|
|
23
|
+
minRotationIntervalMs: number;
|
|
24
|
+
pidOffsetEnabled: boolean;
|
|
25
|
+
fetchTimeoutMs: number;
|
|
26
|
+
streamStallTimeoutMs: number;
|
|
27
|
+
maxRuntimeAccountAttempts: number;
|
|
28
|
+
maxRequestBodyBytes: number;
|
|
29
|
+
quotaRemainingPercentThreshold: number;
|
|
30
|
+
sessionAffinityStore: SessionAffinityStore | null;
|
|
31
|
+
lastObservedAffinityGeneration: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Mutable rotation-loop state shared by every request of one proxy instance.
|
|
35
|
+
* `activeAccountManager` and `lastObservedAffinityGeneration` are reassigned
|
|
36
|
+
* at runtime (stale-state recovery and affinity-generation tracking), so the
|
|
37
|
+
* whole container is passed by reference and never copied.
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export interface RotationProxyState extends RotationProxyStateInit {
|
|
42
|
+
readonly knownAccountManagers: Set<AccountManager>;
|
|
43
|
+
readonly status: RuntimeRotationProxyStatus;
|
|
44
|
+
readonly threadGoalFallbacks: Map<string, string | null>;
|
|
45
|
+
lastGlobalAccountIndex: number | null;
|
|
46
|
+
lastGlobalSwitchAt: number;
|
|
47
|
+
staleRuntimeReloadPromise: Promise<AccountManager | null> | null;
|
|
48
|
+
lastStaleRuntimeReloadAt: number;
|
|
49
|
+
}
|
|
50
|
+
/** @internal */
|
|
51
|
+
export declare function createRotationProxyState(init: RotationProxyStateInit): RotationProxyState;
|
|
52
|
+
/** @internal */
|
|
53
|
+
export declare function recoverStaleRuntimeState(state: RotationProxyState): Promise<AccountManager | null>;
|
|
54
|
+
//# sourceMappingURL=rotation-proxy-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-proxy-state.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-proxy-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,EAAE,cAAc,CAAC;IACrC,gBAAgB,EAAE,SAAS,GAAG,QAAQ,CAAC;IACvC,kBAAkB,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC5C,SAAS,EAAE,OAAO,KAAK,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;IACpC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,yBAAyB,EAAE,MAAM,CAAC;IAClC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,8BAA8B,EAAE,MAAM,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,8BAA8B,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,yBAAyB,EAAE,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACjE,wBAAwB,EAAE,MAAM,CAAC;CACjC;AAID,gBAAgB;AAChB,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,sBAAsB,GAC1B,kBAAkB,CAuBpB;AAED,gBAAgB;AAChB,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,kBAAkB,GACvB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AccountManager } from "../accounts.js";
|
|
2
|
+
import { recordRuntimeReload, recordRuntimeReset, } from "./runtime-observability.js";
|
|
3
|
+
const STALE_RUNTIME_RELOAD_DEDUPE_MS = 1_000;
|
|
4
|
+
/** @internal */
|
|
5
|
+
export function createRotationProxyState(init) {
|
|
6
|
+
return {
|
|
7
|
+
...init,
|
|
8
|
+
knownAccountManagers: new Set([init.activeAccountManager]),
|
|
9
|
+
status: {
|
|
10
|
+
startedAt: init.now(),
|
|
11
|
+
totalRequests: 0,
|
|
12
|
+
upstreamRequests: 0,
|
|
13
|
+
retries: 0,
|
|
14
|
+
rotations: 0,
|
|
15
|
+
streamsStarted: 0,
|
|
16
|
+
lastError: null,
|
|
17
|
+
lastAccountIndex: null,
|
|
18
|
+
lastAccountLabel: null,
|
|
19
|
+
lastAccountId: null,
|
|
20
|
+
lastAccountUpdatedAt: null,
|
|
21
|
+
},
|
|
22
|
+
threadGoalFallbacks: new Map(),
|
|
23
|
+
lastGlobalAccountIndex: null,
|
|
24
|
+
lastGlobalSwitchAt: 0,
|
|
25
|
+
staleRuntimeReloadPromise: null,
|
|
26
|
+
lastStaleRuntimeReloadAt: 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** @internal */
|
|
30
|
+
export async function recoverStaleRuntimeState(state) {
|
|
31
|
+
if (Date.now() - state.lastStaleRuntimeReloadAt <= STALE_RUNTIME_RELOAD_DEDUPE_MS) {
|
|
32
|
+
return state.activeAccountManager;
|
|
33
|
+
}
|
|
34
|
+
if (state.staleRuntimeReloadPromise) {
|
|
35
|
+
return state.staleRuntimeReloadPromise;
|
|
36
|
+
}
|
|
37
|
+
state.staleRuntimeReloadPromise = (async () => {
|
|
38
|
+
AccountManager.resetVolatileRuntimeState();
|
|
39
|
+
recordRuntimeReset("pool-exhausted-no-account");
|
|
40
|
+
const reloaded = await AccountManager.loadFromDisk();
|
|
41
|
+
reloaded.setRoutingMutexMode(state.routingMutexMode);
|
|
42
|
+
state.activeAccountManager = reloaded;
|
|
43
|
+
state.knownAccountManagers.add(reloaded);
|
|
44
|
+
state.lastStaleRuntimeReloadAt = Date.now();
|
|
45
|
+
recordRuntimeReload("pool-exhausted-no-account");
|
|
46
|
+
return reloaded;
|
|
47
|
+
})()
|
|
48
|
+
.catch((error) => {
|
|
49
|
+
state.status.lastError = error instanceof Error ? error.message : String(error);
|
|
50
|
+
return null;
|
|
51
|
+
})
|
|
52
|
+
.finally(() => {
|
|
53
|
+
state.staleRuntimeReloadPromise = null;
|
|
54
|
+
});
|
|
55
|
+
return state.staleRuntimeReloadPromise;
|
|
56
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { AccountManager } from "../accounts.js";
|
|
2
|
+
import type { ModelFamily } from "../prompts/codex.js";
|
|
3
|
+
export interface RuntimeRotationProxyServer {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
close: () => Promise<void>;
|
|
8
|
+
getStatus: () => RuntimeRotationProxyStatus;
|
|
9
|
+
}
|
|
10
|
+
export interface RuntimeRotationProxyStatus {
|
|
11
|
+
startedAt: number;
|
|
12
|
+
totalRequests: number;
|
|
13
|
+
upstreamRequests: number;
|
|
14
|
+
retries: number;
|
|
15
|
+
rotations: number;
|
|
16
|
+
streamsStarted: number;
|
|
17
|
+
lastError: string | null;
|
|
18
|
+
lastAccountIndex: number | null;
|
|
19
|
+
lastAccountLabel: string | null;
|
|
20
|
+
lastAccountId: string | null;
|
|
21
|
+
lastAccountUpdatedAt: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface RuntimeRotationProxyOptions {
|
|
24
|
+
host?: string;
|
|
25
|
+
port?: number;
|
|
26
|
+
upstreamBaseUrl?: string;
|
|
27
|
+
clientApiKey: string;
|
|
28
|
+
accountManager?: AccountManager;
|
|
29
|
+
fetchImpl?: typeof fetch;
|
|
30
|
+
now?: () => number;
|
|
31
|
+
quotaRemainingPercentThreshold?: number;
|
|
32
|
+
maxRequestBodyBytes?: number;
|
|
33
|
+
fetchTimeoutMs?: number;
|
|
34
|
+
streamStallTimeoutMs?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface RequestContext {
|
|
37
|
+
body: Buffer;
|
|
38
|
+
headers: Headers;
|
|
39
|
+
method: "GET" | "POST";
|
|
40
|
+
upstreamPath: string;
|
|
41
|
+
model: string | null;
|
|
42
|
+
family: ModelFamily;
|
|
43
|
+
stream: boolean;
|
|
44
|
+
sessionKey: string | null;
|
|
45
|
+
}
|
|
46
|
+
export type ExhaustionReason = "rate-limit" | "server-error" | "network-error" | "auth-failure" | "budget" | "deactivated" | "no-account";
|
|
47
|
+
export type RuntimeProxyHttpError = Error & {
|
|
48
|
+
statusCode: number;
|
|
49
|
+
code: string;
|
|
50
|
+
};
|
|
51
|
+
export interface RuntimeRotationAccountIdentity {
|
|
52
|
+
index: number;
|
|
53
|
+
label: string;
|
|
54
|
+
accountId: string | null;
|
|
55
|
+
updatedAt: number;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=rotation-server-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-server-types.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-server-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,SAAS,EAAE,MAAM,0BAA0B,CAAC;CAC5C;AAED,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,2BAA2B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,gBAAgB,GACzB,YAAY,GACZ,cAAc,GACd,eAAe,GACf,cAAc,GACd,QAAQ,GACR,aAAa,GACb,YAAY,CAAC;AAChB,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SessionAffinityStore } from "../session-affinity.js";
|
|
2
|
+
export interface StorageMeta {
|
|
3
|
+
pinnedAccountIndex: number | null;
|
|
4
|
+
affinityGeneration: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Cheap, hot-path-safe single read with mtime-cache short-circuit. When the
|
|
8
|
+
* file's `mtimeMs` and `size` match the cached snapshot for this path we
|
|
9
|
+
* return the cached value WITHOUT reading or hashing the file. Only when
|
|
10
|
+
* mtime/size differ (or were never cached) do we `readFileSync` + sha1 and,
|
|
11
|
+
* if the content hash still matches, skip the `JSON.parse`. Transient
|
|
12
|
+
* failures (EBUSY/EPERM/EACCES/EAGAIN, partial-write SyntaxError) fall through
|
|
13
|
+
* to the last cached value for this path; defaults are only returned when the
|
|
14
|
+
* file has never been successfully read.
|
|
15
|
+
*
|
|
16
|
+
* Replaces an earlier retry loop with a sub-15ms busy-wait that blocked the
|
|
17
|
+
* event loop on every transient failure. The proxy is on the request hot
|
|
18
|
+
* path; serving a slightly stale (but consistent) value is strictly better
|
|
19
|
+
* than blocking. See #474.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readStorageMetaFromDisk(storagePath?: string): StorageMeta;
|
|
22
|
+
/**
|
|
23
|
+
* Backwards-compatible helper retained for tests. Prefer `readStorageMetaFromDisk`
|
|
24
|
+
* for new callers that also need `affinityGeneration`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readPinnedAccountIndexFromDisk(storagePath?: string): number | null;
|
|
27
|
+
/**
|
|
28
|
+
* Test-only: reset the storage-meta content-hash cache between scenarios so
|
|
29
|
+
* each test starts from a clean read-from-disk state.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resetPinCacheForTesting(): void;
|
|
32
|
+
/**
|
|
33
|
+
* If the on-disk `affinityGeneration` is greater than `lastObservedGeneration`,
|
|
34
|
+
* drop every entry in `sessionAffinityStore` and return the new generation so
|
|
35
|
+
* the caller can update its tracker. Otherwise returns `lastObservedGeneration`
|
|
36
|
+
* unchanged. Extracted so the request-flow logic can be unit-tested without
|
|
37
|
+
* spinning up the full proxy. See issue #474.
|
|
38
|
+
*/
|
|
39
|
+
export declare function maybeInvalidateAffinityFromDisk(sessionAffinityStore: SessionAffinityStore | null, lastObservedGeneration: number, storagePath?: string): number;
|
|
40
|
+
//# sourceMappingURL=rotation-storage-meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-storage-meta.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-storage-meta.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAqCnE,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AA8BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,WAAW,GAAE,MAAyB,GACpC,WAAW,CA6Eb;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,WAAW,GAAE,MAAyB,GACpC,MAAM,GAAG,IAAI,CAEf;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC9C,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,EACjD,sBAAsB,EAAE,MAAM,EAC9B,WAAW,GAAE,MAAyB,GACpC,MAAM,CAOR"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { getStoragePath } from "../storage.js";
|
|
4
|
+
// Keyed by absolute storage path so multiple proxy instances and concurrent
|
|
5
|
+
// vitest workers (each pointing at their own temp storage file) cannot
|
|
6
|
+
// corrupt each other's snapshots. See issue #474.
|
|
7
|
+
const STORAGE_META_CACHE = new Map();
|
|
8
|
+
// The mtime+size short-circuit (L3) may only be trusted once the cached
|
|
9
|
+
// mtime is far enough in the past that no *subsequent* write could share the
|
|
10
|
+
// same coarse mtime tick. Filesystems report mtime at wildly different
|
|
11
|
+
// granularities (ext4 ns, FAT 2s, some network/Windows volumes ~1s, and CI
|
|
12
|
+
// containers occasionally coarser), and our writers use atomic rename, so two
|
|
13
|
+
// rapid CLI bumps can land on an identical mtimeMs. Within this settle window
|
|
14
|
+
// we therefore ignore mtime equality and fall back to the read + sha1 path
|
|
15
|
+
// (the real source of truth). Outside it, the file has been quiescent long
|
|
16
|
+
// enough that mtime equality provably means "unchanged", so we skip the read.
|
|
17
|
+
// 2s comfortably exceeds the coarsest mtime granularity we expect in practice.
|
|
18
|
+
const MTIME_SHORTCIRCUIT_SETTLE_MS = 2_000;
|
|
19
|
+
function hashStorageBytes(bytes) {
|
|
20
|
+
return createHash("sha1").update(bytes).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
function metaFromSnapshot(snapshot) {
|
|
23
|
+
return {
|
|
24
|
+
pinnedAccountIndex: snapshot.pinnedAccountIndex,
|
|
25
|
+
affinityGeneration: snapshot.affinityGeneration,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Cheap, hot-path-safe single read with mtime-cache short-circuit. When the
|
|
30
|
+
* file's `mtimeMs` and `size` match the cached snapshot for this path we
|
|
31
|
+
* return the cached value WITHOUT reading or hashing the file. Only when
|
|
32
|
+
* mtime/size differ (or were never cached) do we `readFileSync` + sha1 and,
|
|
33
|
+
* if the content hash still matches, skip the `JSON.parse`. Transient
|
|
34
|
+
* failures (EBUSY/EPERM/EACCES/EAGAIN, partial-write SyntaxError) fall through
|
|
35
|
+
* to the last cached value for this path; defaults are only returned when the
|
|
36
|
+
* file has never been successfully read.
|
|
37
|
+
*
|
|
38
|
+
* Replaces an earlier retry loop with a sub-15ms busy-wait that blocked the
|
|
39
|
+
* event loop on every transient failure. The proxy is on the request hot
|
|
40
|
+
* path; serving a slightly stale (but consistent) value is strictly better
|
|
41
|
+
* than blocking. See #474.
|
|
42
|
+
*/
|
|
43
|
+
export function readStorageMetaFromDisk(storagePath = getStoragePath()) {
|
|
44
|
+
if (!existsSync(storagePath)) {
|
|
45
|
+
STORAGE_META_CACHE.delete(storagePath);
|
|
46
|
+
return { pinnedAccountIndex: null, affinityGeneration: 0 };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
// mtime+size short-circuit (L3): when neither has changed since the last
|
|
50
|
+
// successful read AND the cached mtime has settled (see
|
|
51
|
+
// MTIME_SHORTCIRCUIT_SETTLE_MS) we return the cached snapshot without
|
|
52
|
+
// reading or hashing the file. During the settle window we deliberately
|
|
53
|
+
// fall through to the read + sha1 path below, which stays the source of
|
|
54
|
+
// truth and protects against the coarse-mtime collision described on
|
|
55
|
+
// StorageMetaSnapshot. So this is a pure fast path for the common
|
|
56
|
+
// "file quiescent, proxy polling every request" case.
|
|
57
|
+
const stats = statSync(storagePath);
|
|
58
|
+
const cachedByStat = STORAGE_META_CACHE.get(storagePath);
|
|
59
|
+
if (cachedByStat &&
|
|
60
|
+
cachedByStat.mtimeMs === stats.mtimeMs &&
|
|
61
|
+
cachedByStat.size === stats.size &&
|
|
62
|
+
Date.now() - stats.mtimeMs > MTIME_SHORTCIRCUIT_SETTLE_MS) {
|
|
63
|
+
return metaFromSnapshot(cachedByStat);
|
|
64
|
+
}
|
|
65
|
+
const bytes = readFileSync(storagePath);
|
|
66
|
+
const contentHash = hashStorageBytes(bytes);
|
|
67
|
+
const cached = STORAGE_META_CACHE.get(storagePath);
|
|
68
|
+
if (cached && cached.contentHash === contentHash) {
|
|
69
|
+
// Content is byte-identical despite the mtime/size change (e.g. an
|
|
70
|
+
// atomic-rename rewrite of the same bytes). Refresh the stat fields so
|
|
71
|
+
// the next request takes the fast path, but skip the JSON.parse.
|
|
72
|
+
const refreshed = {
|
|
73
|
+
...cached,
|
|
74
|
+
mtimeMs: stats.mtimeMs,
|
|
75
|
+
size: stats.size,
|
|
76
|
+
};
|
|
77
|
+
STORAGE_META_CACHE.set(storagePath, refreshed);
|
|
78
|
+
return metaFromSnapshot(refreshed);
|
|
79
|
+
}
|
|
80
|
+
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
81
|
+
const pinnedAccountIndex = typeof parsed.pinnedAccountIndex === "number" &&
|
|
82
|
+
Number.isFinite(parsed.pinnedAccountIndex)
|
|
83
|
+
? Math.trunc(parsed.pinnedAccountIndex)
|
|
84
|
+
: null;
|
|
85
|
+
const affinityGeneration = typeof parsed.affinityGeneration === "number" &&
|
|
86
|
+
Number.isFinite(parsed.affinityGeneration) &&
|
|
87
|
+
Number.isInteger(parsed.affinityGeneration) &&
|
|
88
|
+
parsed.affinityGeneration >= 0
|
|
89
|
+
? parsed.affinityGeneration
|
|
90
|
+
: 0;
|
|
91
|
+
const snapshot = {
|
|
92
|
+
mtimeMs: stats.mtimeMs,
|
|
93
|
+
size: stats.size,
|
|
94
|
+
contentHash,
|
|
95
|
+
pinnedAccountIndex,
|
|
96
|
+
affinityGeneration,
|
|
97
|
+
};
|
|
98
|
+
STORAGE_META_CACHE.set(storagePath, snapshot);
|
|
99
|
+
return { pinnedAccountIndex, affinityGeneration };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
// On any failure, prefer the last good snapshot for this path so we
|
|
103
|
+
// don't blow away affinity unnecessarily. Defensive: even non-transient
|
|
104
|
+
// errors fall back to the cache when one exists — better stale than
|
|
105
|
+
// wrong. Defaults are only returned when this file has never been read
|
|
106
|
+
// successfully (cache miss).
|
|
107
|
+
void error;
|
|
108
|
+
const cached = STORAGE_META_CACHE.get(storagePath);
|
|
109
|
+
if (cached) {
|
|
110
|
+
return metaFromSnapshot(cached);
|
|
111
|
+
}
|
|
112
|
+
return { pinnedAccountIndex: null, affinityGeneration: 0 };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Backwards-compatible helper retained for tests. Prefer `readStorageMetaFromDisk`
|
|
117
|
+
* for new callers that also need `affinityGeneration`.
|
|
118
|
+
*/
|
|
119
|
+
export function readPinnedAccountIndexFromDisk(storagePath = getStoragePath()) {
|
|
120
|
+
return readStorageMetaFromDisk(storagePath).pinnedAccountIndex;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Test-only: reset the storage-meta content-hash cache between scenarios so
|
|
124
|
+
* each test starts from a clean read-from-disk state.
|
|
125
|
+
*/
|
|
126
|
+
export function resetPinCacheForTesting() {
|
|
127
|
+
STORAGE_META_CACHE.clear();
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* If the on-disk `affinityGeneration` is greater than `lastObservedGeneration`,
|
|
131
|
+
* drop every entry in `sessionAffinityStore` and return the new generation so
|
|
132
|
+
* the caller can update its tracker. Otherwise returns `lastObservedGeneration`
|
|
133
|
+
* unchanged. Extracted so the request-flow logic can be unit-tested without
|
|
134
|
+
* spinning up the full proxy. See issue #474.
|
|
135
|
+
*/
|
|
136
|
+
export function maybeInvalidateAffinityFromDisk(sessionAffinityStore, lastObservedGeneration, storagePath = getStoragePath()) {
|
|
137
|
+
const meta = readStorageMetaFromDisk(storagePath);
|
|
138
|
+
if (meta.affinityGeneration > lastObservedGeneration) {
|
|
139
|
+
sessionAffinityStore?.clearAll();
|
|
140
|
+
return meta.affinityGeneration;
|
|
141
|
+
}
|
|
142
|
+
return lastObservedGeneration;
|
|
143
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AccountManager, ManagedAccount } from "../accounts.js";
|
|
2
|
+
import type { ModelFamily } from "../prompts/codex.js";
|
|
3
|
+
/** @internal */
|
|
4
|
+
export declare const DEFAULT_AUTH_FAILURE_COOLDOWN_MS = 30000;
|
|
5
|
+
/** @internal */
|
|
6
|
+
export declare function applyMonotonicAuthCooldown(accountManager: AccountManager, account: ManagedAccount, cooldownMs: number): void;
|
|
7
|
+
/** @internal */
|
|
8
|
+
export declare function ensureFreshAccessToken(params: {
|
|
9
|
+
accountManager: AccountManager;
|
|
10
|
+
account: ManagedAccount;
|
|
11
|
+
family: ModelFamily;
|
|
12
|
+
model: string | null;
|
|
13
|
+
now: number;
|
|
14
|
+
tokenRefreshSkewMs: number;
|
|
15
|
+
tokenInvalidationCooldownMs: number;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
ok: true;
|
|
18
|
+
accessToken: string;
|
|
19
|
+
account: ManagedAccount;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
retryable: boolean;
|
|
23
|
+
invalidated?: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
//# sourceMappingURL=rotation-token-refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-token-refresh.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-token-refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAQvD,gBAAgB;AAChB,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAMvD,gBAAgB;AAChB,wBAAgB,0BAA0B,CACzC,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,GAChB,IAAI,CAUN;AA6CD,gBAAgB;AAChB,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACpD,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2BAA2B,EAAE,MAAM,CAAC;CACpC,GAAG,OAAO,CACR;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC1D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAC1D,CAgEA"}
|