@omnicross/core 0.1.6 → 0.1.7

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 (131) hide show
  1. package/dist/ApiConverter.cjs +2 -2
  2. package/dist/ApiConverter.js +1 -1
  3. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +4 -3
  4. package/dist/auth/GeminiCodeAssistProjectResolver.js +3 -2
  5. package/dist/{chunk-3Z5BQZFM.cjs → chunk-235MXAGX.cjs} +3 -1
  6. package/dist/{chunk-DLXZEZWO.cjs → chunk-2E42SAW3.cjs} +42 -4
  7. package/dist/{chunk-7AK7B36B.cjs → chunk-2Z4XM3H5.cjs} +6 -6
  8. package/dist/{chunk-OEWZUX4G.js → chunk-32O35CIF.js} +9 -20
  9. package/dist/chunk-3SCOLIPT.cjs +63 -0
  10. package/dist/{chunk-SYQF7OIR.js → chunk-3WD4HTR2.js} +2 -0
  11. package/dist/{chunk-SQYVORNP.cjs → chunk-4BB343BI.cjs} +527 -267
  12. package/dist/{chunk-AT7B7SOZ.js → chunk-5NJLQ6T6.js} +21 -10
  13. package/dist/chunk-5RSZYQJH.cjs +62 -0
  14. package/dist/{chunk-IFXJ2BG7.js → chunk-7C7DET6S.js} +51 -6
  15. package/dist/{chunk-UDCC7EMR.js → chunk-E3COOKUP.js} +307 -47
  16. package/dist/chunk-FU7EAR73.js +62 -0
  17. package/dist/{chunk-UX7VWA46.js → chunk-FXR6N3SR.js} +39 -1
  18. package/dist/{chunk-WYTEQ4Q5.cjs → chunk-GDIXXKF2.cjs} +21 -10
  19. package/dist/{chunk-WB6PH56J.js → chunk-GFIZ6LQI.js} +12 -8
  20. package/dist/chunk-GL6XM527.js +61 -0
  21. package/dist/{chunk-EJLH6NFT.cjs → chunk-J3QQ6JS5.cjs} +12 -8
  22. package/dist/{chunk-VRFBB5DB.js → chunk-MYYR3HZL.js} +4 -4
  23. package/dist/{chunk-YJVHCHQX.js → chunk-N7OOJI5V.js} +46 -2
  24. package/dist/chunk-NKVZ6Z3Y.cjs +61 -0
  25. package/dist/{chunk-SNYBEXLB.cjs → chunk-OJGQKHN5.cjs} +3 -1
  26. package/dist/chunk-OTZC4TNH.cjs +79 -0
  27. package/dist/{chunk-6VUQPOV3.cjs → chunk-OVQBNVSV.cjs} +10 -21
  28. package/dist/{chunk-4VLRHHFE.cjs → chunk-OXHNSZ53.cjs} +9 -11
  29. package/dist/{chunk-6CL5HTPQ.js → chunk-PEGTIPB3.js} +8 -10
  30. package/dist/chunk-PO3XB56Z.js +79 -0
  31. package/dist/{chunk-SIZQQD6T.js → chunk-RJ5ZGNI3.js} +42 -5
  32. package/dist/{chunk-KCVJWJST.cjs → chunk-RJUONLUQ.cjs} +47 -10
  33. package/dist/{chunk-BPKCU575.js → chunk-SOO562NM.js} +3 -1
  34. package/dist/{chunk-UNWKG6EI.cjs → chunk-XPIOJQS2.cjs} +51 -6
  35. package/dist/chunk-XXFYLL7R.js +63 -0
  36. package/dist/{chunk-YK57NMIF.cjs → chunk-YWL7YZWS.cjs} +47 -3
  37. package/dist/completion/CompletionService.cjs +23 -19
  38. package/dist/completion/CompletionService.d.cts +1 -0
  39. package/dist/completion/CompletionService.d.ts +1 -0
  40. package/dist/completion/CompletionService.js +22 -18
  41. package/dist/completion.cjs +23 -19
  42. package/dist/completion.d.cts +1 -0
  43. package/dist/completion.d.ts +1 -0
  44. package/dist/completion.js +22 -18
  45. package/dist/index.cjs +26 -22
  46. package/dist/index.d.cts +2 -2
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.js +26 -22
  49. package/dist/outbound-api/auditCapture.cjs +2 -2
  50. package/dist/outbound-api/auditCapture.d.cts +3 -4
  51. package/dist/outbound-api/auditCapture.d.ts +3 -4
  52. package/dist/outbound-api/auditCapture.js +1 -1
  53. package/dist/outbound-api/routeResolver.d.cts +3 -2
  54. package/dist/outbound-api/routeResolver.d.ts +3 -2
  55. package/dist/outbound-api/subscriptionRegistryPort.d.cts +1 -0
  56. package/dist/outbound-api/subscriptionRegistryPort.d.ts +1 -0
  57. package/dist/outbound-api/types.d.cts +2 -1
  58. package/dist/outbound-api/types.d.ts +2 -1
  59. package/dist/outbound-api.cjs +23 -19
  60. package/dist/outbound-api.d.cts +7 -5
  61. package/dist/outbound-api.d.ts +7 -5
  62. package/dist/outbound-api.js +22 -18
  63. package/dist/pipeline/AccountAllowanceScheduling.d.cts +2 -1
  64. package/dist/pipeline/AccountAllowanceScheduling.d.ts +2 -1
  65. package/dist/pipeline/AccountRouteActivity.cjs +10 -0
  66. package/dist/pipeline/AccountRouteActivity.d.cts +61 -0
  67. package/dist/pipeline/AccountRouteActivity.d.ts +61 -0
  68. package/dist/pipeline/AccountRouteActivity.js +10 -0
  69. package/dist/pipeline/ServerOverloadCounter.cjs +16 -0
  70. package/dist/pipeline/ServerOverloadCounter.d.cts +77 -0
  71. package/dist/pipeline/ServerOverloadCounter.d.ts +77 -0
  72. package/dist/pipeline/ServerOverloadCounter.js +16 -0
  73. package/dist/pipeline/SubscriptionAccountHealth.cjs +4 -2
  74. package/dist/pipeline/SubscriptionAccountHealth.d.cts +32 -3
  75. package/dist/pipeline/SubscriptionAccountHealth.d.ts +32 -3
  76. package/dist/pipeline/SubscriptionAccountHealth.js +3 -1
  77. package/dist/pipeline/upstreamFetch.cjs +4 -3
  78. package/dist/pipeline/upstreamFetch.d.cts +35 -6
  79. package/dist/pipeline/upstreamFetch.d.ts +35 -6
  80. package/dist/pipeline/upstreamFetch.js +3 -2
  81. package/dist/pipeline/upstreamTrace.cjs +4 -2
  82. package/dist/pipeline/upstreamTrace.d.cts +22 -8
  83. package/dist/pipeline/upstreamTrace.d.ts +22 -8
  84. package/dist/pipeline/upstreamTrace.js +3 -1
  85. package/dist/ports.d.cts +1 -1
  86. package/dist/ports.d.ts +1 -1
  87. package/dist/provider-proxy/ProviderProxy.cjs +23 -19
  88. package/dist/provider-proxy/ProviderProxy.d.cts +1 -0
  89. package/dist/provider-proxy/ProviderProxy.d.ts +1 -0
  90. package/dist/provider-proxy/ProviderProxy.js +22 -18
  91. package/dist/provider-proxy/identity/codexCliHeaders.cjs +10 -0
  92. package/dist/provider-proxy/identity/codexCliHeaders.d.cts +45 -0
  93. package/dist/provider-proxy/identity/codexCliHeaders.d.ts +45 -0
  94. package/dist/provider-proxy/identity/codexCliHeaders.js +10 -0
  95. package/dist/provider-proxy/ingress/providerProxyShared.cjs +23 -19
  96. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -1
  97. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -1
  98. package/dist/provider-proxy/ingress/providerProxyShared.js +22 -18
  99. package/dist/provider-proxy/matchText.cjs +2 -2
  100. package/dist/provider-proxy/matchText.d.cts +1 -3
  101. package/dist/provider-proxy/matchText.d.ts +1 -3
  102. package/dist/provider-proxy/matchText.js +1 -1
  103. package/dist/provider-proxy/types.d.cts +5 -0
  104. package/dist/provider-proxy/types.d.ts +5 -0
  105. package/dist/provider-proxy.cjs +23 -19
  106. package/dist/provider-proxy.d.cts +1 -0
  107. package/dist/provider-proxy.d.ts +1 -0
  108. package/dist/provider-proxy.js +22 -18
  109. package/dist/{routeResolver-CHTv_Bs5.d.ts → routeResolver-BxOfunbm.d.ts} +1 -1
  110. package/dist/{routeResolver-kepxnfcC.d.cts → routeResolver-D5OzD0iM.d.cts} +1 -1
  111. package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -2
  112. package/dist/transformer/transformers/AnthropicTransformer.js +2 -1
  113. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -2
  114. package/dist/transformer/transformers/OpenAIResponseTransformer.js +2 -1
  115. package/dist/transformer/transformers.cjs +7 -6
  116. package/dist/transformer/transformers.js +6 -5
  117. package/dist/transformer.cjs +9 -8
  118. package/dist/transformer.js +8 -7
  119. package/dist/{types-hsoKrVQS.d.ts → types-CqZD77rS.d.ts} +39 -0
  120. package/dist/{types-H3wGZSOo.d.cts → types-gjJ5lJ5n.d.cts} +39 -0
  121. package/dist/usage/pricing-engine.cjs +2 -2
  122. package/dist/usage/pricing-engine.d.cts +20 -0
  123. package/dist/usage/pricing-engine.d.ts +20 -0
  124. package/dist/usage/pricing-engine.js +1 -1
  125. package/dist/usage/usage-recorder.cjs +2 -2
  126. package/dist/usage/usage-recorder.d.cts +5 -1
  127. package/dist/usage/usage-recorder.d.ts +5 -1
  128. package/dist/usage/usage-recorder.js +1 -1
  129. package/dist/usage.cjs +3 -3
  130. package/dist/usage.js +2 -2
  131. package/package.json +1 -1
