@omnicross/core 0.1.3 → 0.1.5

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 (141) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +57 -57
  3. package/README.md +15 -15
  4. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +6 -5
  5. package/dist/auth/GeminiCodeAssistProjectResolver.js +6 -5
  6. package/dist/{chunk-2DCNB7DF.cjs → chunk-3Q6Z6JTO.cjs} +154 -26
  7. package/dist/chunk-3QFXFCHG.js +33 -0
  8. package/dist/chunk-3Z5BQZFM.cjs +52 -0
  9. package/dist/{chunk-4VAVYUZS.cjs → chunk-4XMYPW46.cjs} +9 -9
  10. package/dist/chunk-4YINUUKQ.cjs +33 -0
  11. package/dist/{chunk-S4WBV25P.js → chunk-6QZGDLL4.js} +106 -23
  12. package/dist/{chunk-C72S6TTV.cjs → chunk-7FEBOPJO.cjs} +5 -4
  13. package/dist/chunk-APYG5QD7.cjs +50 -0
  14. package/dist/{chunk-5HTVET6E.js → chunk-BODMAL6G.js} +143 -15
  15. package/dist/{chunk-CWM2ZDU5.js → chunk-BPKCU575.js} +3 -10
  16. package/dist/{chunk-2FMI2B6V.cjs → chunk-CGKLE6IW.cjs} +350 -461
  17. package/dist/{chunk-BO4RFWBR.js → chunk-D3TDKWRP.js} +84 -3
  18. package/dist/{chunk-RSJ3TWJQ.cjs → chunk-DDMRUL76.cjs} +5 -5
  19. package/dist/chunk-FCR77GYM.cjs +33 -0
  20. package/dist/{chunk-4DECIFU7.js → chunk-FH2P4OCD.js} +178 -289
  21. package/dist/{chunk-N5QFKSDO.js → chunk-HRRYG2AX.js} +2 -1
  22. package/dist/{chunk-KUU2RNG6.cjs → chunk-HYN75H6G.cjs} +3 -0
  23. package/dist/{chunk-Z7LUNECE.js → chunk-IB3FDI4O.js} +5 -4
  24. package/dist/chunk-IFXJ2BG7.js +109 -0
  25. package/dist/{chunk-JO5NLTLY.js → chunk-IK3KE3AU.js} +3 -0
  26. package/dist/{chunk-C7PSERMH.js → chunk-IWQAX3CS.js} +1 -1
  27. package/dist/{chunk-YGXJGRFI.cjs → chunk-JWVTXXPX.cjs} +106 -23
  28. package/dist/{chunk-7YN22L2H.cjs → chunk-K52THW2C.cjs} +5 -5
  29. package/dist/chunk-K5NM7VAH.js +33 -0
  30. package/dist/{chunk-Y6OM7EV7.cjs → chunk-KFI44N2R.cjs} +2 -1
  31. package/dist/{chunk-Z7Y2NPHY.js → chunk-MFZ5437A.js} +1 -1
  32. package/dist/chunk-OE6TDIWW.js +22 -0
  33. package/dist/{chunk-MQNDWYPN.js → chunk-OQWKZCXP.js} +13 -6
  34. package/dist/chunk-OZFM4X3S.js +18 -0
  35. package/dist/chunk-PG7PS2NN.cjs +170 -0
  36. package/dist/{chunk-3QOSDDNI.cjs → chunk-SNYBEXLB.cjs} +6 -13
  37. package/dist/chunk-SYQF7OIR.js +52 -0
  38. package/dist/{chunk-CZHZGRU7.js → chunk-UHGVBFU3.js} +2 -0
  39. package/dist/chunk-UIBD2YY5.cjs +22 -0
  40. package/dist/chunk-UNWKG6EI.cjs +109 -0
  41. package/dist/{chunk-SVXC36MU.cjs → chunk-VACWOIRE.cjs} +2 -0
  42. package/dist/chunk-WLYIIEAF.js +50 -0
  43. package/dist/chunk-XSVNC2UD.cjs +18 -0
  44. package/dist/{chunk-FFALUUZZ.cjs → chunk-ZCIQ3L3R.cjs} +18 -11
  45. package/dist/completion/CompletionService.cjs +26 -19
  46. package/dist/completion/CompletionService.js +25 -18
  47. package/dist/completion.cjs +28 -21
  48. package/dist/completion.js +27 -20
  49. package/dist/index.cjs +35 -25
  50. package/dist/index.d.cts +7 -3
  51. package/dist/index.d.ts +7 -3
  52. package/dist/index.js +44 -34
  53. package/dist/keyPolicy-Cp0FntZl.d.cts +90 -0
  54. package/dist/keyPolicy-Cp0FntZl.d.ts +90 -0
  55. package/dist/outbound-api/auditCapture.cjs +9 -0
  56. package/dist/outbound-api/auditCapture.d.cts +54 -0
  57. package/dist/outbound-api/auditCapture.d.ts +54 -0
  58. package/dist/outbound-api/auditCapture.js +9 -0
  59. package/dist/outbound-api/auditRedact.cjs +8 -0
  60. package/dist/outbound-api/auditRedact.d.cts +30 -0
  61. package/dist/outbound-api/auditRedact.d.ts +30 -0
  62. package/dist/outbound-api/auditRedact.js +8 -0
  63. package/dist/outbound-api/billingCapture.cjs +8 -0
  64. package/dist/outbound-api/billingCapture.d.cts +61 -0
  65. package/dist/outbound-api/billingCapture.d.ts +61 -0
  66. package/dist/outbound-api/billingCapture.js +8 -0
  67. package/dist/outbound-api/quotaWarn.cjs +12 -0
  68. package/dist/outbound-api/quotaWarn.d.cts +43 -0
  69. package/dist/outbound-api/quotaWarn.d.ts +43 -0
  70. package/dist/outbound-api/quotaWarn.js +12 -0
  71. package/dist/outbound-api/routeResolver.cjs +2 -2
  72. package/dist/outbound-api/routeResolver.d.cts +3 -2
  73. package/dist/outbound-api/routeResolver.d.ts +3 -2
  74. package/dist/outbound-api/routeResolver.js +1 -1
  75. package/dist/outbound-api/types.d.cts +2 -1
  76. package/dist/outbound-api/types.d.ts +2 -1
  77. package/dist/outbound-api.cjs +33 -23
  78. package/dist/outbound-api.d.cts +9 -140
  79. package/dist/outbound-api.d.ts +9 -140
  80. package/dist/outbound-api.js +32 -22
  81. package/dist/pipeline/AuthSource.d.cts +6 -0
  82. package/dist/pipeline/AuthSource.d.ts +6 -0
  83. package/dist/pipeline/SubscriptionAuthSource.cjs +2 -2
  84. package/dist/pipeline/SubscriptionAuthSource.js +1 -1
  85. package/dist/pipeline/SubscriptionAuthStrategy.d.cts +6 -0
  86. package/dist/pipeline/SubscriptionAuthStrategy.d.ts +6 -0
  87. package/dist/pipeline/auditUsageStash.cjs +10 -0
  88. package/dist/pipeline/auditUsageStash.d.cts +37 -0
  89. package/dist/pipeline/auditUsageStash.d.ts +37 -0
  90. package/dist/pipeline/auditUsageStash.js +10 -0
  91. package/dist/pipeline/executeProviderCall.cjs +2 -2
  92. package/dist/pipeline/executeProviderCall.js +1 -1
  93. package/dist/pipeline/upstreamFetch.cjs +15 -0
  94. package/dist/pipeline/upstreamFetch.d.cts +89 -0
  95. package/dist/pipeline/upstreamFetch.d.ts +89 -0
  96. package/dist/pipeline/upstreamFetch.js +15 -0
  97. package/dist/pipeline/upstreamTrace.cjs +14 -0
  98. package/dist/pipeline/upstreamTrace.d.cts +85 -0
  99. package/dist/pipeline/upstreamTrace.d.ts +85 -0
  100. package/dist/pipeline/upstreamTrace.js +14 -0
  101. package/dist/pipeline/webhookEmit.cjs +10 -0
  102. package/dist/pipeline/webhookEmit.d.cts +36 -0
  103. package/dist/pipeline/webhookEmit.d.ts +36 -0
  104. package/dist/pipeline/webhookEmit.js +10 -0
  105. package/dist/ports.d.cts +2 -1
  106. package/dist/ports.d.ts +2 -1
  107. package/dist/provider-proxy/ProviderProxy.cjs +26 -19
  108. package/dist/provider-proxy/ProviderProxy.js +25 -18
  109. package/dist/provider-proxy/ingress/providerProxyShared.cjs +28 -19
  110. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +17 -1
  111. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +17 -1
  112. package/dist/provider-proxy/ingress/providerProxyShared.js +27 -18
  113. package/dist/provider-proxy/types.d.cts +7 -0
  114. package/dist/provider-proxy/types.d.ts +7 -0
  115. package/dist/provider-proxy.cjs +26 -19
  116. package/dist/provider-proxy.js +25 -18
  117. package/dist/{routeResolver-B1NglTfe.d.ts → routeResolver-C4T7yClx.d.ts} +1 -1
  118. package/dist/{routeResolver-CbG5uBgm.d.cts → routeResolver-CB3tvJKy.d.cts} +1 -1
  119. package/dist/transformer/transformers/AnthropicTransformer.cjs +2 -2
  120. package/dist/transformer/transformers/AnthropicTransformer.js +1 -1
  121. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +3 -3
  122. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +2 -2
  123. package/dist/transformer/transformers/GeminiTransformer.cjs +3 -3
  124. package/dist/transformer/transformers/GeminiTransformer.js +2 -2
  125. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +2 -2
  126. package/dist/transformer/transformers/OpenAIResponseTransformer.js +1 -1
  127. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +2 -2
  128. package/dist/transformer/transformers/OpenCodeGoTransformer.js +1 -1
  129. package/dist/transformer/transformers.cjs +8 -8
  130. package/dist/transformer/transformers.js +7 -7
  131. package/dist/transformer.cjs +8 -8
  132. package/dist/transformer.js +7 -7
  133. package/dist/{types-aBFFXoBz.d.cts → types-B8Arpxn0.d.cts} +14 -90
  134. package/dist/{types-6OUY_xfA.d.ts → types-lgPYQuZS.d.ts} +14 -90
  135. package/dist/usage/usage-recorder.cjs +3 -2
  136. package/dist/usage/usage-recorder.js +2 -1
  137. package/dist/usage.cjs +3 -2
  138. package/dist/usage.js +2 -1
  139. package/package.json +64 -64
  140. package/dist/chunk-S6JGLF3G.cjs +0 -89
  141. package/dist/{chunk-FTQ7IQUC.js → chunk-C6OV7GCC.js} +8 -8
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SubscriptionAuthSource,
3
3
  stripAuthHeaders
