codex-multi-auth 2.8.7 → 2.9.1

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.
Files changed (62) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +14 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +34 -0
  5. package/dist/lib/account-policy.d.ts +3 -1
  6. package/dist/lib/account-policy.d.ts.map +1 -1
  7. package/dist/lib/account-policy.js +14 -1
  8. package/dist/lib/budget-guard.d.ts +1 -0
  9. package/dist/lib/budget-guard.d.ts.map +1 -1
  10. package/dist/lib/budget-guard.js +13 -3
  11. package/dist/lib/codex-manager/account-pool-write.d.ts +8 -0
  12. package/dist/lib/codex-manager/account-pool-write.d.ts.map +1 -1
  13. package/dist/lib/codex-manager/account-pool-write.js +1 -1
  14. package/dist/lib/codex-manager/help.d.ts +2 -0
  15. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  16. package/dist/lib/codex-manager/help.js +38 -1
  17. package/dist/lib/codex-manager/login-flow.d.ts +3 -0
  18. package/dist/lib/codex-manager/login-flow.d.ts.map +1 -1
  19. package/dist/lib/codex-manager/login-flow.js +80 -6
  20. package/dist/lib/codex-manager/login-menu-actions.d.ts.map +1 -1
  21. package/dist/lib/codex-manager/login-menu-actions.js +41 -5
  22. package/dist/lib/codex-manager/login-oauth.d.ts +38 -2
  23. package/dist/lib/codex-manager/login-oauth.d.ts.map +1 -1
  24. package/dist/lib/codex-manager/login-oauth.js +205 -23
  25. package/dist/lib/policy/runtime-policy.d.ts +7 -0
  26. package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
  27. package/dist/lib/policy/runtime-policy.js +1 -0
  28. package/dist/lib/request/fetch-helpers.d.ts +7 -0
  29. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  30. package/dist/lib/request/fetch-helpers.js +1 -1
  31. package/dist/lib/request/response-handler.d.ts +3 -1
  32. package/dist/lib/request/response-handler.d.ts.map +1 -1
  33. package/dist/lib/request/response-handler.js +26 -5
  34. package/dist/lib/request/stream-failover-runtime.d.ts +8 -1
  35. package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
  36. package/dist/lib/request/stream-failover-runtime.js +9 -1
  37. package/dist/lib/request/stream-failover.d.ts.map +1 -1
  38. package/dist/lib/request/stream-failover.js +41 -0
  39. package/dist/lib/runtime/account-check.d.ts.map +1 -1
  40. package/dist/lib/runtime/account-check.js +8 -1
  41. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  42. package/dist/lib/runtime-rotation-proxy.js +46 -3
  43. package/dist/lib/storage.d.ts +19 -0
  44. package/dist/lib/storage.d.ts.map +1 -1
  45. package/dist/lib/storage.js +32 -0
  46. package/dist/lib/usage/index.d.ts +2 -0
  47. package/dist/lib/usage/index.d.ts.map +1 -1
  48. package/dist/lib/usage/index.js +2 -0
  49. package/dist/lib/usage/ledger.d.ts.map +1 -1
  50. package/dist/lib/usage/ledger.js +7 -0
  51. package/dist/lib/usage/pricing.d.ts +15 -0
  52. package/dist/lib/usage/pricing.d.ts.map +1 -1
  53. package/dist/lib/usage/pricing.js +24 -0
  54. package/dist/lib/usage/stream-usage-deferral.d.ts +39 -0
  55. package/dist/lib/usage/stream-usage-deferral.d.ts.map +1 -0
  56. package/dist/lib/usage/stream-usage-deferral.js +54 -0
  57. package/dist/lib/usage/types.d.ts +6 -0
  58. package/dist/lib/usage/types.d.ts.map +1 -1
  59. package/dist/lib/usage/usage-extraction.d.ts +42 -0
  60. package/dist/lib/usage/usage-extraction.d.ts.map +1 -0
  61. package/dist/lib/usage/usage-extraction.js +178 -0
  62. package/package.json +1 -1
@@ -11,6 +11,8 @@ import { setCodexCliActiveSelection } from "../codex-cli/writer.js";
11
11
  import { createLogger } from "../logger.js";
12
12
  import { MODEL_FAMILIES } from "../prompts/codex.js";
13
13
  import { findMatchingAccountIndex, withAccountStorageTransaction, } from "../storage.js";