@@ -0,0 +1,77 @@
1
+ import { AccountRouteEndpoint } from './AccountRouteActivity.cjs';
2
+
3
+ /**
4
+ * ServerOverloadCounter — a bounded, metadata-only tally of Codex server-
5
+ * overload events (`response.failed` with `error.code` `server_is_overloaded` /
6
+ * `slow_down`) per provider+account+endpoint.
7
+ *
8
+ * WHY a dedicated store (not derived from {@link AccountRouteActivity}): those
9
+ * 200-status overloads are invisible at the route-activity HTTP-status layer, and
10
+ * the route-activity ring (300 rows) can be pushed out by normal traffic before
11
+ * an operator notices. This counter ACCUMULATES across the ring and keeps a
12
+ * bounded recent-timestamp ring for a trend sparkline, so "how often is account X
13
+ * being overloaded, and is it worsening" stays answerable.
14
+ *
15
+ * Overload is account-INDEPENDENT server capacity (retrying on another account is
16
+ * pointless), so — unlike {@link SubscriptionAccountHealth} — this store only
17
+ * OBSERVES; it never gates scheduling. It carries no secrets, only counts + epoch
18
+ * timestamps. In-memory (cleared on restart), same as the other pipeline stores.
19
+ *
20
+ * Shaped like `SubscriptionAccountHealth`: an in-memory `Map`, an injectable
21
+ * `now` clock, no external deps, opaque `providerId\0accountId\0endpoint` keys.
22
+ *
23
+ * @module pipeline/ServerOverloadCounter
24
+ */
25
+
26
+ /** Bounded recent-event ring per entry — the sparkline's data source. */
27
+ declare const OVERLOAD_RECENT_LIMIT = 64;
28
+ /**
29
+ * Entries with no event in this window are pruned on read, so the map cannot
30
+ * grow unbounded across a long-lived process with many transient accounts.
31
+ */
32
+ declare const OVERLOAD_ENTRY_TTL_MS: number;
33
+ interface OverloadRecordInput {
34
+ providerId: string;
35
+ accountId: string;
36
+ endpoint: AccountRouteEndpoint;
37
+ /** Epoch-ms of the event. Omit to use the clock default. */
38
+ now?: number;
39
+ }
40
+ interface OverloadCounterEntry {
41
+ providerId: string;
42
+ accountId: string;
43
+ endpoint: AccountRouteEndpoint;
44
+ /** Lifetime count of overload events for this key (since first observed). */
45
+ count: number;
46
+ firstTs: number;
47
+ lastTs: number;
48
+ /** Most-recent-first epoch-ms events, capped at {@link OVERLOAD_RECENT_LIMIT}. */
49
+ recent: number[];
50
+ }
51
+ interface OverloadCounterQuery {
52
+ providerId?: string;
53
+ accountId?: string;
54
+ }
55
+ declare class ServerOverloadCounterStore {
56
+ private readonly entries;
57
+ /**
58
+ * Record one overload event. Creates the entry on first sight, then bumps
59
+ * `count`, `lastTs`, and prepends the event to the bounded `recent` ring.
60
+ */
61
+ recordOverload(input: OverloadRecordInput, now?: number): OverloadCounterEntry;
62
+ /**
63
+ * Snapshot all (optionally filtered) entries, pruning stale ones first. Returns
64
+ * copies — callers (admin API → JSON) never see the live mutable entries.
65
+ */
66
+ list(query?: OverloadCounterQuery, now?: number): OverloadCounterEntry[];
67
+ clear(): void;
68
+ }
69
+ declare function getSharedOverloadCounter(): ServerOverloadCounterStore;
70
+ /**
71
+ * TEST SEAM — swap the singleton (e.g. with a fresh instance). Mirrors the
72
+ * `setShared…`/`__reset…ForTests` discipline of the sibling pipeline stores.
73
+ */
74
+ declare function setSharedOverloadCounter(instance: ServerOverloadCounterStore): void;
75
+ declare function __resetSharedOverloadCounterForTests(): void;
76
+
77
+ export { OVERLOAD_ENTRY_TTL_MS, OVERLOAD_RECENT_LIMIT, type OverloadCounterEntry, type OverloadCounterQuery, type OverloadRecordInput, ServerOverloadCounterStore, __resetSharedOverloadCounterForTests, getSharedOverloadCounter, setSharedOverloadCounter };
@@ -0,0 +1,77 @@
1
+ import { AccountRouteEndpoint } from './AccountRouteActivity.js';
2
+
3
+ /**
4
+ * ServerOverloadCounter — a bounded, metadata-only tally of Codex server-
5
+ * overload events (`response.failed` with `error.code` `server_is_overloaded` /
6
+ * `slow_down`) per provider+account+endpoint.
7
+ *
8
+ * WHY a dedicated store (not derived from {@link AccountRouteActivity}): those
9
+ * 200-status overloads are invisible at the route-activity HTTP-status layer, and
10
+ * the route-activity ring (300 rows) can be pushed out by normal traffic before
11
+ * an operator notices. This counter ACCUMULATES across the ring and keeps a
12
+ * bounded recent-timestamp ring for a trend sparkline, so "how often is account X
13
+ * being overloaded, and is it worsening" stays answerable.
14
+ *
15
+ * Overload is account-INDEPENDENT server capacity (retrying on another account is
16
+ * pointless), so — unlike {@link SubscriptionAccountHealth} — this store only
17
+ * OBSERVES; it never gates scheduling. It carries no secrets, only counts + epoch
18
+ * timestamps. In-memory (cleared on restart), same as the other pipeline stores.
19
+ *
20
+ * Shaped like `SubscriptionAccountHealth`: an in-memory `Map`, an injectable
21
+ * `now` clock, no external deps, opaque `providerId\0accountId\0endpoint` keys.
22
+ *
23
+ * @module pipeline/ServerOverloadCounter
24
+ */
25
+
26
+ /** Bounded recent-event ring per entry — the sparkline's data source. */
27
+ declare const OVERLOAD_RECENT_LIMIT = 64;
28
+ /**
29
+ * Entries with no event in this window are pruned on read, so the map cannot
30
+ * grow unbounded across a long-lived process with many transient accounts.
31
+ */
32
+ declare const OVERLOAD_ENTRY_TTL_MS: number;
33
+ interface OverloadRecordInput {
34
+ providerId: string;
35
+ accountId: string;
36
+ endpoint: AccountRouteEndpoint;
37
+ /** Epoch-ms of the event. Omit to use the clock default. */
38
+ now?: number;
39
+ }
40
+ interface OverloadCounterEntry {
41
+ providerId: string;
42
+ accountId: string;
43
+ endpoint: AccountRouteEndpoint;
44
+ /** Lifetime count of overload events for this key (since first observed). */
45
+ count: number;
46
+ firstTs: number;
47
+ lastTs: number;
48
+ /** Most-recent-first epoch-ms events, capped at {@link OVERLOAD_RECENT_LIMIT}. */
49
+ recent: number[];
50
+ }
51
+ interface OverloadCounterQuery {
52
+ providerId?: string;
53
+ accountId?: string;
54
+ }
55
+ declare class ServerOverloadCounterStore {
56
+ private readonly entries;
57
+ /**
58
+ * Record one overload event. Creates the entry on first sight, then bumps
59
+ * `count`, `lastTs`, and prepends the event to the bounded `recent` ring.
60
+ */
61
+ recordOverload(input: OverloadRecordInput, now?: number): OverloadCounterEntry;
62
+ /**
63
+ * Snapshot all (optionally filtered) entries, pruning stale ones first. Returns
64
+ * copies — callers (admin API → JSON) never see the live mutable entries.
65
+ */
66
+ list(query?: OverloadCounterQuery, now?: number): OverloadCounterEntry[];
67
+ clear(): void;
68
+ }
69
+ declare function getSharedOverloadCounter(): ServerOverloadCounterStore;
70
+ /**
71
+ * TEST SEAM — swap the singleton (e.g. with a fresh instance). Mirrors the
72
+ * `setShared…`/`__reset…ForTests` discipline of the sibling pipeline stores.
73
+ */
74
+ declare function setSharedOverloadCounter(instance: ServerOverloadCounterStore): void;
75
+ declare function __resetSharedOverloadCounterForTests(): void;
76
+
77
+ export { OVERLOAD_ENTRY_TTL_MS, OVERLOAD_RECENT_LIMIT, type OverloadCounterEntry, type OverloadCounterQuery, type OverloadRecordInput, ServerOverloadCounterStore, __resetSharedOverloadCounterForTests, getSharedOverloadCounter, setSharedOverloadCounter };
@@ -0,0 +1,16 @@
1
+ import {
2
+ OVERLOAD_ENTRY_TTL_MS,
3
+ OVERLOAD_RECENT_LIMIT,
4
+ ServerOverloadCounterStore,
5
+ __resetSharedOverloadCounterForTests,
6
+ getSharedOverloadCounter,
7
+ setSharedOverloadCounter
8
+ } from "../chunk-PO3XB56Z.js";
9
+ export {
10
+ OVERLOAD_ENTRY_TTL_MS,
11
+ OVERLOAD_RECENT_LIMIT,
12
+ ServerOverloadCounterStore,
13
+ __resetSharedOverloadCounterForTests,
14
+ getSharedOverloadCounter,
15
+ setSharedOverloadCounter
16
+ };
@@ -9,8 +9,8 @@
9
9
 