4
- } from "../chunk-N5QFKSDO.js";
4
+ } from "../chunk-HRRYG2AX.js";
5
5
  import "../chunk-AVYJ4YBN.js";
6
6
  export {
7
7
  SubscriptionAuthSource,
@@ -49,6 +49,12 @@ interface AuthApplyHints {
49
49
  * pre-health behavior).
50
50
  */
51
51
  reportSelection?: (accountId: string, isActive: boolean, remappedModel?: string) => void;
52
+ /**
53
+ * OPTIONAL preferred subscription account id (provider/subscription duality).
54
+ * When set and schedulable the account picker resolves it directly; absent or
55
+ * unschedulable ⇒ pool auto-schedule.
56
+ */
57
+ preferredAccountId?: string;
52
58
  }
53
59
  interface AuthStrategy {
54
60
  /** Discriminator — also surfaced through `subscription:list` to renderers. */
@@ -49,6 +49,12 @@ interface AuthApplyHints {
49
49
  * pre-health behavior).
50
50
  */
51
51
  reportSelection?: (accountId: string, isActive: boolean, remappedModel?: string) => void;
52
+ /**
53
+ * OPTIONAL preferred subscription account id (provider/subscription duality).
54
+ * When set and schedulable the account picker resolves it directly; absent or
55
+ * unschedulable ⇒ pool auto-schedule.
56
+ */
57
+ preferredAccountId?: string;
52
58
  }