14
+ import { cloneAccountStorageForPersistence } from "../storage/account-persistence.js";
15
+ import { CodexValidationError } from "../errors.js";
14
16
  import { UI_COPY } from "../ui/ui-copy.js";
15
17
  import { applyAccountPoolResults, } from "./account-pool-write.js";
16
18
  import { stylePromptText } from "./formatters/index.js";
@@ -39,7 +41,7 @@ export function isAbortError(error) {
39
41
  *
40
42
  * @internal
41
43
  */
42
- export function resolveAccountSelection(tokens, orgOverride) {
44
+ export function resolveAccountSelection(tokens, orgOverride, targetAccountId) {
43
45
  const candidates = getAccountIdCandidates(tokens.access, tokens.idToken);
44
46
  // Surface every workspace/organization exposed by the token so the saved
45
47
  // account can track them (issue #491/#512). Without this, same-email
@@ -54,18 +56,50 @@ export function resolveAccountSelection(tokens, orgOverride) {
54
56
  isDefault: candidate.isDefault,
55
57
  }))
56
58
  : undefined;
57
- const override = resolveOrgOverride(orgOverride);
58
- if (override) {
59
- // Prefer the token candidate's human label for the chosen org so the
60
- // saved row is identifiable, falling back to a bare manual binding.
61
- const matched = candidates.find((candidate) => candidate.accountId === override);
62
- return {
63
- ...tokens,
64
- accountIdOverride: override,
65
- accountIdSource: "manual",
66
- accountLabel: matched?.label,
67
- workspaces,
68
- };
59
+ // A targeted re-authentication names one saved row, which is a stricter and
60
+ // more specific instruction than the ambient CODEX_AUTH_ACCOUNT_ID env var
61
+ // that resolveOrgOverride also honours. Consulting the override first let an
62
+ // unrelated exported org id hijack `login --account <n>` and then fail the
63
+ // identity guard with a misleading "does not match" message. An explicit
64
+ // `--org` cannot reach here alongside a target: parseAuthLoginArgs rejects
65
+ // that combination outright.
66
+ if (targetAccountId) {
67
+ const targetedCandidate = candidates.find((candidate) => candidate.accountId === targetAccountId);
68
+ if (targetedCandidate) {
69
+ return {
70
+ ...tokens,
71
+ accountIdOverride: targetedCandidate.accountId,
72
+ // `id_token` candidates auto-follow the access token inside
73
+ // resolveRequestAccountId, which would rewrite this binding back to
74
+ // the access-token account and make the caller's own identity guard
75
+ // reject the write. Pin those as an explicit selection; a `token`
76
+ // candidate already IS the access-token account, and an `org`
77
+ // candidate never auto-follows, so both keep their source.
78
+ accountIdSource: targetedCandidate.source === "id_token"
79
+ ? "manual"
80
+ : targetedCandidate.source,
81
+ accountLabel: targetedCandidate.label,
82
+ workspaces,
83
+ };
84
+ }
85
+ // The user signed in as somebody else. Fall through to the generic
86
+ // selection so persistAccountPool refuses the write with the precise
87
+ // identity-mismatch message instead of a confusing override error.
88
+ }
89
+ else {
90
+ const override = resolveOrgOverride(orgOverride);
91
+ if (override) {
92
+ // Prefer the token candidate's human label for the chosen org so the
93
+ // saved row is identifiable, falling back to a bare manual binding.
94
+ const matched = candidates.find((candidate) => candidate.accountId === override);
95
+ return {
96
+ ...tokens,
97
+ accountIdOverride: override,
98
+ accountIdSource: "manual",
99
+ accountLabel: matched?.label,
100
+ workspaces,
101
+ };
102
+ }
69
103
  }
70
104
  if (candidates.length === 0) {
71
105
  return tokens;
@@ -300,8 +334,81 @@ export async function runSignInFlow(forceNewLogin, signInMode, options = {}) {
300
334
  }
301
335
  return runOAuthFlow(forceNewLogin, signInMode);
302
336
  }
337
+ function sameExpectedLoginIdentity(write, expected) {
338
+ const expectedAccountId = expected.accountId?.trim();
339
+ const incomingAccountId = write.accountId?.trim();
340
+ const expectedEmail = sanitizeEmail(expected.email);
341
+ const incomingEmail = sanitizeEmail(write.email);
342
+ // When the saved row already carries the provider identity it is
343
+ // authoritative and the incoming login must match it: the id survives an
344
+ // email change, and falling back to a shared email across workspaces would
345
+ // let a targeted re-auth overwrite the wrong saved account.
346
+ if (expectedAccountId) {
347
+ return incomingAccountId === expectedAccountId;
348
+ }
349
+ // A pre-#491 row saved before workspace tracking carries no account id at
350
+ // all. Fresh tokens essentially always carry one, so demanding the id on both
351
+ // sides made every legacy row permanently un-refreshable through --account.
352
+ // Email is the only identity such a row has, and the caller already resolved
353
+ // it to a single unambiguous row before starting the sign-in.
354
+ return Boolean(expectedEmail && incomingEmail === expectedEmail);
355
+ }
356
+ function matchesExpectedAccount(account, expected) {
357
+ if (!account)
358
+ return false;
359
+ if (expected.recordId && account.recordId) {
360
+ return account.recordId === expected.recordId;
361
+ }
362
+ const expectedAccountId = expected.accountId?.trim();
363
+ const candidateAccountId = account.accountId?.trim();
364
+ if (expectedAccountId || candidateAccountId) {
365
+ return Boolean(expectedAccountId &&
366
+ candidateAccountId &&
367
+ expectedAccountId === candidateAccountId);
368
+ }
369
+ const expectedEmail = sanitizeEmail(expected.email);
370
+ const candidateEmail = sanitizeEmail(account.email);
371
+ if (expectedEmail || candidateEmail) {
372
+ return Boolean(expectedEmail && candidateEmail === expectedEmail);
373
+ }
374
+ return account.refreshToken === expected.refreshToken;
375
+ }
376
+ /**
377
+ * Locate the saved row a targeted re-authentication must write.
378
+ *
379
+ * Resolution is deliberately identity-first and refresh-token-last. The runtime
380
+ * rotation proxy rewrites a stored refreshToken whenever it refreshes an account
381
+ * (AccountManager.commitRefreshedAuth), so a sign-in that overlaps a live codex
382
+ * session would otherwise "lose" its own target and throw away a completed
383
+ * OAuth. `recordId` is exact when both sides have one, the caller's position is
384
+ * honoured only while the row sitting there is still the same identity, and
385
+ * findMatchingAccountIndex supplies the same composite/email/refresh-token
386
+ * ladder the rest of the pool already resolves identities with.
387
+ */
388
+ function resolveExpectedAccountIndex(accounts, expected, hintedIndex) {
389
+ if (expected.recordId) {
390
+ const byRecordId = accounts.findIndex((account) => account?.recordId === expected.recordId);
391
+ if (byRecordId >= 0)
392
+ return byRecordId;
393
+ }
394
+ if (validSelectionIndex(hintedIndex, accounts) &&
395
+ matchesExpectedAccount(accounts[hintedIndex], expected)) {
396
+ return hintedIndex;
397
+ }
398
+ return findMatchingAccountIndex(accounts, {
399
+ accountId: expected.accountId,
400
+ email: expected.email,
401
+ refreshToken: expected.refreshToken,
402
+ }, { allowUniqueAccountIdFallbackWithoutEmail: true });
403
+ }
404
+ function validSelectionIndex(index, accounts) {
405
+ return (typeof index === "number" &&
406
+ Number.isInteger(index) &&
407
+ index >= 0 &&
408
+ index < accounts.length);
409
+ }
303
410
  /** @internal */
304
- export async function persistAccountPool(results, replaceAll) {
411
+ export async function persistAccountPool(results, replaceAll, options = {}) {
305
412
  if (results.length === 0)
306
413
  return null;
307
414
  return await withAccountStorageTransaction(async (loadedStorage, persist) => {
@@ -324,26 +431,101 @@ export async function persistAccountPool(results, replaceAll) {
324
431
  accessToken: result.access,
325
432
  expiresAt: result.expires,
326
433
  workspaces: result.workspaces,
434
+ // A targeted re-auth only tops up credentials for the row the user
435
+ // named; it must not silently re-enable an account they disabled.
436
+ preserveEnabledState: Boolean(options.expectedAccount),
327
437
  now,
328
438
  };
329
439
  });
440
+ if (options.expectedAccount && writes.length !== 1) {
441
+ throw new CodexValidationError("Targeted re-authentication accepts exactly one OAuth result. No saved credentials were changed.");
442
+ }
443
+ const expectedAccountIndex = options.expectedAccount && stored
444
+ ? resolveExpectedAccountIndex(stored.accounts, options.expectedAccount, options.expectedAccountIndex)
445
+ : undefined;
446
+ if (options.expectedAccount && expectedAccountIndex === undefined) {
447
+ throw new CodexValidationError("The requested Codex account is no longer present. No saved credentials were changed.");
448
+ }
449
+ const expectedAccount = options.expectedAccount;
450
+ if (expectedAccount &&
451
+ writes.some((write) => !sameExpectedLoginIdentity(write, expectedAccount))) {
452
+ throw new CodexValidationError("The authenticated Codex identity does not match the account requested for re-authentication. No saved credentials were changed.");
453
+ }
330
454
  const { accounts, activeIndex, outcome } = applyAccountPoolResults({
331
455
  existing,
332
456
  writes,
333
457
  priorActiveIndex: stored?.activeIndex,
334
- findMatchingAccountIndex,
458
+ findMatchingAccountIndex: expectedAccountIndex === undefined
459
+ ? findMatchingAccountIndex
460
+ : () => expectedAccountIndex,
335
461
  });
462
+ const nextActiveIndex = options.preserveSelection &&
463
+ validSelectionIndex(stored?.activeIndex, accounts)
464
+ ? stored.activeIndex
465
+ : activeIndex;
466
+ const priorActiveIndex = stored?.activeIndex;
336
467
  const activeIndexByFamily = {};
337
468
  for (const family of MODEL_FAMILIES) {
338
- activeIndexByFamily[family] = activeIndex;
469
+ const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
470
+ const priorFamilyIndex = storedFamilyIndex ?? priorActiveIndex;
471
+ if (!validSelectionIndex(priorFamilyIndex, accounts)) {
472
+ activeIndexByFamily[family] = nextActiveIndex;
473
+ continue;
474
+ }
475
+ if (options.preserveSelection) {
476
+ activeIndexByFamily[family] = priorFamilyIndex;
477
+ continue;
478
+ }
479
+ // A family the user deliberately pointed at a DIFFERENT account than
480
+ // the global selection is a setting of its own, and a plain login must
481
+ // not silently drag it onto the account just signed in: adding a third
482
+ // account used to move a deliberate `codex-max -> account 2` binding
483
+ // onto account 3. Families that were merely following the global
484
+ // selection keep following it, which is what makes a plain login still
485
+ // feel like "this new account is now the one in use".
486
+ //
487
+ // Indices stay meaningful here because login only updates a row in
488
+ // place or appends one; it never reorders or removes the pool.
489
+ const followedGlobalSelection = storedFamilyIndex === undefined || storedFamilyIndex === priorActiveIndex;
490
+ activeIndexByFamily[family] = followedGlobalSelection
491
+ ? nextActiveIndex
492
+ : priorFamilyIndex;
339
493
  }
340
- await persist({
341
- version: 3,
342
- accounts,
343
- activeIndex,
344
- activeIndexByFamily,
345
- });
346
- return outcome;
494
+ // Reuse the shared persistence clone so the pin/affinity carry-over rule
495
+ // (issue #474) keeps living in exactly one place instead of being
496
+ // re-derived at every write site with a slightly different validity check.
497
+ const nextStorage = cloneAccountStorageForPersistence(stored);
498
+ nextStorage.accounts = accounts;
499
+ nextStorage.activeIndex = nextActiveIndex;
500
+ nextStorage.activeIndexByFamily = activeIndexByFamily;
501
+ // A selection-preserving login leaves the pool exactly where it was, so a
502
+ // manual `switch <n>` pin survives it: login only updates a row in place
503
+ // or appends one and never reorders, so the raw position still points at
504
+ // the row the user pinned even when two rows share an identity.
505
+ //
506
+ // A plain login is the opposite. It moves activeIndex onto the account
507
+ // just signed in and publishes that account to ~/.codex/auth.json.
508
+ // Carrying an old pin through it would leave storage claiming one account
509
+ // is active while the runtime proxy routes every request to another
510
+ // (runtime-rotation-proxy resolves pinnedAccountIndex first) -- the
511
+ // contradiction `status` reports as "runtime using N but pin requests M".
512
+ if (!options.preserveSelection ||
513
+ !validSelectionIndex(nextStorage.pinnedAccountIndex, accounts)) {
514
+ delete nextStorage.pinnedAccountIndex;
515
+ }
516
+ await persist(nextStorage);
517
+ if (outcome === null)
518
+ return null;
519
+ return {
520
+ outcome,
521
+ accountIndex: activeIndex,
522
+ activeIndex: nextActiveIndex,
523
+ // The Codex CLI reads the `codex` family selection, so that -- not the
524
+ // bare global index -- decides whether this write owns the native
525
+ // ~/.codex/auth.json credentials.
526
+ isActiveAccount: activeIndex === (activeIndexByFamily.codex ?? nextActiveIndex),
527
+ accountEnabled: accounts[activeIndex]?.enabled !== false,
528
+ };
347
529
  });
348
530
  }
349
531
  /** @internal */
@@ -7,6 +7,13 @@ export interface RuntimePolicyAccount {
7
7
  index: number;
8
8
  accountId?: string | null;
9
9
  email?: string | null;
10
+ /**
11
+ * Only used to key account policy for an account with no accountId and no
12
+ * email. Without it the runtime would key such an account as "unknown"
13
+ * while the CLI keys it by refresh-token digest, and pause/drain/tag state
14
+ * written by one would be invisible to the other.
15
+ */
16
+ refreshToken?: string | null;
10
17
  }
11
18
  export interface RuntimePolicyDecision {
12
19
  allowed: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-policy.d.ts","sourceRoot":"","sources":["../../../lib/policy/runtime-policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-policy.d.ts","sourceRoot":"","sources":["../../../lib/policy/runtime-policy.ts"],"names":[],"mappings":"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"}
@@ -98,6 +98,7 @@ export async function evaluateRuntimePolicy(input) {
98
98
  const accountKey = getAccountPolicyKey({
99
99
  accountId: account.accountId ?? undefined,
100
100
  email: account.email ?? undefined,
101
+ refreshToken: account.refreshToken ?? undefined,
101
102
  }, account.index);
102
103
  const accountPolicy = input.state.accountPolicies.accounts[accountKey];
103
104
  let boost = 0;
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { type FastSessionInputTrimPlan } from "./request-transformer.js";
6
6
  import type { UserConfig, RequestBody } from "../types.js";
7
+ import type { UsageTokenCounts } from "../usage/types.js";
7
8
  export { shouldRefreshToken, refreshAndUpdateToken } from "./token-refresh.js";
8
9
  export { DEFAULT_UNSUPPORTED_CODEX_FALLBACK_CHAIN, extractUnsupportedCodexModelFromText, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, shouldFallbackToGpt52OnUnsupportedGpt53, isEntitlementError, isWorkspaceDisabledError, createEntitlementErrorResponse, } from "./error-classification.js";
9
10
  export type { EntitlementError, UnsupportedCodexModelInfo, ResolveUnsupportedCodexFallbackOptions, } from "./error-classification.js";
@@ -70,6 +71,12 @@ export declare function handleErrorResponse(response: Response, options?: ErrorH
70
71
  */
71
72
  export declare function handleSuccessResponse(response: Response, isStreaming: boolean, options?: {
72
73
  onResponseId?: (responseId: string) => void;
74
+ /**
75
+ * Reports the upstream token counts once they are known, for the usage
76
+ * ledger. Fires from the SSE tee on the streaming path and from the
77
+ * assembled response on the non-streaming path.
78
+ */
79
+ onUsage?: (usage: UsageTokenCounts) => void;
73
80
  streamStallTimeoutMs?: number;
74
81
  }): Promise<Response>;
75
82
  //# sourceMappingURL=fetch-helpers.d.ts.map
@@ -1 +1 @@
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;AAiB3D,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,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,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACC,OAAO,CAAC,QAAQ,CAAC,CAanB"}
1
+ {"version":3,"file":"fetch-helpers.d.ts","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"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"}
@@ -155,7 +155,7 @@ export async function handleSuccessResponse(response, isStreaming, options) {
155
155
  return await convertSseToJson(response, responseHeaders, options);
156
156
  }
157
157
  // For streaming requests (streamText), return stream as-is
158
- return attachResponseIdCapture(response, responseHeaders, options?.onResponseId);
158
+ return attachResponseIdCapture(response, responseHeaders, options?.onResponseId, options?.onUsage);
159
159
  }
160
160
  async function safeReadBody(response) {
161
161
  try {
@@ -1,3 +1,4 @@
1
+ import type { UsageTokenCounts } from "../usage/types.js";
1
2
  /**
2
3
  * Convert SSE stream response to JSON for generateText()
3
4
  * @param response - Fetch response with SSE stream
@@ -6,6 +7,7 @@
6
7
  */
7
8
  export declare function convertSseToJson(response: Response, headers: Headers, options?: {
8
9
  onResponseId?: (responseId: string) => void;
10
+ onUsage?: (usage: UsageTokenCounts) => void;
9
11
  streamStallTimeoutMs?: number;
10
12
  }): Promise<Response>;
11
13
  /**
@@ -21,5 +23,5 @@ export declare function ensureContentType(headers: Headers): Headers;
21
23
  * @returns True if response should be considered empty/malformed
22
24
  */
23
25
  export declare function isEmptyResponse(body: unknown): boolean;
24
- export declare function attachResponseIdCapture(response: Response, headers: Headers, onResponseId?: (responseId: string) => void): Response;
26
+ export declare function attachResponseIdCapture(response: Response, headers: Headers, onResponseId?: (responseId: string) => void, onUsage?: (usage: UsageTokenCounts) => void): Response;
25
27
  //# sourceMappingURL=response-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../../lib/request/response-handler.ts"],"names":[],"mappings":"AAwwBA;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;IACT,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACC,OAAO,CAAC,QAAQ,CAAC,CA2HnB;AA6DD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ3D;AA2BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CA4CtD;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GACzC,QAAQ,CAiBV"}
1
+ {"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../../lib/request/response-handler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAqwB1D;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;IACT,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACC,OAAO,CAAC,QAAQ,CAAC,CAkInB;AAwED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ3D;AA2BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CA4CtD;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GACzC,QAAQ,CAiBV"}
@@ -1,6 +1,7 @@
1
1
  import { createLogger, logRequest, LOGGING_ENABLED } from "../logger.js";
2
2
  import { HTTP_STATUS, PLUGIN_NAME } from "../constants.js";
3
3
  import { isRecord } from "../utils.js";
4
+ import { extractResponsesUsage } from "../usage/usage-extraction.js";
4
5
  const log = createLogger("response-handler");
5
6
  const MAX_SSE_SIZE = 10 * 1024 * 1024; // 10MB limit to prevent memory exhaustion
6
7
  const DEFAULT_STREAM_STALL_TIMEOUT_MS = 45_000;
@@ -663,6 +664,15 @@ export async function convertSseToJson(response, headers, options) {
663
664
  });
664
665
  }
665
666
  logStreamDiagnostics(finalResponse);
667
+ if (options?.onUsage) {
668
+ // The non-streaming branch already holds the assembled response, so
669
+ // the token counts come straight off it. Reported even though the
670
+ // caller sees JSON rather than SSE: the usage ledger (and therefore
671
+ // the maxTokens / maxCostUsd budget caps) needs both shapes.
672
+ const usage = extractResponsesUsage(finalResponse);
673
+ if (usage)
674
+ options.onUsage(usage);
675
+ }
666
676
  // Return as plain JSON (not SSE)
667
677
  const jsonHeaders = new Headers(headers);
668
678
  jsonHeaders.set("content-type", "application/json; charset=utf-8");
@@ -685,7 +695,7 @@ export async function convertSseToJson(response, headers, options) {
685
695
  reader.releaseLock();
686
696
  }
687
697
  }
688
- function createResponseIdCapturingStream(body, onResponseId) {
698
+ function createResponseIdCapturingStream(body, onResponseId, onUsage) {
689
699
  const decoder = new TextDecoder();
690
700
  let bufferedText = "";
691
701
  let loggedMalformedStreamChunk = false;
@@ -709,7 +719,18 @@ function createResponseIdCapturingStream(body, onResponseId) {
709
719
  continue;
710
720
  try {
711
721
  const data = JSON.parse(payload);
712
- maybeCaptureResponseEvent(state, data, onResponseId);
722
+ if (onResponseId) {
723
+ maybeCaptureResponseEvent(state, data, onResponseId);
724
+ }
725
+ if (onUsage) {
726
+ // Reuse the JSON this loop already parsed rather than scanning
727
+ // the stream twice. Without these counts every usage-ledger row
728
+ // lands with zero tokens and zero cost, which silently disables
729
+ // the maxTokens / maxCostUsd budget caps.
730
+ const usage = extractResponsesUsage(data);
731
+ if (usage)
732
+ onUsage(usage);
733
+ }
713
734
  if (state.encounteredError)
714
735
  break;
715
736
  }
@@ -812,15 +833,15 @@ export function isEmptyResponse(body) {
812
833
  }
813
834
  return false;
814
835
  }
815
- export function attachResponseIdCapture(response, headers, onResponseId) {
816
- if (!response.body || !onResponseId) {
836
+ export function attachResponseIdCapture(response, headers, onResponseId, onUsage) {
837
+ if (!response.body || (!onResponseId && !onUsage)) {
817
838
  return new Response(response.body, {
818
839
  status: response.status,
819
840
  statusText: response.statusText,
820
841
  headers,
821
842
  });
822
843
  }
823
- return new Response(createResponseIdCapturingStream(response.body, onResponseId), {
844
+ return new Response(createResponseIdCapturingStream(response.body, onResponseId, onUsage), {
824
845
  status: response.status,
825
846
  statusText: response.statusText,
826
847
  headers,
@@ -4,5 +4,12 @@ export declare const HOP_BY_HOP_HEADERS: Set<string>;
4
4
  export declare function responseHeadersForClient(upstreamHeaders: Headers): Record<string, string>;
5
5
  export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, onTimeout: () => void, message: string): Promise<T>;
6
6
  export declare function readErrorBody(response: Response, timeoutMs: number, maxBytes?: number): Promise<string>;
7
- export declare function forwardStreamingResponse(upstream: Response, res: ServerResponse, status: RuntimeRotationProxyStatus, onStreamError: () => void, streamStallTimeoutMs: number): Promise<boolean>;
7
+ export declare function forwardStreamingResponse(upstream: Response, res: ServerResponse, status: RuntimeRotationProxyStatus, onStreamError: () => void, streamStallTimeoutMs: number,
8
+ /**
9
+ * Observe each forwarded chunk. Used to recover the upstream `usage` totals
10
+ * for the usage ledger without buffering the body; it must not mutate the
11
+ * chunk and is called before the write, so a slow observer delays the
12
+ * forward. Implementations are expected to swallow their own errors.
13
+ */
14
+ onChunk?: (chunk: Uint8Array) => void): Promise<boolean>;
8
15
  //# sourceMappingURL=stream-failover-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-failover-runtime.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,eAAO,MAAM,kBAAkB,aAW7B,CAAC;AAWH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzF;AAED,wBAAsB,WAAW,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,wBAAsB,aAAa,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAoBD,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,0BAA0B,EAClC,aAAa,EAAE,MAAM,IAAI,EACzB,oBAAoB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAqDlB"}
1
+ {"version":3,"file":"stream-failover-runtime.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,eAAO,MAAM,kBAAkB,aAW7B,CAAC;AAWH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzF;AAED,wBAAsB,WAAW,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,wBAAsB,aAAa,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAoBD,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,0BAA0B,EAClC,aAAa,EAAE,MAAM,IAAI,EACzB,oBAAoB,EAAE,MAAM;AAC5B;;;;;GAKG;AACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GACnC,OAAO,CAAC,OAAO,CAAC,CAsDlB"}
@@ -128,7 +128,14 @@ function waitForDrain(res) {
128
128
  res.once("error", settle);
129
129
  });
130
130
  }
131
- export async function forwardStreamingResponse(upstream, res, status, onStreamError, streamStallTimeoutMs) {
131
+ export async function forwardStreamingResponse(upstream, res, status, onStreamError, streamStallTimeoutMs,
132
+ /**
133
+ * Observe each forwarded chunk. Used to recover the upstream `usage` totals
134
+ * for the usage ledger without buffering the body; it must not mutate the
135
+ * chunk and is called before the write, so a slow observer delays the
136
+ * forward. Implementations are expected to swallow their own errors.
137
+ */
138
+ onChunk) {
132
139
  status.streamsStarted += 1;
133
140
  res.writeHead(upstream.status, responseHeadersForClient(upstream.headers));
134
141
  if (!upstream.body) {
@@ -149,6 +156,7 @@ export async function forwardStreamingResponse(upstream, res, status, onStreamEr
149
156
  if (done)
150
157
  break;
151
158
  if (value && value.byteLength > 0) {
159
+ onChunk?.(value);
152
160
  // If the response is already finished (clean end by a concurrent
153
161
  // close-then-reader-cancel path), stop writing. Do NOT guard on
154
162
  // res.destroyed here: a socket-error-during-backpressure scenario sets
@@ -1 +1 @@
1
- {"version":3,"file":"stream-failover.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkGD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACpC,eAAe,EAAE,QAAQ,EACzB,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,EACxF,OAAO,GAAE,qBAA0B,GACjC,QAAQ,CA4HV"}
1
+ {"version":3,"file":"stream-failover.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkGD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACpC,eAAe,EAAE,QAAQ,EACzB,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,EACxF,OAAO,GAAE,qBAA0B,GACjC,QAAQ,CAuKV"}
@@ -117,6 +117,34 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
117
117
  }
118
118
  let closed = false;
119
119
  let releaseCurrentReaderForCancel = null;
120
+ // Backpressure. `pump()` runs from `start()` as a free-running loop, so
121
+ // without a demand signal it enqueues every chunk upstream delivers as fast
122
+ // as it arrives and the whole stream buffers in memory for a slow consumer.
123
+ // `pull()` (and cancellation) release the loop; the sibling forwarder in
124
+ // stream-failover-runtime.ts gets the same guarantee from waitForDrain.
125
+ let demandWaiter = null;
126
+ let demandPending = false;
127
+ const signalDemand = () => {
128
+ if (demandWaiter) {
129
+ demandWaiter();
130
+ return;
131
+ }
132
+ // `pull()` can fire before the loop parks. Latch it, or the next
133
+ // awaitDemand() would block on a signal that already happened.
134
+ demandPending = true;
135
+ };
136
+ const awaitDemand = () => {
137
+ if (demandPending || closed) {
138
+ demandPending = false;
139
+ return Promise.resolve();
140
+ }
141
+ return new Promise((resolve) => {
142
+ demandWaiter = () => {
143
+ demandWaiter = null;
144
+ resolve();
145
+ };
146
+ });
147
+ };
120
148
  const body = new ReadableStream({
121
149
  start(controller) {
122
150
  let currentReader = initialResponse.body?.getReader() ?? null;
@@ -174,6 +202,13 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
174
202
  if (result.value && result.value.byteLength > 0) {
175
203
  emittedBytes += result.value.byteLength;
176
204
  controller.enqueue(result.value);
205
+ // Park until the consumer asks for more. desiredSize is
206
+ // null once the controller is errored or closed, and the
207
+ // loop's own `closed` checks cover that case.
208
+ if (typeof controller.desiredSize === "number" &&
209
+ controller.desiredSize <= 0) {
210
+ await awaitDemand();
211
+ }
177
212
  }
178
213
  }
179
214
  catch (error) {
@@ -206,8 +241,14 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
206
241
  }
207
242
  });
208
243
  },
244
+ pull() {
245
+ signalDemand();
246
+ },
209
247
  cancel() {
210
248
  closed = true;
249
+ // Release a parked pump so it observes `closed` and unwinds instead
250
+ // of holding the upstream reader open for a demand that never comes.
251
+ signalDemand();
211
252
  if (releaseCurrentReaderForCancel) {
212
253
  void releaseCurrentReaderForCancel();
213
254
  }
@@ -1 +1 @@
1
- {"version":3,"file":"account-check.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-check.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-check.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { maskEmail } from "../logger.js";
2
2
  import { CODEX_UNAVAILABLE_PROBE_NOTE } from "../quota-probe.js";
3
3
  import { isCodexUnavailableError } from "../errors.js";
4
- import { reconcilePinnedAccountIndex, } from "../storage.js";
4
+ import { bumpStorageAffinityGeneration, reconcilePinnedAccountIndex, } from "../storage.js";
5
5
  export async function runRuntimeAccountCheck(deepProbe, deps) {
6
6
  const loadedStorage = await deps.hydrateEmails(await deps.loadAccounts());
7
7
  const workingStorage = loadedStorage
@@ -195,6 +195,13 @@ export async function runRuntimeAccountCheck(deepProbe, deps) {
195
195
  workingStorage.accounts = workingStorage.accounts.filter((account) => !state.removeFromActive.has(account.refreshToken));
196
196
  deps.clampRuntimeActiveIndices(workingStorage, deps.MODEL_FAMILIES);
197
197
  workingStorage.pinnedAccountIndex = reconcilePinnedAccountIndex(pinnedAccount, workingStorage.accounts);
198
+ // The filter can drop several accounts at once, shifting every index
199
+ // after each hole. Session affinity remembers accounts BY INDEX, so
200
+ // without a generation bump a live proxy keeps routing in-flight
201
+ // sessions to whatever now occupies the old slot — and this path is
202
+ // AUTOMATIC (revoked-token accounts are removed without a prompt), so
203
+ // nothing else invalidates the affinity map. See issue #474.
204
+ bumpStorageAffinityGeneration(workingStorage);
198
205
  state.storageChanged = true;
199
206
  }
200
207
  const persistAccountAndFlaggedStorage = deps.persistAccountAndFlaggedStorage;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA4CtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8bD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA4KrC"}
1
+ {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6CtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8bD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA4KrC"}