10
10
 
11
11
 
12
- var _chunkYK57NMIFcjs = require('../chunk-YK57NMIF.cjs');
13
12
 
13
+ var _chunkYWL7YZWScjs = require('../chunk-YWL7YZWS.cjs');
14
14
 
15
15
 
16
16
 
@@ -21,4 +21,6 @@ var _chunkYK57NMIFcjs = require('../chunk-YK57NMIF.cjs');
21
21
 
22
22
 
23
23
 
24
- exports.ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT = _chunkYK57NMIFcjs.ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT; exports.AUTH_ERROR_TTL_MS = _chunkYK57NMIFcjs.AUTH_ERROR_TTL_MS; exports.OVERLOAD_ENABLED_DEFAULT = _chunkYK57NMIFcjs.OVERLOAD_ENABLED_DEFAULT; exports.OVERLOAD_TTL_MS = _chunkYK57NMIFcjs.OVERLOAD_TTL_MS; exports.SERVER_ERROR_TTL_MS = _chunkYK57NMIFcjs.SERVER_ERROR_TTL_MS; exports.SubscriptionAccountHealth = _chunkYK57NMIFcjs.SubscriptionAccountHealth; exports.__resetSharedAccountHealthForTests = _chunkYK57NMIFcjs.__resetSharedAccountHealthForTests; exports.getSharedAccountHealth = _chunkYK57NMIFcjs.getSharedAccountHealth; exports.resolveResetSeconds = _chunkYK57NMIFcjs.resolveResetSeconds; exports.setSharedAccountHealth = _chunkYK57NMIFcjs.setSharedAccountHealth;
24
+
25
+
26
+ exports.ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT = _chunkYWL7YZWScjs.ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT; exports.AUTH_ERROR_TTL_MS = _chunkYWL7YZWScjs.AUTH_ERROR_TTL_MS; exports.MAX_QUOTA_COOLDOWN_MS = _chunkYWL7YZWScjs.MAX_QUOTA_COOLDOWN_MS; exports.OVERLOAD_ENABLED_DEFAULT = _chunkYWL7YZWScjs.OVERLOAD_ENABLED_DEFAULT; exports.OVERLOAD_TTL_MS = _chunkYWL7YZWScjs.OVERLOAD_TTL_MS; exports.SERVER_ERROR_TTL_MS = _chunkYWL7YZWScjs.SERVER_ERROR_TTL_MS; exports.SubscriptionAccountHealth = _chunkYWL7YZWScjs.SubscriptionAccountHealth; exports.__resetSharedAccountHealthForTests = _chunkYWL7YZWScjs.__resetSharedAccountHealthForTests; exports.getSharedAccountHealth = _chunkYWL7YZWScjs.getSharedAccountHealth; exports.resolveResetSeconds = _chunkYWL7YZWScjs.resolveResetSeconds; exports.setSharedAccountHealth = _chunkYWL7YZWScjs.setSharedAccountHealth;
@@ -31,6 +31,12 @@ declare const OVERLOAD_ENABLED_DEFAULT = true;
31
31
  declare const AUTH_ERROR_TTL_MS: number;