53
59
  interface AuthStrategy {
54
60
  /** Discriminator — also surfaced through `subscription:list` to renderers. */
@@ -0,0 +1,10 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+ var _chunkXSVNC2UDcjs = require('../chunk-XSVNC2UD.cjs');
6
+
7
+
8
+
9
+
10
+ exports.__clearAuditUsageForTests = _chunkXSVNC2UDcjs.__clearAuditUsageForTests; exports.readAuditUsage = _chunkXSVNC2UDcjs.readAuditUsage; exports.stashAuditUsage = _chunkXSVNC2UDcjs.stashAuditUsage;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * auditUsageStash — a per-request usage correlation stash for the audit capture
3
+ * (request-audit-log, design D1). The audit record is assembled at the outbound
4
+ * router's post-response point, but token counts + cost are produced downstream
5
+ * by the usage tap → `UsageRecorder`. This `WeakMap<res, detail>` bridges them:
6
+ * the recorder stashes the usage detail keyed by the SAME `http.ServerResponse`
7
+ * the audit capture holds, so `beginAuditCapture` can read it at response close.
8
+ *
9
+ * The token counts + model/provider are stashed SYNCHRONOUSLY at `record()` time
10
+ * (before the response closes ⇒ reliably present); the cost is stashed on the
11
+ * deferred pricing tick (best-effort — populated when it lands before close).
12
+ * Keyed by the response OBJECT (a `WeakMap`, so a completed request's entry is
13
+ * GC'd with the response — no leak, no cleanup needed).
14
+ *
15
+ * This is OPT-IN + gated: only the outbound taps set `auditResponse`, and the
16
+ * audit capture only reads when audit is enabled. Any other `UsageRecorder`
17
+ * caller leaves `auditResponse` unset ⇒ this map is never touched ⇒ zero
18
+ * regression.
19
+ *
20
+ * @module @omnicross/core/pipeline/auditUsageStash
21
+ */
22
+ /** The subset of usage numbers an audit record carries (all optional). */
23
+ interface AuditUsageDetail {
24
+ inputTokens?: number;
25
+ outputTokens?: number;
26
+ costUsd?: number;
27
+ model?: string;
28
+ provider?: string;
29
+ }
30
+ /** Merge a partial usage detail into the entry keyed by `key` (the response). */
31
+ declare function stashAuditUsage(key: object, detail: AuditUsageDetail): void;
32
+ /** Read the accumulated usage detail for `key`, or `undefined` when none. */
33
+ declare function readAuditUsage(key: object): AuditUsageDetail | undefined;
34
+ /** TEST SEAM — drop a stashed entry so a suite starts clean. */
35
+ declare function __clearAuditUsageForTests(key: object): void;
36
+
37
+ export { type AuditUsageDetail, __clearAuditUsageForTests, readAuditUsage, stashAuditUsage };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * auditUsageStash — a per-request usage correlation stash for the audit capture
3
+ * (request-audit-log, design D1). The audit record is assembled at the outbound
4
+ * router's post-response point, but token counts + cost are produced downstream
5
+ * by the usage tap → `UsageRecorder`. This `WeakMap<res, detail>` bridges them:
6
+ * the recorder stashes the usage detail keyed by the SAME `http.ServerResponse`
7
+ * the audit capture holds, so `beginAuditCapture` can read it at response close.
8
+ *
9
+ * The token counts + model/provider are stashed SYNCHRONOUSLY at `record()` time
10
+ * (before the response closes ⇒ reliably present); the cost is stashed on the
11
+ * deferred pricing tick (best-effort — populated when it lands before close).
12
+ * Keyed by the response OBJECT (a `WeakMap`, so a completed request's entry is
13
+ * GC'd with the response — no leak, no cleanup needed).
14
+ *
15
+ * This is OPT-IN + gated: only the outbound taps set `auditResponse`, and the
16
+ * audit capture only reads when audit is enabled. Any other `UsageRecorder`
17
+ * caller leaves `auditResponse` unset ⇒ this map is never touched ⇒ zero
18
+ * regression.
19
+ *
20
+ * @module @omnicross/core/pipeline/auditUsageStash
21
+ */
22
+ /** The subset of usage numbers an audit record carries (all optional). */
23
+ interface AuditUsageDetail {
24
+ inputTokens?: number;
25
+ outputTokens?: number;
26
+ costUsd?: number;
27
+ model?: string;
28
+ provider?: string;
29
+ }
30
+ /** Merge a partial usage detail into the entry keyed by `key` (the response). */
31
+ declare function stashAuditUsage(key: object, detail: AuditUsageDetail): void;
32
+ /** Read the accumulated usage detail for `key`, or `undefined` when none. */
33
+ declare function readAuditUsage(key: object): AuditUsageDetail | undefined;
34
+ /** TEST SEAM — drop a stashed entry so a suite starts clean. */
35
+ declare function __clearAuditUsageForTests(key: object): void;
36
+
37
+ export { type AuditUsageDetail, __clearAuditUsageForTests, readAuditUsage, stashAuditUsage };
@@ -0,0 +1,10 @@
1
+ import {
2
+ __clearAuditUsageForTests,
3
+ readAuditUsage,
4
+ stashAuditUsage
5
+ } from "../chunk-OZFM4X3S.js";
6
+ export {
7
+ __clearAuditUsageForTests,
8
+ readAuditUsage,
9
+ stashAuditUsage
10
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkKUU2RNG6cjs = require('../chunk-KUU2RNG6.cjs');
3
+ var _chunkHYN75H6Gcjs = require('../chunk-HYN75H6G.cjs');
4
4
 
5
5
 
6
- exports.executeProviderCall = _chunkKUU2RNG6cjs.executeProviderCall;
6
+ exports.executeProviderCall = _chunkHYN75H6Gcjs.executeProviderCall;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  executeProviderCall
3
- } from "../chunk-JO5NLTLY.js";
3
+ } from "../chunk-IK3KE3AU.js";
4
4
  export {
5
5
  executeProviderCall
6
6
  };
@@ -0,0 +1,15 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+ var _chunkPG7PS2NNcjs = require('../chunk-PG7PS2NN.cjs');
8
+ require('../chunk-3Z5BQZFM.cjs');
9
+
10
+
11
+
12
+
13
+
14
+
15
+ exports.__resetUpstreamProxyForTests = _chunkPG7PS2NNcjs.__resetUpstreamProxyForTests; exports.bumpUpstreamProxyGeneration = _chunkPG7PS2NNcjs.bumpUpstreamProxyGeneration; exports.fetchUpstream = _chunkPG7PS2NNcjs.fetchUpstream; exports.resolveUpstreamDispatcher = _chunkPG7PS2NNcjs.resolveUpstreamDispatcher; exports.setUpstreamProxyResolver = _chunkPG7PS2NNcjs.setUpstreamProxyResolver;
@@ -0,0 +1,89 @@
1
+ import { ProxyConfig } from '@omnicross/contracts/account-tokens-types';
2
+ import { Dispatcher } from 'undici';
3
+
4
+ /**
5
+ * upstreamFetch — the single proxy-aware egress seam for `@omnicross/core`
6
+ * (upstream-proxy).
7
+ *
8
+ * Every outbound UPSTREAM call (relay ingress `fetchFn` closures, the OAuth
9
+ * token-refresh `FetchLike`, the Gemini Code Assist handshake) routes through
10
+ * {@link fetchUpstream}. When a proxy resolves for the call it attaches an
11
+ * undici {@link Dispatcher} (`ProxyAgent` for http/https, an `Agent` with a
12
+ * socks5 connector for socks5); ABSENT any proxy it is a BARE `fetch` — the
13
+ * dispatcher option is never set, so behavior is byte-identical to the
14
+ * pre-change code (the zero-regression guarantee).
15
+ *
16
+ * Core stays config/account-agnostic: it only knows opaque `providerId` /
17
+ * `accountId` strings + a {@link ProxyConfig} descriptor. The daemon injects the
18
+ * layered lookup via {@link setUpstreamProxyResolver} — the same module-slot
19
+ * pattern as `setSubscriptionRegistryForOutbound`. Core never imports config or
20
+ * account material.
21
+ *
22
+ * Dispatchers are CACHED by resolved-proxy identity (one instance reused, not
23
+ * per-request, so keep-alive holds and sockets don't leak). A config change bumps
24
+ * a generation via {@link bumpUpstreamProxyGeneration} (also called by
25
+ * `setUpstreamProxyResolver`) which disposes the old dispatchers and rebuilds on
26
+ * next use.
27
+ *
28
+ * FROZEN SEAM: `#7` (client fingerprint) attaches per-account TLS/agent behavior
29
+ * at this SAME dispatcher point — do not fork a second egress path.
30
+ *
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`.
36
+ *
37
+ * @module @omnicross/core/pipeline/upstreamFetch
38
+ */
39
+
40
+ /** The opaque call context the resolver maps to a proxy (precedence input). */
41
+ interface UpstreamProxyContext {
42
+ /** The subscription provider id (`claude`/`codex`/`gemini`/`opencodego`) or `'byo'`. */
43
+ providerId?: string;
44
+ /** The selected pooled account id (per-account override input). */
45
+ accountId?: string;
46
+ /**
47
+ * The target upstream URL. Injected by {@link fetchUpstream} so the resolver can
48
+ * apply host-based bypass (loopback / `NO_PROXY`). Callers of the ingress helpers
49
+ * do NOT set this — it is filled from the fetch `url`.
50
+ */
51
+ url?: string;
52
+ }
53
+ /**
54
+ * The layered proxy lookup the daemon injects. Applies precedence
55
+ * account > provider > global > env and returns the WINNING `ProxyConfig`, or
56
+ * `undefined` for a direct (non-proxied) call.
57
+ */
58
+ type UpstreamProxyResolver = (ctx: UpstreamProxyContext) => ProxyConfig | undefined;
59
+ /**
60
+ * Inject (or clear, with `null`) the layered proxy resolver. Idempotent — last
61
+ * write wins. Bumps the dispatcher generation so a resolver swap (or a config
62
+ * edit that re-registers) rebuilds dispatchers from the new lookup and disposes
63
+ * the old ones.
64
+ */
65
+ declare function setUpstreamProxyResolver(fn: UpstreamProxyResolver | null): void;
66
+ /**
67
+ * Invalidate every cached dispatcher (config change / admin edit). Old
68
+ * dispatchers are `close()`d best-effort so in-flight sockets drain; new calls
69
+ * rebuild from the current resolver output.
70
+ */
71
+ declare function bumpUpstreamProxyGeneration(): void;
72
+ /**
73
+ * Resolve the dispatcher for one call. Returns `undefined` (⇒ bare fetch) when
74
+ * no resolver is registered, the resolver returns undefined, or the descriptor
75
+ * is malformed. A resolver throw is swallowed → direct call (egress never breaks
76
+ * on a proxy-lookup error).
77
+ */
78
+ declare function resolveUpstreamDispatcher(ctx: UpstreamProxyContext): Dispatcher | undefined;
79
+ /**
80
+ * Proxy-aware `fetch`. Attaches the resolved undici dispatcher ONLY when a proxy
81
+ * applies; otherwise it is a BARE `fetch(url, init)` — byte-identical to the
82
+ * pre-change egress (zero-regression). The `dispatcher` option is undici-specific
83
+ * (Node's global fetch IS undici); the cast threads it without a DOM-lib type.
84
+ */
85
+ declare function fetchUpstream(url: string, init: RequestInit, ctx?: UpstreamProxyContext): Promise<Response>;
86
+ /** TEST SEAM — clear the resolver + cache so a suite starts from the direct-fetch baseline. */
87
+ declare function __resetUpstreamProxyForTests(): void;
88
+
89
+ export { type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
@@ -0,0 +1,89 @@
1
+ import { ProxyConfig } from '@omnicross/contracts/account-tokens-types';
2
+ import { Dispatcher } from 'undici';
3
+
4
+ /**
5
+ * upstreamFetch — the single proxy-aware egress seam for `@omnicross/core`
6
+ * (upstream-proxy).
7
+ *
8
+ * Every outbound UPSTREAM call (relay ingress `fetchFn` closures, the OAuth
9
+ * token-refresh `FetchLike`, the Gemini Code Assist handshake) routes through
10
+ * {@link fetchUpstream}. When a proxy resolves for the call it attaches an
11
+ * undici {@link Dispatcher} (`ProxyAgent` for http/https, an `Agent` with a
12
+ * socks5 connector for socks5); ABSENT any proxy it is a BARE `fetch` — the
13
+ * dispatcher option is never set, so behavior is byte-identical to the
14
+ * pre-change code (the zero-regression guarantee).
15
+ *
16
+ * Core stays config/account-agnostic: it only knows opaque `providerId` /
17
+ * `accountId` strings + a {@link ProxyConfig} descriptor. The daemon injects the
18
+ * layered lookup via {@link setUpstreamProxyResolver} — the same module-slot
19
+ * pattern as `setSubscriptionRegistryForOutbound`. Core never imports config or
20
+ * account material.
21
+ *
22
+ * Dispatchers are CACHED by resolved-proxy identity (one instance reused, not
23
+ * per-request, so keep-alive holds and sockets don't leak). A config change bumps
24
+ * a generation via {@link bumpUpstreamProxyGeneration} (also called by
25
+ * `setUpstreamProxyResolver`) which disposes the old dispatchers and rebuilds on
26
+ * next use.
27
+ *
28
+ * FROZEN SEAM: `#7` (client fingerprint) attaches per-account TLS/agent behavior
29
+ * at this SAME dispatcher point — do not fork a second egress path.
30
+ *
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`.
36
+ *
37
+ * @module @omnicross/core/pipeline/upstreamFetch
38
+ */
39
+
40
+ /** The opaque call context the resolver maps to a proxy (precedence input). */
41
+ interface UpstreamProxyContext {
42
+ /** The subscription provider id (`claude`/`codex`/`gemini`/`opencodego`) or `'byo'`. */
43
+ providerId?: string;
44
+ /** The selected pooled account id (per-account override input). */
45
+ accountId?: string;
46
+ /**
47
+ * The target upstream URL. Injected by {@link fetchUpstream} so the resolver can
48
+ * apply host-based bypass (loopback / `NO_PROXY`). Callers of the ingress helpers
49
+ * do NOT set this — it is filled from the fetch `url`.
50
+ */
51
+ url?: string;
52
+ }
53
+ /**
54
+ * The layered proxy lookup the daemon injects. Applies precedence
55
+ * account > provider > global > env and returns the WINNING `ProxyConfig`, or
56
+ * `undefined` for a direct (non-proxied) call.
57
+ */
58
+ type UpstreamProxyResolver = (ctx: UpstreamProxyContext) => ProxyConfig | undefined;
59
+ /**
60
+ * Inject (or clear, with `null`) the layered proxy resolver. Idempotent — last
61
+ * write wins. Bumps the dispatcher generation so a resolver swap (or a config
62
+ * edit that re-registers) rebuilds dispatchers from the new lookup and disposes
63
+ * the old ones.
64
+ */
65
+ declare function setUpstreamProxyResolver(fn: UpstreamProxyResolver | null): void;
66
+ /**
67
+ * Invalidate every cached dispatcher (config change / admin edit). Old
68
+ * dispatchers are `close()`d best-effort so in-flight sockets drain; new calls
69
+ * rebuild from the current resolver output.
70
+ */
71
+ declare function bumpUpstreamProxyGeneration(): void;
72
+ /**
73
+ * Resolve the dispatcher for one call. Returns `undefined` (⇒ bare fetch) when
74
+ * no resolver is registered, the resolver returns undefined, or the descriptor
75
+ * is malformed. A resolver throw is swallowed → direct call (egress never breaks
76
+ * on a proxy-lookup error).
77
+ */
78
+ declare function resolveUpstreamDispatcher(ctx: UpstreamProxyContext): Dispatcher | undefined;
79
+ /**
80
+ * Proxy-aware `fetch`. Attaches the resolved undici dispatcher ONLY when a proxy
81
+ * applies; otherwise it is a BARE `fetch(url, init)` — byte-identical to the
82
+ * pre-change egress (zero-regression). The `dispatcher` option is undici-specific
83
+ * (Node's global fetch IS undici); the cast threads it without a DOM-lib type.
84
+ */
85
+ declare function fetchUpstream(url: string, init: RequestInit, ctx?: UpstreamProxyContext): Promise<Response>;
86
+ /** TEST SEAM — clear the resolver + cache so a suite starts from the direct-fetch baseline. */
87
+ declare function __resetUpstreamProxyForTests(): void;
88
+
89
+ export { type UpstreamProxyContext, type UpstreamProxyResolver, __resetUpstreamProxyForTests, bumpUpstreamProxyGeneration, fetchUpstream, resolveUpstreamDispatcher, setUpstreamProxyResolver };
@@ -0,0 +1,15 @@
1
+ import {
2
+ __resetUpstreamProxyForTests,
3
+ bumpUpstreamProxyGeneration,
4
+ fetchUpstream,
5
+ resolveUpstreamDispatcher,
6
+ setUpstreamProxyResolver
7
+ } from "../chunk-D3TDKWRP.js";
8
+ import "../chunk-SYQF7OIR.js";
9
+ export {
10
+ __resetUpstreamProxyForTests,
11
+ bumpUpstreamProxyGeneration,
12
+ fetchUpstream,
13
+ resolveUpstreamDispatcher,
14
+ setUpstreamProxyResolver
15
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+ var _chunk3Z5BQZFMcjs = require('../chunk-3Z5BQZFM.cjs');
8
+
9
+
10
+
11
+
12
+
13
+
14
+ exports.__resetUpstreamTraceForTests = _chunk3Z5BQZFMcjs.__resetUpstreamTraceForTests; exports.getUpstreamTracePath = _chunk3Z5BQZFMcjs.getUpstreamTracePath; exports.redactHeaders = _chunk3Z5BQZFMcjs.redactHeaders; exports.setUpstreamTracePath = _chunk3Z5BQZFMcjs.setUpstreamTracePath; exports.writeUpstreamTrace = _chunk3Z5BQZFMcjs.writeUpstreamTrace;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * upstreamTrace — opt-in COMPLETE upstream-exchange capture for debugging
3
+ * (the omnicross → provider leg, e.g. the codex Responses call).
4
+ *
5
+ * The request-audit-log (`auditCapture`) only sees the CLIENT-facing leg
6
+ * (what the client sent to omnicross + what omnicross returned). It can NOT
7
+ * show the actual upstream provider request/response — and for a streaming
8
+ * codex reply it records metadata only. Every protocol-level codex bug
9
+ * (missing `Content-Type`, `store:false`, `input_text`, …) lives in the
10
+ * UPSTREAM exchange, so this module captures it verbatim.
11
+ *
12
+ * {@link fetchUpstream} is the single egress seam for every upstream call.
13
+ * When a trace path is installed it clones the response, reads the FULL body
14
+ * (a `text/event-stream` included — `clone().text()` tees the stream so the
15
+ * relay keeps streaming the original while the clone is buffered for the
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.
20
+ *
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
+ *
25
+ * Secret discipline: request/response AUTHORIZATION + api-key HEADER values are
26
+ * masked (`***REDACTED***`) — they are OAuth bearer tokens, not the thing under
27
+ * test, and a plaintext trace file must not hold them. Header KEYS stay visible
28
+ * so presence is verifiable. The request/response BODIES are captured VERBATIM
29
+ * (a prompt / a codex SSE stream) — that is the whole point.
30
+ *
31
+ * @module @omnicross/core/pipeline/upstreamTrace
32
+ */
33
+ /**
34
+ * Install (or clear, with `null`/blank) the trace file path. Idempotent — last
35
+ * write wins. The path is resolved by the daemon relative to the audit store.
36
+ */
37
+ declare function setUpstreamTracePath(path: string | null): void;
38
+ /** The active trace file path, or `null` when tracing is disabled. */
39
+ declare function getUpstreamTracePath(): string | null;
40
+ /**
41
+ * Mask secret header values while keeping the keys. Accepts a web `Headers`
42
+ * (from a fetch response) or a plain `Record<string,string>` (from a relay
43
+ * `buildHeaders`). Never throws.
44
+ */
45
+ declare function redactHeaders(headers: Headers | Record<string, string> | Array<[string, string]> | undefined | null): Record<string, string>;
46
+ /** One complete upstream-exchange trace record (appended as one JSON line). */
47
+ interface UpstreamTraceRecord {
48
+ /** Epoch ms the call started (request send time). */
49
+ ts: number;
50
+ /** Round-trip duration in ms (response fully read). */
51
+ durationMs: number;
52
+ /** The opaque relay provider id (`codex`/`claude`/`gemini`/`opencodego`/`byo`). */
53
+ providerId?: string;
54
+ /** The selected pooled account id, when the relay reported one. */
55
+ accountId?: string;
56
+ /** The upstream URL the request was sent to. */
57
+ url: string;
58
+ /** HTTP method. */
59
+ method: string;
60
+ /** Outbound request headers (secret values masked). */
61
+ requestHeaders: Record<string, string>;
62
+ /** Outbound request body verbatim (the codex Responses payload), when a string. */
63
+ requestBody: string | null;
64
+ /** Upstream HTTP status (`0` when the fetch itself failed). */
65
+ status: number;
66
+ /** Upstream HTTP status text. */
67
+ statusText: string;
68
+ /** Upstream response headers. */
69
+ responseHeaders: Record<string, string>;
70
+ /** Upstream response body verbatim — the FULL `text/event-stream` for a stream. */
71
+ responseBody: string;
72
+ /** Response body size in UTF-8 bytes. */
73
+ responseBytes: number;
74
+ }
75
+ /**
76
+ * Append one trace record to the installed file. A no-op (zero work) when no
77
+ * path is installed. Fire-and-forget safe: any fs error is swallowed — a trace
78
+ * failure must NEVER surface into the egress path. ASYNC so a slow disk / large
79
+ * SSE body never blocks the event loop (the call site does not await it).
80
+ */
81
+ declare function writeUpstreamTrace(record: UpstreamTraceRecord): Promise<void>;
82
+ /** TEST SEAM — clear the trace path so a suite starts from the no-trace baseline. */
83
+ declare function __resetUpstreamTraceForTests(): void;
84
+
85
+ export { type UpstreamTraceRecord, __resetUpstreamTraceForTests, getUpstreamTracePath, redactHeaders, setUpstreamTracePath, writeUpstreamTrace };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * upstreamTrace — opt-in COMPLETE upstream-exchange capture for debugging
3
+ * (the omnicross → provider leg, e.g. the codex Responses call).
4
+ *
5
+ * The request-audit-log (`auditCapture`) only sees the CLIENT-facing leg
6
+ * (what the client sent to omnicross + what omnicross returned). It can NOT
7
+ * show the actual upstream provider request/response — and for a streaming
8
+ * codex reply it records metadata only. Every protocol-level codex bug
9
+ * (missing `Content-Type`, `store:false`, `input_text`, …) lives in the
10
+ * UPSTREAM exchange, so this module captures it verbatim.
11
+ *
12
+ * {@link fetchUpstream} is the single egress seam for every upstream call.
13
+ * When a trace path is installed it clones the response, reads the FULL body
14
+ * (a `text/event-stream` included — `clone().text()` tees the stream so the
15
+ * relay keeps streaming the original while the clone is buffered for the
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.
20
+ *
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
+ *
25
+ * Secret discipline: request/response AUTHORIZATION + api-key HEADER values are
26
+ * masked (`***REDACTED***`) — they are OAuth bearer tokens, not the thing under
27
+ * test, and a plaintext trace file must not hold them. Header KEYS stay visible
28
+ * so presence is verifiable. The request/response BODIES are captured VERBATIM
29
+ * (a prompt / a codex SSE stream) — that is the whole point.
30
+ *
31
+ * @module @omnicross/core/pipeline/upstreamTrace
32
+ */
33
+ /**
34
+ * Install (or clear, with `null`/blank) the trace file path. Idempotent — last
35
+ * write wins. The path is resolved by the daemon relative to the audit store.
36
+ */
37
+ declare function setUpstreamTracePath(path: string | null): void;
38
+ /** The active trace file path, or `null` when tracing is disabled. */
39
+ declare function getUpstreamTracePath(): string | null;
40
+ /**
41
+ * Mask secret header values while keeping the keys. Accepts a web `Headers`
42
+ * (from a fetch response) or a plain `Record<string,string>` (from a relay
43
+ * `buildHeaders`). Never throws.
44
+ */
45
+ declare function redactHeaders(headers: Headers | Record<string, string> | Array<[string, string]> | undefined | null): Record<string, string>;
46
+ /** One complete upstream-exchange trace record (appended as one JSON line). */
47
+ interface UpstreamTraceRecord {
48
+ /** Epoch ms the call started (request send time). */
49
+ ts: number;
50
+ /** Round-trip duration in ms (response fully read). */
51
+ durationMs: number;
52
+ /** The opaque relay provider id (`codex`/`claude`/`gemini`/`opencodego`/`byo`). */
53
+ providerId?: string;
54
+ /** The selected pooled account id, when the relay reported one. */
55
+ accountId?: string;
56
+ /** The upstream URL the request was sent to. */
57
+ url: string;
58
+ /** HTTP method. */
59
+ method: string;
60
+ /** Outbound request headers (secret values masked). */
61
+ requestHeaders: Record<string, string>;
62
+ /** Outbound request body verbatim (the codex Responses payload), when a string. */
63
+ requestBody: string | null;
64
+ /** Upstream HTTP status (`0` when the fetch itself failed). */
65
+ status: number;
66
+ /** Upstream HTTP status text. */
67
+ statusText: string;
68
+ /** Upstream response headers. */
69
+ responseHeaders: Record<string, string>;
70
+ /** Upstream response body verbatim — the FULL `text/event-stream` for a stream. */
71
+ responseBody: string;
72
+ /** Response body size in UTF-8 bytes. */
73
+ responseBytes: number;
74
+ }
75
+ /**
76
+ * Append one trace record to the installed file. A no-op (zero work) when no
77
+ * path is installed. Fire-and-forget safe: any fs error is swallowed — a trace
78
+ * failure must NEVER surface into the egress path. ASYNC so a slow disk / large
79
+ * SSE body never blocks the event loop (the call site does not await it).
80
+ */
81
+ declare function writeUpstreamTrace(record: UpstreamTraceRecord): Promise<void>;
82
+ /** TEST SEAM — clear the trace path so a suite starts from the no-trace baseline. */
83
+ declare function __resetUpstreamTraceForTests(): void;
84
+
85
+ export { type UpstreamTraceRecord, __resetUpstreamTraceForTests, getUpstreamTracePath, redactHeaders, setUpstreamTracePath, writeUpstreamTrace };
@@ -0,0 +1,14 @@
1
+ import {
2
+ __resetUpstreamTraceForTests,
3
+ getUpstreamTracePath,
4
+ redactHeaders,
5
+ setUpstreamTracePath,
6
+ writeUpstreamTrace
7
+ } from "../chunk-SYQF7OIR.js";
8
+ export {
9
+ __resetUpstreamTraceForTests,
10
+ getUpstreamTracePath,
11
+ redactHeaders,
12
+ setUpstreamTracePath,
13
+ writeUpstreamTrace
14
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+ var _chunkUIBD2YY5cjs = require('../chunk-UIBD2YY5.cjs');
6
+
7
+
8
+
9
+
10
+ exports.__resetWebhookSinkForTests = _chunkUIBD2YY5cjs.__resetWebhookSinkForTests; exports.emitWebhookEvent = _chunkUIBD2YY5cjs.emitWebhookEvent; exports.setWebhookSink = _chunkUIBD2YY5cjs.setWebhookSink;
@@ -0,0 +1,36 @@
1
+ import { WebhookEvent } from '@omnicross/contracts/webhook-types';
2
+
3
+ /**
4
+ * webhookEmit — the module-slot emit port for `@omnicross/core`
5
+ * (webhook-notifications, design D2).
6
+ *
7
+ * Core SOURCES (the wire quota path in `outboundApiRouter`, the relay/dispatch
8
+ * error path) call {@link emitWebhookEvent}. The concrete `WebhookDispatcher`
9
+ * (config/secrets/HTTP/HMAC) lives in the DAEMON and registers itself as the
10
+ * sink at bootstrap via {@link setWebhookSink}. Core imports NOTHING from the
11
+ * daemon — exactly the `setSharedAccountHealth` / `setUpstreamProxyResolver`
12
+ * precedent.
13
+ *
14
+ * HARD CONTRACT (design D2 / risk "a webhook blocking the request path"):
15
+ * {@link emitWebhookEvent} NEVER throws and NEVER awaits. It hands the event to
16
+ * the sink (which enqueues and returns immediately) — a slow/failing/throwing
17
+ * sink can never affect the caller. Absent a sink it is a pure no-op, so a
18
+ * no-webhook-config daemon is byte-identical to before this change.
19
+ *
20
+ * @module @omnicross/core/pipeline/webhookEmit
21
+ */
22
+
23
+ /** The sink the daemon registers; it MUST enqueue-and-return (never block). */
24
+ type WebhookSink = (event: WebhookEvent) => void;
25
+ /** Install (or clear, with `null`) the webhook sink. Idempotent; last write wins. */
26
+ declare function setWebhookSink(fn: WebhookSink | null): void;
27
+ /**
28
+ * Emit a webhook event to the registered sink. A no-op when no sink is set
29
+ * (zero regression). NEVER throws (a misbehaving sink is swallowed) and NEVER
30
+ * awaits (the sink enqueues + returns) — so no request path is ever delayed.
31
+ */
32
+ declare function emitWebhookEvent(event: WebhookEvent): void;
33
+ /** TEST SEAM — clear the sink so a suite starts from the no-sink baseline. */
34
+ declare function __resetWebhookSinkForTests(): void;
35
+
36
+ export { type WebhookSink, __resetWebhookSinkForTests, emitWebhookEvent, setWebhookSink };
@@ -0,0 +1,36 @@
1
+ import { WebhookEvent } from '@omnicross/contracts/webhook-types';
2
+
3
+ /**
4
+ * webhookEmit — the module-slot emit port for `@omnicross/core`
5
+ * (webhook-notifications, design D2).
6
+ *
7
+ * Core SOURCES (the wire quota path in `outboundApiRouter`, the relay/dispatch
8
+ * error path) call {@link emitWebhookEvent}. The concrete `WebhookDispatcher`
9
+ * (config/secrets/HTTP/HMAC) lives in the DAEMON and registers itself as the
10
+ * sink at bootstrap via {@link setWebhookSink}. Core imports NOTHING from the
11
+ * daemon — exactly the `setSharedAccountHealth` / `setUpstreamProxyResolver`
12
+ * precedent.
13
+ *
14
+ * HARD CONTRACT (design D2 / risk "a webhook blocking the request path"):
15
+ * {@link emitWebhookEvent} NEVER throws and NEVER awaits. It hands the event to
16
+ * the sink (which enqueues and returns immediately) — a slow/failing/throwing
17
+ * sink can never affect the caller. Absent a sink it is a pure no-op, so a
18
+ * no-webhook-config daemon is byte-identical to before this change.
19
+ *
20
+ * @module @omnicross/core/pipeline/webhookEmit
21
+ */
22
+
23
+ /** The sink the daemon registers; it MUST enqueue-and-return (never block). */
24
+ type WebhookSink = (event: WebhookEvent) => void;
25
+ /** Install (or clear, with `null`) the webhook sink. Idempotent; last write wins. */
26
+ declare function setWebhookSink(fn: WebhookSink | null): void;
27
+ /**
28
+ * Emit a webhook event to the registered sink. A no-op when no sink is set
29
+ * (zero regression). NEVER throws (a misbehaving sink is swallowed) and NEVER
30
+ * awaits (the sink enqueues + returns) — so no request path is ever delayed.
31
+ */
32
+ declare function emitWebhookEvent(event: WebhookEvent): void;
33
+ /** TEST SEAM — clear the sink so a suite starts from the no-sink baseline. */
34
+ declare function __resetWebhookSinkForTests(): void;
35
+
36
+ export { type WebhookSink, __resetWebhookSinkForTests, emitWebhookEvent, setWebhookSink };