codex-multi-auth 2.12.0 → 2.14.0
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 +1 -1
- package/README.md +10 -1
- package/dist/lib/accounts.d.ts +75 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +213 -42
- package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/account-manager-commands.js +1 -0
- package/dist/lib/codex-manager/commands/limits.d.ts +21 -0
- package/dist/lib/codex-manager/commands/limits.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/limits.js +158 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +1 -0
- package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
- package/dist/lib/codex-manager/persist-selected-account.js +14 -0
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +12 -0
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +1 -14
- package/dist/lib/preemptive-quota-scheduler.d.ts +12 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
- package/dist/lib/preemptive-quota-scheduler.js +21 -0
- package/dist/lib/redaction.d.ts +17 -0
- package/dist/lib/redaction.d.ts.map +1 -0
- package/dist/lib/redaction.js +28 -0
- package/dist/lib/request/error-classification.d.ts +13 -6
- package/dist/lib/request/error-classification.d.ts.map +1 -1
- package/dist/lib/request/error-classification.js +45 -0
- package/dist/lib/request/fetch-helpers.d.ts +1 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +1 -1
- package/dist/lib/runtime/rotation-proxy-state.d.ts +6 -0
- package/dist/lib/runtime/rotation-proxy-state.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-server-types.d.ts +7 -0
- package/dist/lib/runtime/rotation-server-types.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-storage-meta.js +4 -1
- package/dist/lib/runtime-rotation-proxy.d.ts +23 -0
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +237 -13
- package/dist/lib/storage.d.ts +20 -2
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +69 -25
- package/package.json +1 -1
- package/scripts/codex-routing.js +1 -0
- package/scripts/codex.js +157 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { formatAccountLabel } from "../../accounts.js";
|
|
2
|
+
import { MODEL_FAMILIES } from "../../prompts/codex.js";
|
|
3
|
+
import { findQuotaCacheEntryForAccount } from "../../quota-readiness.js";
|
|
4
|
+
import { redactEmails } from "../../redaction.js";
|
|
5
|
+
const LIMITS_SCHEMA_VERSION = 1;
|
|
6
|
+
const LIMITS_REFRESH_MAX_AGE_MS = 5 * 60_000;
|
|
7
|
+
const LIMITS_USAGE = "Usage: codex-multi-auth limits --json [--refresh]";
|
|
8
|
+
/** Parse the intentionally small, JSON-only limits command surface. */
|
|
9
|
+
function parseLimitsOptions(args) {
|
|
10
|
+
const options = { json: false, refresh: false, help: false };
|
|
11
|
+
for (const arg of args) {
|
|
12
|
+
if (arg === "--json" || arg === "-j") {
|
|
13
|
+
options.json = true;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (arg === "--refresh") {
|
|
17
|
+
options.refresh = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (arg === "--help" || arg === "-h") {
|
|
21
|
+
options.help = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
return { ok: false, message: `Unknown limits option: ${arg}` };
|
|
25
|
+
}
|
|
26
|
+
if (!options.json && !options.help) {
|
|
27
|
+
return { ok: false, message: LIMITS_USAGE };
|
|
28
|
+
}
|
|
29
|
+
return { ok: true, options };
|
|
30
|
+
}
|
|
31
|
+
/** Convert a cached quota window to the explicit-null public JSON contract. */
|
|
32
|
+
function publicWindow(window) {
|
|
33
|
+
return {
|
|
34
|
+
usedPercent: window.usedPercent ?? null,
|
|
35
|
+
windowMinutes: window.windowMinutes ?? null,
|
|
36
|
+
resetAtMs: window.resetAtMs ?? null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** Remove internal probe metadata and stabilize optional quota fields. */
|
|
40
|
+
function publicQuotaEntry(entry) {
|
|
41
|
+
return {
|
|
42
|
+
updatedAt: entry.updatedAt,
|
|
43
|
+
status: entry.status,
|
|
44
|
+
planType: entry.planType ?? null,
|
|
45
|
+
primary: publicWindow(entry.primary),
|
|
46
|
+
secondary: publicWindow(entry.secondary),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Emit configured accounts joined to safe cached quota records.
|
|
51
|
+
*
|
|
52
|
+
* Cached mode performs no provider requests. Refresh mode delegates to the
|
|
53
|
+
* existing sequential, age-gated refresh path before serializing the snapshot.
|
|
54
|
+
*/
|
|
55
|
+
export async function runLimitsCommand(args, deps) {
|
|
56
|
+
const parsed = parseLimitsOptions(args);
|
|
57
|
+
const logInfo = deps.logInfo ?? console.log;
|
|
58
|
+
const logError = deps.logError ?? console.error;
|
|
59
|
+
if (!parsed.ok) {
|
|
60
|
+
logError(parsed.message);
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
if (parsed.options.help) {
|
|
64
|
+
logInfo(LIMITS_USAGE);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
deps.setStoragePath(null);
|
|
68
|
+
const storage = await deps.loadAccounts();
|
|
69
|
+
if (!storage || storage.accounts.length === 0) {
|
|
70
|
+
const generatedAt = deps.getNow?.() ?? Date.now();
|
|
71
|
+
logInfo(JSON.stringify({
|
|
72
|
+
schemaVersion: LIMITS_SCHEMA_VERSION,
|
|
73
|
+
generatedAt,
|
|
74
|
+
mode: parsed.options.refresh ? "refresh" : "cached",
|
|
75
|
+
// Keep the key set identical for an empty pool so a consumer
|
|
76
|
+
// never has to branch on its presence. There is no account to
|
|
77
|
+
// route to, so `routedIndex` is null rather than a positional 0
|
|
78
|
+
// that addresses nothing.
|
|
79
|
+
selection: {
|
|
80
|
+
pinnedIndex: null,
|
|
81
|
+
routedIndex: null,
|
|
82
|
+
activeIndexByFamily: {},
|
|
83
|
+
},
|
|
84
|
+
accounts: [],
|
|
85
|
+
}, null, 2));
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
let cache = await deps.loadQuotaCache();
|
|
89
|
+
if (parsed.options.refresh) {
|
|
90
|
+
cache = await deps.refreshQuotaCache(storage, cache, LIMITS_REFRESH_MAX_AGE_MS);
|
|
91
|
+
}
|
|
92
|
+
const generatedAt = deps.getNow?.() ?? Date.now();
|
|
93
|
+
const selection = resolveSelection(storage, deps.resolveActiveIndex);
|
|
94
|
+
const accounts = storage.accounts.map((account, index) => {
|
|
95
|
+
const quota = findQuotaCacheEntryForAccount(cache, account, storage.accounts);
|
|
96
|
+
return {
|
|
97
|
+
index,
|
|
98
|
+
// Labels are built from the account email. Mask it, exactly as
|
|
99
|
+
// `forecast --json` already does, so a snapshot written to a log
|
|
100
|
+
// shipper or a ticket does not carry the address.
|
|
101
|
+
label: redactEmails(formatAccountLabel(account, index)),
|
|
102
|
+
enabled: account.enabled !== false,
|
|
103
|
+
current: index === selection.routedIndex,
|
|
104
|
+
quota: quota ? publicQuotaEntry(quota) : null,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
logInfo(JSON.stringify({
|
|
108
|
+
schemaVersion: LIMITS_SCHEMA_VERSION,
|
|
109
|
+
generatedAt,
|
|
110
|
+
mode: parsed.options.refresh ? "refresh" : "cached",
|
|
111
|
+
selection,
|
|
112
|
+
accounts,
|
|
113
|
+
}, null, 2));
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The CONFIGURED routing target, and the state that decides it.
|
|
118
|
+
*
|
|
119
|
+
* `current` cannot be `activeIndexByFamily.codex` alone. The runtime proxy
|
|
120
|
+
* routes on `pinnedAccountIndex` whenever a `switch` pin is set, and flows that
|
|
121
|
+
* move the active index without touching the pin (rotation saves, `unpin`, an
|
|
122
|
+
* ephemeral `--account`) would otherwise leave `current: true` on a row that is
|
|
123
|
+
* not the configured target. Both inputs are emitted so a consumer can tell
|
|
124
|
+
* which one applied, and the per-family map is emitted because a pool can hold
|
|
125
|
+
* a different active index per family.
|
|
126
|
+
*
|
|
127
|
+
* This is deliberately NOT a prediction of which account the next request
|
|
128
|
+
* lands on. The proxy skips an account that is disabled, inside a rate-limit
|
|
129
|
+
* window, cooling down, or behind an open circuit breaker, and it applies
|
|
130
|
+
* session affinity and an ephemeral `--account` override that never touch
|
|
131
|
+
* storage. Reproducing that here would mean a third copy of the selector
|
|
132
|
+
* (`why-selected` and `forecast` already own live selection), and a snapshot
|
|
133
|
+
* read from a cache cannot be authoritative about it in any case. Consumers
|
|
134
|
+
* that need liveness have `enabled` on every row and `why-selected --json`.
|
|
135
|
+
*
|
|
136
|
+
* `routedIndex` is null only for an empty pool, where no row is `current`.
|
|
137
|
+
*/
|
|
138
|
+
function resolveSelection(storage, resolveActiveIndex) {
|
|
139
|
+
if (storage.accounts.length === 0) {
|
|
140
|
+
return { pinnedIndex: null, routedIndex: null, activeIndexByFamily: {} };
|
|
141
|
+
}
|
|
142
|
+
const activeIndexByFamily = {};
|
|
143
|
+
for (const family of MODEL_FAMILIES) {
|
|
144
|
+
activeIndexByFamily[family] = resolveActiveIndex(storage, family);
|
|
145
|
+
}
|
|
146
|
+
const rawPin = storage.pinnedAccountIndex;
|
|
147
|
+
const pinnedIndex = typeof rawPin === "number" &&
|
|
148
|
+
Number.isInteger(rawPin) &&
|
|
149
|
+
rawPin >= 0 &&
|
|
150
|
+
rawPin < storage.accounts.length
|
|
151
|
+
? rawPin
|
|
152
|
+
: null;
|
|
153
|
+
return {
|
|
154
|
+
pinnedIndex,
|
|
155
|
+
routedIndex: pinnedIndex ?? activeIndexByFamily.codex ?? 0,
|
|
156
|
+
activeIndexByFamily,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/help.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/help.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,IAAI,CAuDjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAuGtE;AAED,UAAU,cAAc;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,cAAc,IAAI,IAAI,CAgBrC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAyD5D"}
|
|
@@ -8,6 +8,7 @@ export function printUsage() {
|
|
|
8
8
|
" codex-multi-auth login [--device-auth|--manual|--no-browser] [--org <org_id>] [--preserve-selection] [--account <index|email|account_id>]",
|
|
9
9
|
" codex-multi-auth status [--json] (list is the same command)",
|
|
10
10
|
" codex-multi-auth check (always live-probes)",
|
|
11
|
+
" codex-multi-auth limits --json [--refresh] (structured quota windows; refresh is age-gated)",
|
|
11
12
|
"",
|
|
12
13
|
"Daily use:",
|
|
13
14
|
" codex-multi-auth list [--json]",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist-selected-account.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/persist-selected-account.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACN,KAAK,gBAAgB,EAIrB,MAAM,eAAe,CAAC;AAQvB;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CAAC,EACnD,OAAO,EACP,WAAW,EACX,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,2BAAmC,EACnC,MAAc,EACd,QAAgB,EAChB,sBAA8B,GAC9B,EAAE;IACF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"persist-selected-account.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/persist-selected-account.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACN,KAAK,gBAAgB,EAIrB,MAAM,eAAe,CAAC;AAQvB;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CAAC,EACnD,OAAO,EACP,WAAW,EACX,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,2BAAmC,EACnC,MAAc,EACd,QAAgB,EAChB,sBAA8B,GAC9B,EAAE;IACF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAmHrD"}
|
|
@@ -77,6 +77,20 @@ export async function persistAndSyncSelectedAccount({ storage, targetIndex, pars
|
|
|
77
77
|
account.lastSwitchReason = switchReason;
|
|
78
78
|
if (setPin) {
|
|
79
79
|
storage.pinnedAccountIndex = targetIndex;
|
|
80
|
+
// A manual switch requests a fresh upstream attempt, including when
|
|
81
|
+
// reselecting the same account after an out-of-band quota reset. Real 429
|
|
82
|
+
// responses will populate these markers again.
|
|
83
|
+
//
|
|
84
|
+
// `setPin` is the right trigger because it is set only by `switch` (which
|
|
85
|
+
// the login dashboard's account picker also routes through), i.e. exactly
|
|
86
|
+
// the paths where a person picked this account. `best` passes `clearPin`
|
|
87
|
+
// and a backup restore passes neither, and neither of those is a request
|
|
88
|
+
// to revalidate a rate-limited account.
|
|
89
|
+
//
|
|
90
|
+
// Delete rather than assign `{}`: `AccountManager.buildStorageSnapshot`
|
|
91
|
+
// omits the field when the map is empty, so assigning would persist a
|
|
92
|
+
// second on-disk shape for the same state.
|
|
93
|
+
delete account.rateLimitResetTimes;
|
|
80
94
|
}
|
|
81
95
|
else if (clearPin) {
|
|
82
96
|
delete storage.pinnedAccountIndex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AA4DA,OAAO,EAIN,yBAAyB,EACzB,MAAM,eAAe,CAAC;AA6BvB,OAAO,EAEN,mBAAmB,EAMnB,sBAAsB,EAGtB,MAAM,qCAAqC,CAAC;AA+B7C,OAAO,EAEN,KAAK,gBAAgB,EAWrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AA4IvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAuGrE;AACD,mFAAmF;AACnF,wBAAgB,wBAAwB,IAAI,CAC3C,OAAO,EAAE,gBAAgB,KACrB,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAwEzD;AA8PD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C7E"}
|
|
@@ -14,6 +14,7 @@ import { runBudgetCommand } from "./codex-manager/commands/budget.js";
|
|
|
14
14
|
import { runBridgeCommand } from "./codex-manager/commands/bridge.js";
|
|
15
15
|
import { runCheckCommand } from "./codex-manager/commands/check.js";
|
|
16
16
|
import { runIntegrationsCommand } from "./codex-manager/commands/integrations.js";
|
|
17
|
+
import { runLimitsCommand } from "./codex-manager/commands/limits.js";
|
|
17
18
|
import { runModelsCommand } from "./codex-manager/commands/models.js";
|
|
18
19
|
import { runMonitorCommand } from "./codex-manager/commands/monitor.js";
|
|
19
20
|
import { runConfigExplainCommand } from "./codex-manager/commands/config-explain.js";
|
|
@@ -37,6 +38,7 @@ import { runHistoryCommand } from "./codex-manager/commands/history.js";
|
|
|
37
38
|
import { runUnpinCommand } from "./codex-manager/commands/unpin.js";
|
|
38
39
|
import { runWorkspaceCommand } from "./codex-manager/commands/workspace.js";
|
|
39
40
|
import { runUsageCommand } from "./codex-manager/commands/usage.js";
|
|
41
|
+
import { refreshQuotaCacheForMenu } from "./codex-manager/login-menu-data.js";
|
|
40
42
|
import { printUsage } from "./codex-manager/help.js";
|
|
41
43
|
import { availabilityTone, formatBackupSavedAt, formatCompactQuotaSnapshot, formatRateLimitEntry, formatResultSummary, normalizeFailureDetail, riskTone, styleAccountDetailText, stylePromptText, styleQuotaSummary, } from "./codex-manager/formatters/index.js";
|
|
42
44
|
import { applyUiThemeFromDashboardSettings } from "./codex-manager/settings-hub.js";
|
|
@@ -376,6 +378,16 @@ const CLI_COMMAND_HANDLERS = new Map([
|
|
|
376
378
|
["login", (rest) => runAuthLogin(rest, { runForecast, createRepairCommandDeps })],
|
|
377
379
|
["list", runListOrStatusCommand],
|
|
378
380
|
["status", runListOrStatusCommand],
|
|
381
|
+
[
|
|
382
|
+
"limits",
|
|
383
|
+
(rest) => runLimitsCommand(rest, {
|
|
384
|
+
setStoragePath,
|
|
385
|
+
loadAccounts,
|
|
386
|
+
loadQuotaCache,
|
|
387
|
+
refreshQuotaCache: refreshQuotaCacheForMenu,
|
|
388
|
+
resolveActiveIndex,
|
|
389
|
+
}),
|
|
390
|
+
],
|
|
379
391
|
[
|
|
380
392
|
"switch",
|
|
381
393
|
(rest) => runSwitchCommand(rest, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/forecast.js
CHANGED
|
@@ -1,25 +1,12 @@
|
|
|
1
1
|
import { AUTH_INVALIDATION_MARKER, formatAccountLabel, formatWaitTime, } from "./accounts.js";
|
|
2
2
|
import { findQuotaCacheEntryForAccount, isQuotaCacheEntryExhausted, quotaUsedPercentIsExhausted, } from "./quota-readiness.js";
|
|
3
|
+
import { redactEmails } from "./redaction.js";
|
|
3
4
|
import { getRateLimitResetTimeForFamily, getRateLimitResetTimeForModel, } from "./runtime/account-status.js";
|
|
4
5
|
function clampRisk(score) {
|
|
5
6
|
if (!Number.isFinite(score))
|
|
6
7
|
return 100;
|
|
7
8
|
return Math.max(0, Math.min(100, Math.round(score)));
|
|
8
9
|
}
|
|
9
|
-
function maskEmail(value) {
|
|
10
|
-
const atIndex = value.indexOf("@");
|
|
11
|
-
if (atIndex <= 0)
|
|
12
|
-
return "***@***";
|
|
13
|
-
const local = value.slice(0, atIndex);
|
|
14
|
-
const domain = value.slice(atIndex + 1);
|
|
15
|
-
const domainParts = domain.split(".");
|
|
16
|
-
const tld = domainParts.pop() ?? "";
|
|
17
|
-
const prefix = local.slice(0, Math.min(2, local.length));
|
|
18
|
-
return `${prefix}***@***.${tld || "***"}`;
|
|
19
|
-
}
|
|
20
|
-
function redactEmails(value) {
|
|
21
|
-
return value.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, (match) => maskEmail(match));
|
|
22
|
-
}
|
|
23
10
|
function redactSensitiveReason(value) {
|
|
24
11
|
return redactEmails(value
|
|
25
12
|
.replace(/Bearer\s+\S+/gi, "Bearer ***")
|
|
@@ -48,6 +48,18 @@ export declare class PreemptiveQuotaScheduler {
|
|
|
48
48
|
update(key: string, snapshot: QuotaSchedulerSnapshot): void;
|
|
49
49
|
markRateLimited(key: string, retryAfterMs: number, now?: number): void;
|
|
50
50
|
getDeferral(key: string, now?: number): QuotaDeferralDecision;
|
|
51
|
+
/**
|
|
52
|
+
* Forget cached quota observations for one account across its model keys.
|
|
53
|
+
*
|
|
54
|
+
* @param prefix Account key INCLUDING its trailing separator, as produced by
|
|
55
|
+
* `buildQuotaScheduleAccountPrefix`. Without that separator the prefix also
|
|
56
|
+
* matches neighbouring identities (`account:email:foo` matches
|
|
57
|
+
* `account:email:foobar:codex`). An empty prefix is a no-op rather than a
|
|
58
|
+
* silent clear-all; use `clearAll()` when that is the intent.
|
|
59
|
+
*/
|
|
60
|
+
clearByPrefix(prefix: string): void;
|
|
61
|
+
/** Forget every cached quota observation. */
|
|
62
|
+
clearAll(): void;
|
|
51
63
|
prune(now?: number): number;
|
|
52
64
|
}
|
|
53
65
|
//# sourceMappingURL=preemptive-quota-scheduler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preemptive-quota-scheduler.d.ts","sourceRoot":"","sources":["../../lib/preemptive-quota-scheduler.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,oBAAoB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,GAAG,uBAAuB,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,sBAAsB,GAAG,IAAI,CAqB5H;AAED,qBAAa,wBAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,gCAAgC,CAAS;IACjD,OAAO,CAAC,kCAAkC,CAAS;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;gBAEZ,OAAO,GAAE,qBAA0B;IAQ/C,SAAS,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI;IA2CpD,OAAO,CAAC,UAAU;IAMlB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAM3D,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IA8B1E,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,qBAAqB;IAkEjE,KAAK,CAAC,GAAG,SAAa,GAAG,MAAM;CAW/B"}
|
|
1
|
+
{"version":3,"file":"preemptive-quota-scheduler.d.ts","sourceRoot":"","sources":["../../lib/preemptive-quota-scheduler.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,oBAAoB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,GAAG,uBAAuB,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,sBAAsB,GAAG,IAAI,CAqB5H;AAED,qBAAa,wBAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,gCAAgC,CAAS;IACjD,OAAO,CAAC,kCAAkC,CAAS;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;gBAEZ,OAAO,GAAE,qBAA0B;IAQ/C,SAAS,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI;IA2CpD,OAAO,CAAC,UAAU;IAMlB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAM3D,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IA8B1E,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,qBAAqB;IAkEjE;;;;;;;;OAQG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAOnC,6CAA6C;IAC7C,QAAQ,IAAI,IAAI;IAIhB,KAAK,CAAC,GAAG,SAAa,GAAG,MAAM;CAW/B"}
|
|
@@ -264,6 +264,27 @@ export class PreemptiveQuotaScheduler {
|
|
|
264
264
|
}
|
|
265
265
|
return { defer: false, waitMs: 0 };
|
|
266
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Forget cached quota observations for one account across its model keys.
|
|
269
|
+
*
|
|
270
|
+
* @param prefix Account key INCLUDING its trailing separator, as produced by
|
|
271
|
+
* `buildQuotaScheduleAccountPrefix`. Without that separator the prefix also
|
|
272
|
+
* matches neighbouring identities (`account:email:foo` matches
|
|
273
|
+
* `account:email:foobar:codex`). An empty prefix is a no-op rather than a
|
|
274
|
+
* silent clear-all; use `clearAll()` when that is the intent.
|
|
275
|
+
*/
|
|
276
|
+
clearByPrefix(prefix) {
|
|
277
|
+
if (!prefix)
|
|
278
|
+
return;
|
|
279
|
+
for (const key of this.snapshots.keys()) {
|
|
280
|
+
if (key.startsWith(prefix))
|
|
281
|
+
this.snapshots.delete(key);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/** Forget every cached quota observation. */
|
|
285
|
+
clearAll() {
|
|
286
|
+
this.snapshots.clear();
|
|
287
|
+
}
|
|
267
288
|
prune(now = Date.now()) {
|
|
268
289
|
let removed = 0;
|
|
269
290
|
for (const [key, snapshot] of this.snapshots.entries()) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email redaction for machine-readable command output.
|
|
3
|
+
*
|
|
4
|
+
* Account labels are built from the operator-visible email, so any command that
|
|
5
|
+
* emits them as JSON hands that address to whatever consumes the output: log
|
|
6
|
+
* shippers, dashboards, ticket attachments. `forecast --json` has masked them
|
|
7
|
+
* since it was written; this module is that same masking, shared so other JSON
|
|
8
|
+
* surfaces do not each re-derive it.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Mask one address, keeping just enough to tell two accounts apart: the first
|
|
12
|
+
* two characters of the local part and the TLD.
|
|
13
|
+
*/
|
|
14
|
+
export declare function maskEmail(value: string): string;
|
|
15
|
+
/** Mask every address embedded in a free-text string. */
|
|
16
|
+
export declare function redactEmails(value: string): string;
|
|
17
|
+
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../lib/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS/C;AAED,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email redaction for machine-readable command output.
|
|
3
|
+
*
|
|
4
|
+
* Account labels are built from the operator-visible email, so any command that
|
|
5
|
+
* emits them as JSON hands that address to whatever consumes the output: log
|
|
6
|
+
* shippers, dashboards, ticket attachments. `forecast --json` has masked them
|
|
7
|
+
* since it was written; this module is that same masking, shared so other JSON
|
|
8
|
+
* surfaces do not each re-derive it.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Mask one address, keeping just enough to tell two accounts apart: the first
|
|
12
|
+
* two characters of the local part and the TLD.
|
|
13
|
+
*/
|
|
14
|
+
export function maskEmail(value) {
|
|
15
|
+
const atIndex = value.indexOf("@");
|
|
16
|
+
if (atIndex <= 0)
|
|
17
|
+
return "***@***";
|
|
18
|
+
const local = value.slice(0, atIndex);
|
|
19
|
+
const domain = value.slice(atIndex + 1);
|
|
20
|
+
const domainParts = domain.split(".");
|
|
21
|
+
const tld = domainParts.pop() ?? "";
|
|
22
|
+
const prefix = local.slice(0, Math.min(2, local.length));
|
|
23
|
+
return `${prefix}***@***.${tld || "***"}`;
|
|
24
|
+
}
|
|
25
|
+
/** Mask every address embedded in a free-text string. */
|
|
26
|
+
export function redactEmails(value) {
|
|
27
|
+
return value.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, (match) => maskEmail(match));
|
|
28
|
+
}
|
|
@@ -35,15 +35,22 @@ export declare function resolveUnsupportedCodexFallbackModel(options: ResolveUns
|
|
|
35
35
|
*/
|
|
36
36
|
export declare function shouldFallbackToGpt52OnUnsupportedGpt53(requestedModel: string | undefined, errorBody: unknown): boolean;
|
|
37
37
|
/**
|
|
38
|
-
* Detects
|
|
38
|
+
* Detects an upstream response saying the selected model is temporarily out of
|
|
39
|
+
* capacity, as opposed to the account being rate limited or the server being
|
|
40
|
+
* broken.
|
|
39
41
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
+
* The distinction matters because the two want opposite handling. A rate limit
|
|
43
|
+
* is per account, so rotating to another account clears it. Capacity is a
|
|
44
|
+
* property of the MODEL, so every account in the pool fails identically and
|
|
45
|
+
* rotating just burns the pool's transient budget in a few seconds, ending the
|
|
46
|
+
* request as a 503. The caller waits and re-sends on the same account instead.
|
|
47
|
+
* See issue #689.
|
|
42
48
|
*
|
|
43
|
-
* @param
|
|
44
|
-
* @param bodyText -
|
|
45
|
-
* @returns `true`
|
|
49
|
+
* @param status - Upstream HTTP status.
|
|
50
|
+
* @param bodyText - Upstream error body, already read.
|
|
51
|
+
* @returns `true` when the request should be waited out rather than rotated.
|
|
46
52
|
*/
|
|
53
|
+
export declare function isModelAtCapacityError(status: number, bodyText: string): boolean;
|
|
47
54
|
export declare function isEntitlementError(code: string, bodyText: string): boolean;
|
|
48
55
|
/**
|
|
49
56
|
* Detects whether an error indicates the workspace/account has been disabled or expired.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-classification.d.ts","sourceRoot":"","sources":["../../../lib/request/error-classification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,gBAAgB;IACzB,aAAa,EAAE,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACvB;AAED,sGAAsG;AACtG,eAAO,MAAM,oCAAoC,6CAA6C,CAAC;AAQ/F,eAAO,MAAM,wCAAwC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAoD7E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sCAAsC;IACtD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,+BAA+B,EAAE,OAAO,CAAC;IACzC,iCAAiC,EAAE,OAAO,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACvC;AAiDD,wBAAgB,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBzF;AAED,sGAAsG;AACtG,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQ3F;AAED,wBAAgB,4BAA4B,CAC3C,SAAS,EAAE,OAAO,GAChB,yBAAyB,CAqD3B;AAED,wBAAgB,oCAAoC,CACnD,OAAO,EAAE,sCAAsC,GAC7C,MAAM,GAAG,SAAS,CAkCpB;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACtD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,OAAO,GAChB,OAAO,CAgBT;
|
|
1
|
+
{"version":3,"file":"error-classification.d.ts","sourceRoot":"","sources":["../../../lib/request/error-classification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,gBAAgB;IACzB,aAAa,EAAE,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACvB;AAED,sGAAsG;AACtG,eAAO,MAAM,oCAAoC,6CAA6C,CAAC;AAQ/F,eAAO,MAAM,wCAAwC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAoD7E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sCAAsC;IACtD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,+BAA+B,EAAE,OAAO,CAAC;IACzC,iCAAiC,EAAE,OAAO,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACvC;AAiDD,wBAAgB,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBzF;AAED,sGAAsG;AACtG,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQ3F;AAED,wBAAgB,4BAA4B,CAC3C,SAAS,EAAE,OAAO,GAChB,yBAAyB,CAqD3B;AAED,wBAAgB,oCAAoC,CACnD,OAAO,EAAE,sCAAsC,GAC7C,MAAM,GAAG,SAAS,CAkCpB;AAED;;GAEG;AACH,wBAAgB,uCAAuC,CACtD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,SAAS,EAAE,OAAO,GAChB,OAAO,CAgBT;AAqCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACd,OAAO,CAIT;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAK1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,GACrB,OAAO,CAoDT;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAmB1E"}
|
|
@@ -242,6 +242,51 @@ export function shouldFallbackToGpt52OnUnsupportedGpt53(requestedModel, errorBod
|
|
|
242
242
|
* @param bodyText - The response body text to inspect for entitlement-related phrases
|
|
243
243
|
* @returns `true` if the combined `code` or `bodyText` indicates an entitlement/subscription issue, `false` otherwise
|
|
244
244
|
*/
|
|
245
|
+
/**
|
|
246
|
+
* Statuses that are never a capacity signal, whatever the body says.
|
|
247
|
+
*
|
|
248
|
+
* Auth, payment, entitlement and not-found responses are terminal for this
|
|
249
|
+
* request and are each handled by their own branch upstream of the capacity
|
|
250
|
+
* check. Retrying them would spin until the deadline for no reason.
|
|
251
|
+
*/
|
|
252
|
+
const NON_CAPACITY_STATUSES = new Set([401, 402, 403, 404]);
|
|
253
|
+
/**
|
|
254
|
+
* Phrases and codes that mean the model itself is out of capacity right now.
|
|
255
|
+
*
|
|
256
|
+
* This is matched on the body TEXT rather than on a status code, because the
|
|
257
|
+
* status this arrives with is not documented and has been reported differently
|
|
258
|
+
* by different callers. Matching text the way `isEntitlementError` and
|
|
259
|
+
* `isWorkspaceDisabledError` already do means a wrong guess about the status
|
|
260
|
+
* leaves behavior exactly as it is today, rather than breaking a path.
|
|
261
|
+
*
|
|
262
|
+
* `at capacity` is deliberately broad. In an OpenAI error body that phrase does
|
|
263
|
+
* not occur outside capacity pressure, and a false positive costs a bounded
|
|
264
|
+
* wait and one re-send, not a wrong answer.
|
|
265
|
+
*/
|
|
266
|
+
const MODEL_AT_CAPACITY_PATTERN = /\bat capacity\b|\bmodel_capacity_exceeded\b|\bcapacity_exceeded\b|\bcurrently overloaded\b|\boverloaded_error\b|\bslow_down\b/i;
|
|
267
|
+
/**
|
|
268
|
+
* Detects an upstream response saying the selected model is temporarily out of
|
|
269
|
+
* capacity, as opposed to the account being rate limited or the server being
|
|
270
|
+
* broken.
|
|
271
|
+
*
|
|
272
|
+
* The distinction matters because the two want opposite handling. A rate limit
|
|
273
|
+
* is per account, so rotating to another account clears it. Capacity is a
|
|
274
|
+
* property of the MODEL, so every account in the pool fails identically and
|
|
275
|
+
* rotating just burns the pool's transient budget in a few seconds, ending the
|
|
276
|
+
* request as a 503. The caller waits and re-sends on the same account instead.
|
|
277
|
+
* See issue #689.
|
|
278
|
+
*
|
|
279
|
+
* @param status - Upstream HTTP status.
|
|
280
|
+
* @param bodyText - Upstream error body, already read.
|
|
281
|
+
* @returns `true` when the request should be waited out rather than rotated.
|
|
282
|
+
*/
|
|
283
|
+
export function isModelAtCapacityError(status, bodyText) {
|
|
284
|
+
if (NON_CAPACITY_STATUSES.has(status))
|
|
285
|
+
return false;
|
|
286
|
+
if (!bodyText)
|
|
287
|
+
return false;
|
|
288
|
+
return MODEL_AT_CAPACITY_PATTERN.test(bodyText);
|
|
289
|
+
}
|
|
245
290
|
export function isEntitlementError(code, bodyText) {
|
|
246
291
|
const haystack = `${code} ${bodyText}`.toLowerCase();
|
|
247
292
|
// "usage_not_included" means the subscription doesn't include this feature
|
|
@@ -6,7 +6,7 @@ import { type FastSessionInputTrimPlan } from "./request-transformer.js";
|
|
|
6
6
|
import type { UserConfig, RequestBody } from "../types.js";
|
|
7
7
|
import type { UsageTokenCounts } from "../usage/types.js";
|
|
8
8
|
export { shouldRefreshToken, refreshAndUpdateToken } from "./token-refresh.js";
|
|
9
|
-
export { DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN, extractUnsupportedCodexModelFromText, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, shouldFallbackToGpt52OnUnsupportedGpt53, isEntitlementError, isWorkspaceDisabledError, createEntitlementErrorResponse, } from "./error-classification.js";
|
|
9
|
+
export { DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN, extractUnsupportedCodexModelFromText, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, shouldFallbackToGpt52OnUnsupportedGpt53, isEntitlementError, isModelAtCapacityError, isWorkspaceDisabledError, createEntitlementErrorResponse, } from "./error-classification.js";
|
|
10
10
|
export type { EntitlementError, UnsupportedCodexModelInfo, ResolveUnsupportedCodexFallbackOptions, } from "./error-classification.js";
|
|
11
11
|
export { extractRequestUrl, rewriteUrlForCodex, resolveProxyUrlForRequest, closeSharedProxyDispatchers, applyProxyCompatibleInit, } from "./url-rewriting.js";
|
|
12
12
|
export type { ProxyCompatibleRequestInit } from "./url-rewriting.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-helpers.d.ts","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fetch-helpers.d.ts","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAIN,KAAK,wBAAwB,EAC7B,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAiB1D,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EACN,wCAAwC,EACxC,oCAAoC,EACpC,4BAA4B,EAC5B,oCAAoC,EACpC,uCAAuC,EACvC,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,GAC9B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACX,gBAAgB,EAChB,yBAAyB,EACzB,sCAAsC,GACtC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EACX,yBAAyB,EACzB,wBAAwB,GACxB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,MAAM,WAAW,8BAA8B;IAC9C,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,4BAA4B,CAAC,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,mBAAmB;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC7C,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,SAAS,UAAO,EAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE;IACT,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1C,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACnC,GACC,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CA4FrD;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,oBAAoB,GACnC,OAAO,CAAC,mBAAmB,CAAC,CA4C9B;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACvC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE;IACZ,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACC,OAAO,CAAC,QAAQ,CAAC,CAkBnB"}
|
|
@@ -11,7 +11,7 @@ import { HTTP_STATUS, ERROR_MESSAGES, LOG_STAGES, MAX_RATE_LIMIT_DELAY_MS, } fro
|
|
|
11
11
|
import { CHATGPT_CODEX_UNSUPPORTED_MODEL_CODE, createEntitlementErrorResponse, extractUnsupportedCodexModelFromText, isEntitlementError, isUnsupportedCodexModelForChatGpt, } from "./error-classification.js";
|
|
12
12
|
import { logDeprecationHeaders } from "./headers.js";
|
|
13
13
|
export { shouldRefreshToken, refreshAndUpdateToken } from "./token-refresh.js";
|
|
14
|
-
export { DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN, extractUnsupportedCodexModelFromText, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, shouldFallbackToGpt52OnUnsupportedGpt53, isEntitlementError, isWorkspaceDisabledError, createEntitlementErrorResponse, } from "./error-classification.js";
|
|
14
|
+
export { DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN, extractUnsupportedCodexModelFromText, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, shouldFallbackToGpt52OnUnsupportedGpt53, isEntitlementError, isModelAtCapacityError, isWorkspaceDisabledError, createEntitlementErrorResponse, } from "./error-classification.js";
|
|
15
15
|
export { extractRequestUrl, rewriteUrlForCodex, resolveProxyUrlForRequest, closeSharedProxyDispatchers, applyProxyCompatibleInit, } from "./url-rewriting.js";
|
|
16
16
|
export { createCodexHeaders } from "./headers.js";
|
|
17
17
|
// MAX_RATE_LIMIT_DELAY_MS is centralized in constants.ts (shared with the
|
|
@@ -21,6 +21,12 @@ export interface RotationProxyStateInit {
|
|
|
21
21
|
tokenRefreshSkewMs: number;
|
|
22
22
|
networkErrorCooldownMs: number;
|
|
23
23
|
serverErrorCooldownMs: number;
|
|
24
|
+
/**
|
|
25
|
+
* Wall-clock ceiling on how long ONE request may wait out a model-capacity
|
|
26
|
+
* response before giving up. `0` restores the pre-#689 behaviour of rotating
|
|
27
|
+
* the pool and returning the exhaustion 503.
|
|
28
|
+
*/
|
|
29
|
+
modelCapacityRetryMs: number;
|
|
24
30
|
tokenInvalidationCooldownMs: number;
|
|
25
31
|
minRotationIntervalMs: number;
|
|
26
32
|
pidOffsetEnabled: boolean;
|
|
@@ -1 +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;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAKjF,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,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,8BAA8B,EAAE,MAAM,CAAC;IACvC;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;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,CAkDhC"}
|
|
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;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAKjF,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;;;;OAIG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B,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,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,8BAA8B,EAAE,MAAM,CAAC;IACvC;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;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,CAkDhC"}
|
|
@@ -48,6 +48,13 @@ export interface RuntimeRotationProxyOptions {
|
|
|
48
48
|
* the value survives the launcher -> detached app-helper process boundary.
|
|
49
49
|
*/
|
|
50
50
|
forcedAccountIndex?: number | null;
|
|
51
|
+
/**
|
|
52
|
+
* Wall-clock ceiling on how long ONE request may wait out a
|
|
53
|
+
* "selected model is at capacity" response before giving up (issue #689).
|
|
54
|
+
* `0` disables the wait entirely. Falls back to
|
|
55
|
+
* `CODEX_MULTI_AUTH_MODEL_CAPACITY_RETRY_MS`, then to a 10 minute default.
|
|
56
|
+
*/
|
|
57
|
+
modelCapacityRetryMs?: number;
|
|
51
58
|
}
|
|
52
59
|
export interface RequestContext {
|
|
53
60
|
body: Buffer;
|
|
@@ -1 +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;IAC5C;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAC;CACtC;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;IAC9B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
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;IAC5C;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAC;CACtC;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;IAC9B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;;OAKG;IACH,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;IAC1B;;;;;;;;;OASG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;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"}
|
|
@@ -1 +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,
|
|
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,CAsFb;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"}
|
|
@@ -90,7 +90,10 @@ export function readStorageMetaFromDisk(storagePath = getStoragePath()) {
|
|
|
90
90
|
: null;
|
|
91
91
|
const affinityGeneration = typeof parsed.affinityGeneration === "number" &&
|
|
92
92
|
Number.isFinite(parsed.affinityGeneration) &&
|
|
93
|
-
|
|
93
|
+
// Safe, not merely integral: see readAffinityGenerationFromDisk. Past
|
|
94
|
+
// 2^53 the CLI's bump stops advancing, so a proxy that accepted the
|
|
95
|
+
// value would never observe another switch.
|
|
96
|
+
Number.isSafeInteger(parsed.affinityGeneration) &&
|
|
94
97
|
parsed.affinityGeneration >= 0
|
|
95
98
|
? parsed.affinityGeneration
|
|
96
99
|
: 0;
|