32
32
  /** Transient cooldown for a 5xx response or network failure. */
33
33
  declare const SERVER_ERROR_TTL_MS: number;
34
+ /**
35
+ * Hard cap on a quota-exhaustion cooldown (the weekly usage window is ~1 week).
36
+ * A parsed/supplied deadline farther than this into the future is clamped, so a
37
+ * bogus parse can never strand an account indefinitely.
38
+ */
39
+ declare const MAX_QUOTA_COOLDOWN_MS: number;
34
40
  /** Per-account health record (all timers are epoch ms). Absent fields ⇒ healthy. */
35
41
  interface HealthRecord {
36
42
  /** From a 429 authoritative reset header — rate-limited until this instant. */
@@ -39,11 +45,20 @@ interface HealthRecord {
39
45
  overloadUntil?: number;
40
46
  /** From a final-401 / plain-403 / 5xx / thrown — transient cooldown until this. */
41
47
  tempUnavailableUntil?: number;
48
+ /**
49
+ * From a detected quota/usage-limit error (e.g. Codex weekly window exhausted).
50
+ * Intentionally NOT cleared by a 2xx: while the account's credits/window are
51
+ * exhausted, in-flight sessions on the SAME account keep returning 2xx (Codex
52
+ * does not kill them mid-session), which would otherwise immediately heal a
53
+ * transient/rate-limit mark and re-strand every NEW session onto this account.
54
+ * Self-heals only when the deadline elapses.
55
+ */
56
+ quotaExhaustedUntil?: number;
42
57
  /** From a 403-ban — permanent, self-heal never clears it. */
43
58
  blocked?: boolean;
44
59
  }
45
60
  /** The coarse health state surfaced to the admin accounts view (secret-free). */
46
- type AccountHealthState = 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'blocked';
61
+ type AccountHealthState = 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'quota_exhausted' | 'blocked';
47
62
  /** Admin-facing status projection for one account. */
48
63
  interface AccountHealthStatus {
49
64
  state: AccountHealthState;
@@ -68,7 +83,7 @@ interface AccountRecoveryEvent {
68
83
  /** A recovery listener (fire-and-forget; the emitter never awaits it). */
69
84
  type AccountRecoveryListener = (event: AccountRecoveryEvent) => void;
70
85
  /** The coarse anomaly state an account transitioned into (secret-free). */
71
- type AccountAnomalyState = 'blocked' | 'unauthorized' | 'rate_limited' | 'overloaded';
86
+ type AccountAnomalyState = 'blocked' | 'unauthorized' | 'rate_limited' | 'overloaded' | 'quota_exhausted';
72
87
  /**
73
88
  * The anomaly signal emitted when a HEALTHY account transitions to unhealthy —
74
89
  * the additive union #5 (webhooks) consumes, which this tracker's frozen `kind`
@@ -192,6 +207,20 @@ declare class SubscriptionAccountHealth {
192
207
  * - 2xx → clear rate-limit + transient state (keep `blocked`).
193
208
  */
194
209
  recordUpstreamOutcome(providerId: string, accountId: string, input: RecordUpstreamOutcomeInput): void;
210
+ /**
211
+ * Mark an account quota/usage-exhausted until `untilEpochMs` (the Codex weekly
212
+ * usage-limit wall). Unlike the status-driven timers set by
213
+ * {@link recordUpstreamOutcome}, this mark is NOT cleared by a 2xx: in-flight
214
+ * sessions on the same account keep succeeding after the window is exhausted,
215
+ * so a traffic-driven clear would re-strand every NEW session onto this
216
+ * account. It excludes the account from NEW-session selection until the
217
+ * deadline elapses (existing sessions are unaffected — they already hold their
218
+ * token). Self-heals lazily on read and via {@link sweepRecoveries}.
219
+ * `untilEpochMs` is clamped to {@link MAX_QUOTA_COOLDOWN_MS}; an already-elapsed
220
+ * deadline is a no-op. Emits a `quota_exhausted` anomaly on the healthy→
221
+ * unhealthy edge.
222
+ */
223
+ markQuotaExhausted(providerId: string, accountId: string, untilEpochMs: number, now?: number): void;
195
224
  /** Whether a record is unhealthy at `now`: blocked, or any timer still future. */
196
225
  private isUnhealthyAt;
197
226
  /**
@@ -260,4 +289,4 @@ declare function setSharedAccountHealth(instance: SubscriptionAccountHealth): vo
260
289
  /** Reset the shared singleton (tests / teardown only). */
261
290
  declare function __resetSharedAccountHealthForTests(): void;
262
291
 
263
- export { ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT, AUTH_ERROR_TTL_MS, type AccountAnomalyEvent, type AccountAnomalyListener, type AccountAnomalyState, type AccountHealthDiagnostic, type AccountHealthDiagnosticFilter, type AccountHealthState, type AccountHealthStatus, type AccountRecoveryEvent, type AccountRecoveryListener, type HeadersLike, type HealthRecord, OVERLOAD_ENABLED_DEFAULT, OVERLOAD_TTL_MS, type RecordUpstreamOutcomeInput, SERVER_ERROR_TTL_MS, SubscriptionAccountHealth, type SubscriptionAccountHealthOptions, __resetSharedAccountHealthForTests, getSharedAccountHealth, resolveResetSeconds, setSharedAccountHealth };
292
+ export { ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT, AUTH_ERROR_TTL_MS, type AccountAnomalyEvent, type AccountAnomalyListener, type AccountAnomalyState, type AccountHealthDiagnostic, type AccountHealthDiagnosticFilter, type AccountHealthState, type AccountHealthStatus, type AccountRecoveryEvent, type AccountRecoveryListener, type HeadersLike, type HealthRecord, MAX_QUOTA_COOLDOWN_MS, OVERLOAD_ENABLED_DEFAULT, OVERLOAD_TTL_MS, type RecordUpstreamOutcomeInput, SERVER_ERROR_TTL_MS, SubscriptionAccountHealth, type SubscriptionAccountHealthOptions, __resetSharedAccountHealthForTests, getSharedAccountHealth, resolveResetSeconds, setSharedAccountHealth };
@@ -31,6 +31,12 @@ declare const OVERLOAD_ENABLED_DEFAULT = true;
31
31
  declare const AUTH_ERROR_TTL_MS: number;
32
32
  /** Transient cooldown for a 5xx response or network failure. */
33
33
  declare const SERVER_ERROR_TTL_MS: number;
34
+ /**
35
+ * Hard cap on a quota-exhaustion cooldown (the weekly usage window is ~1 week).
36
+ * A parsed/supplied deadline farther than this into the future is clamped, so a
37
+ * bogus parse can never strand an account indefinitely.
38
+ */
39
+ declare const MAX_QUOTA_COOLDOWN_MS: number;
34
40
  /** Per-account health record (all timers are epoch ms). Absent fields ⇒ healthy. */
35
41
  interface HealthRecord {
36
42
  /** From a 429 authoritative reset header — rate-limited until this instant. */
@@ -39,11 +45,20 @@ interface HealthRecord {
39
45
  overloadUntil?: number;
40
46
  /** From a final-401 / plain-403 / 5xx / thrown — transient cooldown until this. */
41
47
  tempUnavailableUntil?: number;
48
+ /**
49
+ * From a detected quota/usage-limit error (e.g. Codex weekly window exhausted).
50
+ * Intentionally NOT cleared by a 2xx: while the account's credits/window are
51
+ * exhausted, in-flight sessions on the SAME account keep returning 2xx (Codex
52
+ * does not kill them mid-session), which would otherwise immediately heal a
53
+ * transient/rate-limit mark and re-strand every NEW session onto this account.
54
+ * Self-heals only when the deadline elapses.
55
+ */
56
+ quotaExhaustedUntil?: number;
42
57
  /** From a 403-ban — permanent, self-heal never clears it. */
43
58
  blocked?: boolean;
44
59
  }
45
60
  /** The coarse health state surfaced to the admin accounts view (secret-free). */
46
- type AccountHealthState = 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'blocked';
61
+ type AccountHealthState = 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'quota_exhausted' | 'blocked';
47
62
  /** Admin-facing status projection for one account. */
48
63
  interface AccountHealthStatus {
49
64
  state: AccountHealthState;
@@ -68,7 +83,7 @@ interface AccountRecoveryEvent {
68
83
  /** A recovery listener (fire-and-forget; the emitter never awaits it). */
69
84
  type AccountRecoveryListener = (event: AccountRecoveryEvent) => void;
70
85
  /** The coarse anomaly state an account transitioned into (secret-free). */
71
- type AccountAnomalyState = 'blocked' | 'unauthorized' | 'rate_limited' | 'overloaded';
86
+ type AccountAnomalyState = 'blocked' | 'unauthorized' | 'rate_limited' | 'overloaded' | 'quota_exhausted';
72
87
  /**
73
88
  * The anomaly signal emitted when a HEALTHY account transitions to unhealthy —
74
89
  * the additive union #5 (webhooks) consumes, which this tracker's frozen `kind`
@@ -192,6 +207,20 @@ declare class SubscriptionAccountHealth {
192
207
  * - 2xx → clear rate-limit + transient state (keep `blocked`).
193
208
  */
194
209
  recordUpstreamOutcome(providerId: string, accountId: string, input: RecordUpstreamOutcomeInput): void;
210
+ /**
211
+ * Mark an account quota/usage-exhausted until `untilEpochMs` (the Codex weekly
212
+ * usage-limit wall). Unlike the status-driven timers set by
213
+ * {@link recordUpstreamOutcome}, this mark is NOT cleared by a 2xx: in-flight
214
+ * sessions on the same account keep succeeding after the window is exhausted,
215
+ * so a traffic-driven clear would re-strand every NEW session onto this
216
+ * account. It excludes the account from NEW-session selection until the
217
+ * deadline elapses (existing sessions are unaffected — they already hold their
218
+ * token). Self-heals lazily on read and via {@link sweepRecoveries}.
219
+ * `untilEpochMs` is clamped to {@link MAX_QUOTA_COOLDOWN_MS}; an already-elapsed
220
+ * deadline is a no-op. Emits a `quota_exhausted` anomaly on the healthy→
221
+ * unhealthy edge.
222
+ */
223
+ markQuotaExhausted(providerId: string, accountId: string, untilEpochMs: number, now?: number): void;
195
224
  /** Whether a record is unhealthy at `now`: blocked, or any timer still future. */
196
225
  private isUnhealthyAt;
197
226
  /**
@@ -260,4 +289,4 @@ declare function setSharedAccountHealth(instance: SubscriptionAccountHealth): vo
260
289
  /** Reset the shared singleton (tests / teardown only). */
261
290
  declare function __resetSharedAccountHealthForTests(): void;
262
291
 
263
- export { ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT, AUTH_ERROR_TTL_MS, type AccountAnomalyEvent, type AccountAnomalyListener, type AccountAnomalyState, type AccountHealthDiagnostic, type AccountHealthDiagnosticFilter, type AccountHealthState, type AccountHealthStatus, type AccountRecoveryEvent, type AccountRecoveryListener, type HeadersLike, type HealthRecord, OVERLOAD_ENABLED_DEFAULT, OVERLOAD_TTL_MS, type RecordUpstreamOutcomeInput, SERVER_ERROR_TTL_MS, SubscriptionAccountHealth, type SubscriptionAccountHealthOptions, __resetSharedAccountHealthForTests, getSharedAccountHealth, resolveResetSeconds, setSharedAccountHealth };
292
+ export { ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT, AUTH_ERROR_TTL_MS, type AccountAnomalyEvent, type AccountAnomalyListener, type AccountAnomalyState, type AccountHealthDiagnostic, type AccountHealthDiagnosticFilter, type AccountHealthState, type AccountHealthStatus, type AccountRecoveryEvent, type AccountRecoveryListener, type HeadersLike, type HealthRecord, MAX_QUOTA_COOLDOWN_MS, OVERLOAD_ENABLED_DEFAULT, OVERLOAD_TTL_MS, type RecordUpstreamOutcomeInput, SERVER_ERROR_TTL_MS, SubscriptionAccountHealth, type SubscriptionAccountHealthOptions, __resetSharedAccountHealthForTests, getSharedAccountHealth, resolveResetSeconds, setSharedAccountHealth };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT,
3
3
  AUTH_ERROR_TTL_MS,
4
+ MAX_QUOTA_COOLDOWN_MS,
4
5
  OVERLOAD_ENABLED_DEFAULT,
5
6
  OVERLOAD_TTL_MS,
6
7
  SERVER_ERROR_TTL_MS,
@@ -9,10 +10,11 @@ import {
9
10
  getSharedAccountHealth,
10
11
  resolveResetSeconds,
11
12
  setSharedAccountHealth
12
- } from "../chunk-YJVHCHQX.js";
13
+ } from "../chunk-N7OOJI5V.js";
13
14
  export {
14
15
  ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT,
15
16
  AUTH_ERROR_TTL_MS,
17
+ MAX_QUOTA_COOLDOWN_MS,
16
18
  OVERLOAD_ENABLED_DEFAULT,
17
19
  OVERLOAD_TTL_MS,
18
20
  SERVER_ERROR_TTL_MS,
@@ -4,13 +4,14 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkKCVJWJSTcjs = require('../chunk-KCVJWJST.cjs');
8
- require('../chunk-3Z5BQZFM.cjs');
7
+ var _chunkRJUONLUQcjs = require('../chunk-RJUONLUQ.cjs');
8
+ require('../chunk-235MXAGX.cjs');
9
9
  require('../chunk-HVBBDBS3.cjs');
10
+ require('../chunk-NKVZ6Z3Y.cjs');
10
11
 
11
12
 
12
13
 
13
14
 
14
15
 
15
16
 
16
- exports.__resetUpstreamProxyForTests = _chunkKCVJWJSTcjs.__resetUpstreamProxyForTests; exports.bumpUpstreamProxyGeneration = _chunkKCVJWJSTcjs.bumpUpstreamProxyGeneration; exports.fetchUpstream = _chunkKCVJWJSTcjs.fetchUpstream; exports.resolveUpstreamDispatcher = _chunkKCVJWJSTcjs.resolveUpstreamDispatcher; exports.setUpstreamProxyResolver = _chunkKCVJWJSTcjs.setUpstreamProxyResolver;
17
+ exports.__resetUpstreamProxyForTests = _chunkRJUONLUQcjs.__resetUpstreamProxyForTests; exports.bumpUpstreamProxyGeneration = _chunkRJUONLUQcjs.bumpUpstreamProxyGeneration; exports.fetchUpstream = _chunkRJUONLUQcjs.fetchUpstream; exports.resolveUpstreamDispatcher = _chunkRJUONLUQcjs.resolveUpstreamDispatcher; exports.setUpstreamProxyResolver = _chunkRJUONLUQcjs.setUpstreamProxyResolver;
@@ -1,5 +1,6 @@
1
1
  import { ProxyConfig } from '@omnicross/contracts/account-tokens-types';
2
2
  import { Dispatcher } from 'undici';
3
+ import { AccountRouteEndpoint, AccountRouteSessionSource, AccountRouteActivityRecord } from './AccountRouteActivity.cjs';
3
4
 
4
5
  /**
5
6
  * upstreamFetch — the single proxy-aware egress seam for `@omnicross/core`
@@ -28,27 +29,55 @@ import { Dispatcher } from 'undici';
28
29
  * FROZEN SEAM: `#7` (client fingerprint) attaches per-account TLS/agent behavior
29
30
  * at this SAME dispatcher point — do not fork a second egress path.
30
31
  *
31
- * DEBUG TRACE: when the daemon installs an upstream-trace path (gated on the
32
- * audit `captureBodies` opt-in), relay calls (`ctx.providerId` set) clone the
33
- * response and append the FULL exchange (request + verbatim response incl. SSE)
34
- * to the trace file. Absent a path (the default) it is a pure no-op — zero
35
- * regression. See `upstreamTrace.ts`.
32
+ * DEBUG TRACE: when a diagnostic caller explicitly installs an upstream-trace
33
+ * path, relay calls (`ctx.providerId` set) clone the response and append the
34
+ * FULL exchange (request + verbatim response incl. SSE) to the trace file. The
35
+ * daemon audit runtime never installs this path, preventing duplicate body
36
+ * storage. Absent a path (the default) it is a pure no-op — zero regression.
36
37
  *
37
38
  * @module @omnicross/core/pipeline/upstreamFetch
38
39
  */
39
40
 
41
+ interface AccountRouteActivityContext {
42
+ endpoint: AccountRouteEndpoint;
43
+ sessionKey?: string;
44
+ sessionSource: AccountRouteSessionSource;
45
+ model: string;
46
+ /**
47
+ * Invoked once with the freshly-recorded activity record. Lets a caller
48
+ * capture the record `id` so it can {@link AccountRouteActivityStore.amend}
49
+ * the SAME row later, once a post-hoc fact (e.g. an overload event buried in
50
+ * the 200 SSE body) becomes known during relay. Best-effort: never throws.
51
+ */
52
+ onRecorded?: (record: AccountRouteActivityRecord) => void;
53
+ }
40
54
  /** The opaque call context the resolver maps to a proxy (precedence input). */
41
55
  interface UpstreamProxyContext {
42
56
  /** The subscription provider id (`claude`/`codex`/`gemini`/`opencodego`) or `'byo'`. */
43
57
  providerId?: string;
44
58
  /** The selected pooled account id (per-account override input). */
45
59
  accountId?: string;
60
+ /** Metadata-only live route activity. Never contains prompts, headers, or tokens. */
61
+ routeActivity?: AccountRouteActivityContext;
46
62
  /**
47
63
  * The target upstream URL. Injected by {@link fetchUpstream} so the resolver can
48
64
  * apply host-based bypass (loopback / `NO_PROXY`). Callers of the ingress helpers
49
65
  * do NOT set this — it is filled from the fetch `url`.
50
66
  */
51
67
  url?: string;
68
+ /**
69
+ * CREDENTIAL EXCHANGE — this call's request/response BODIES carry secrets (an
70
+ * authorization code + PKCE verifier out, an access/refresh token back), so the
71
+ * debug trace must record the exchange's METADATA only and replace both bodies
72
+ * with a placeholder.
73
+ *
74
+ * Set it on every OAuth token-endpoint call (interactive login + refresh).
75
+ * Those calls still need a `providerId` so the per-provider proxy layer applies
76
+ * and so a failure is traceable at all — but the trace captures bodies verbatim
77
+ * (that is its purpose for relay traffic), and a plaintext token must never
78
+ * reach the trace file. Purely a trace concern: the proxy resolver ignores it.
79
+ */
80
+ redactBodies?: boolean;
52
81
  }
53
82
  /**
54
83
  * The layered proxy lookup the daemon injects. Applies precedence
@@ -86,4 +115,4 @@ declare function fetchUpstream(url: string, init: RequestInit, ctx?: UpstreamPro
86
115
  /** TEST SEAM — clear the resolver + cache so a suite starts from the direct-fetch baseline. */
87
116
  declare function __resetUpstreamProxyForTests(): void;
88
117
 
89
- export { type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
118
+ export { type AccountRouteActivityContext, type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
@@ -1,5 +1,6 @@
1
1
  import { ProxyConfig } from '@omnicross/contracts/account-tokens-types';
2
2
  import { Dispatcher } from 'undici';
3
+ import { AccountRouteEndpoint, AccountRouteSessionSource, AccountRouteActivityRecord } from './AccountRouteActivity.js';
3
4
 
4
5
  /**
5
6
  * upstreamFetch — the single proxy-aware egress seam for `@omnicross/core`
@@ -28,27 +29,55 @@ import { Dispatcher } from 'undici';
28
29
  * FROZEN SEAM: `#7` (client fingerprint) attaches per-account TLS/agent behavior
29
30
  * at this SAME dispatcher point — do not fork a second egress path.
30
31
  *
31
- * DEBUG TRACE: when the daemon installs an upstream-trace path (gated on the
32
- * audit `captureBodies` opt-in), relay calls (`ctx.providerId` set) clone the
33
- * response and append the FULL exchange (request + verbatim response incl. SSE)
34
- * to the trace file. Absent a path (the default) it is a pure no-op — zero
35
- * regression. See `upstreamTrace.ts`.
32
+ * DEBUG TRACE: when a diagnostic caller explicitly installs an upstream-trace
33
+ * path, relay calls (`ctx.providerId` set) clone the response and append the
34
+ * FULL exchange (request + verbatim response incl. SSE) to the trace file. The
35
+ * daemon audit runtime never installs this path, preventing duplicate body
36
+ * storage. Absent a path (the default) it is a pure no-op — zero regression.
36
37
  *
37
38
  * @module @omnicross/core/pipeline/upstreamFetch
38
39
  */
39
40
 
41
+ interface AccountRouteActivityContext {
42
+ endpoint: AccountRouteEndpoint;
43
+ sessionKey?: string;
44
+ sessionSource: AccountRouteSessionSource;
45
+ model: string;
46
+ /**
47
+ * Invoked once with the freshly-recorded activity record. Lets a caller
48
+ * capture the record `id` so it can {@link AccountRouteActivityStore.amend}
49
+ * the SAME row later, once a post-hoc fact (e.g. an overload event buried in
50
+ * the 200 SSE body) becomes known during relay. Best-effort: never throws.
51
+ */
52
+ onRecorded?: (record: AccountRouteActivityRecord) => void;
53
+ }
40
54
  /** The opaque call context the resolver maps to a proxy (precedence input). */
41
55
  interface UpstreamProxyContext {
42
56
  /** The subscription provider id (`claude`/`codex`/`gemini`/`opencodego`) or `'byo'`. */
43
57
  providerId?: string;
44
58
  /** The selected pooled account id (per-account override input). */
45
59
  accountId?: string;
60
+ /** Metadata-only live route activity. Never contains prompts, headers, or tokens. */
61
+ routeActivity?: AccountRouteActivityContext;
46
62
  /**
47
63
  * The target upstream URL. Injected by {@link fetchUpstream} so the resolver can
48
64
  * apply host-based bypass (loopback / `NO_PROXY`). Callers of the ingress helpers
49
65
  * do NOT set this — it is filled from the fetch `url`.
50
66
  */
51
67
  url?: string;
68
+ /**
69
+ * CREDENTIAL EXCHANGE — this call's request/response BODIES carry secrets (an
70
+ * authorization code + PKCE verifier out, an access/refresh token back), so the
71
+ * debug trace must record the exchange's METADATA only and replace both bodies
72
+ * with a placeholder.
73
+ *
74
+ * Set it on every OAuth token-endpoint call (interactive login + refresh).
75
+ * Those calls still need a `providerId` so the per-provider proxy layer applies
76
+ * and so a failure is traceable at all — but the trace captures bodies verbatim
77
+ * (that is its purpose for relay traffic), and a plaintext token must never
78
+ * reach the trace file. Purely a trace concern: the proxy resolver ignores it.
79
+ */
80
+ redactBodies?: boolean;
52
81
  }
53
82
  /**
54
83
  * The layered proxy lookup the daemon injects. Applies precedence
@@ -86,4 +115,4 @@ declare function fetchUpstream(url: string, init: RequestInit, ctx?: UpstreamPro
86
115
  /** TEST SEAM — clear the resolver + cache so a suite starts from the direct-fetch baseline. */
87
116
  declare function __resetUpstreamProxyForTests(): void;
88
117
 
89
- export { type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
118
+ export { type AccountRouteActivityContext, type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
@@ -4,9 +4,10 @@ import {
4
4
  fetchUpstream,
5
5
  resolveUpstreamDispatcher,
6
6
  setUpstreamProxyResolver
7
- } from "../chunk-SIZQQD6T.js";
8
- import "../chunk-SYQF7OIR.js";
7
+ } from "../chunk-RJ5ZGNI3.js";
8
+ import "../chunk-3WD4HTR2.js";
9
9
  import "../chunk-MKF46GNZ.js";
10
+ import "../chunk-GL6XM527.js";
10
11
  export {
11
12
  __resetUpstreamProxyForTests,
12
13
  bumpUpstreamProxyGeneration,
@@ -4,11 +4,13 @@
4
4
 
5
5
 
6
6
 
7
- var _chunk3Z5BQZFMcjs = require('../chunk-3Z5BQZFM.cjs');
8
7
 
8
+ var _chunk235MXAGXcjs = require('../chunk-235MXAGX.cjs');
9
9
 
10
10
 
11
11
 
12
12
 
13
13
 
14
- exports.__resetUpstreamTraceForTests = _chunk3Z5BQZFMcjs.__resetUpstreamTraceForTests; exports.getUpstreamTracePath = _chunk3Z5BQZFMcjs.getUpstreamTracePath; exports.redactHeaders = _chunk3Z5BQZFMcjs.redactHeaders; exports.setUpstreamTracePath = _chunk3Z5BQZFMcjs.setUpstreamTracePath; exports.writeUpstreamTrace = _chunk3Z5BQZFMcjs.writeUpstreamTrace;
14
+
15
+
16
+ exports.REDACTED_BODY = _chunk235MXAGXcjs.REDACTED_BODY; exports.__resetUpstreamTraceForTests = _chunk235MXAGXcjs.__resetUpstreamTraceForTests; exports.getUpstreamTracePath = _chunk235MXAGXcjs.getUpstreamTracePath; exports.redactHeaders = _chunk235MXAGXcjs.redactHeaders; exports.setUpstreamTracePath = _chunk235MXAGXcjs.setUpstreamTracePath; exports.writeUpstreamTrace = _chunk235MXAGXcjs.writeUpstreamTrace;
@@ -14,22 +14,36 @@
14
14
  * (a `text/event-stream` included — `clone().text()` tees the stream so the
15
15
  * relay keeps streaming the original while the clone is buffered for the
16
16
  * trace), and appends one {@link UpstreamTraceRecord} JSON line. Relay calls
17
- * carry an opaque `providerId`; OAuth-refresh / webhook sends do not, so they
18
- * are skipped (less noise). Tracing is fire-and-forget: a read/write failure
19
- * is swallowed so the egress path is never affected.
17
+ * carry an opaque `providerId`; webhook / billing sends do not, so they are
18
+ * skipped (less noise). OAuth token-endpoint calls (interactive login + refresh)
19
+ * DO carry one a failed login must be diagnosable — but they set the ctx's
20
+ * `redactBodies`, so their bodies are replaced with {@link REDACTED_BODY}.
21
+ * Tracing is fire-and-forget: a read/write failure is swallowed so the egress
22
+ * path is never affected.
20
23
  *
21
- * The daemon installs the path via {@link setUpstreamTracePath} (gated on the
22
- * audit segment's `captureBodies`, hot-reloaded like the audit sink). Absent a
23
- * path the trace is a pure no-op byte-identical zero regression.
24
+ * A diagnostic caller may explicitly install a path via
25
+ * {@link setUpstreamTracePath}. The daemon's audit runtime intentionally does
26
+ * not install one: audit bodies have a single persistence path. Absent an
27
+ * explicit path the trace is a pure no-op — byte-identical zero regression.
24
28
  *
25
29
  * Secret discipline: request/response AUTHORIZATION + api-key HEADER values are
26
30
  * masked (`***REDACTED***`) — they are OAuth bearer tokens, not the thing under
27
31
  * test, and a plaintext trace file must not hold them. Header KEYS stay visible
28
32
  * so presence is verifiable. The request/response BODIES are captured VERBATIM
29
- * (a prompt / a codex SSE stream) — that is the whole point.
33
+ * (a prompt / a codex SSE stream) — that is the whole point — EXCEPT on a
34
+ * credential exchange, where the body IS the secret (see {@link REDACTED_BODY}).
30
35
  *
31
36
  * @module @omnicross/core/pipeline/upstreamTrace
32
37
  */
38
+ /**
39
+ * Placeholder written in place of a request/response body whose content is a
40
+ * CREDENTIAL rather than the thing under test — an OAuth token exchange or
41
+ * refresh (`fetchUpstream` ctx `redactBodies`). Those calls are still traced so a
42
+ * failed login/refresh is diagnosable (url, status, duration, byte count), but a
43
+ * plaintext authorization code / access token / refresh token must never land in
44
+ * this file.
45
+ */
46
+ declare const REDACTED_BODY = "***REDACTED (credential exchange)***";
33
47
  /**
34
48
  * Install (or clear, with `null`/blank) the trace file path. Idempotent — last
35
49
  * write wins. The path is resolved by the daemon relative to the audit store.
@@ -82,4 +96,4 @@ declare function writeUpstreamTrace(record: UpstreamTraceRecord): Promise<void>;
82
96
  /** TEST SEAM — clear the trace path so a suite starts from the no-trace baseline. */
83
97
  declare function __resetUpstreamTraceForTests(): void;
84
98
 
85
- export { type UpstreamTraceRecord, __resetUpstreamTraceForTests, getUpstreamTracePath, redactHeaders, setUpstreamTracePath, writeUpstreamTrace };
99
+ export { REDACTED_BODY, type UpstreamTraceRecord, __resetUpstreamTraceForTests, getUpstreamTracePath, redactHeaders, setUpstreamTracePath, writeUpstreamTrace };