@omnicross/core 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/NOTICE +57 -57
- package/README.md +15 -15
- package/dist/auth/GeminiCodeAssistProjectResolver.cjs +6 -1
- package/dist/auth/GeminiCodeAssistProjectResolver.js +6 -1
- package/dist/chunk-3QFXFCHG.js +33 -0
- package/dist/chunk-4IH4EL7M.cjs +9 -0
- package/dist/chunk-4YINUUKQ.cjs +33 -0
- package/dist/chunk-5ENKBSWO.js +311 -0
- package/dist/chunk-6RPZADX3.cjs +92 -0
- package/dist/chunk-7Y47UCF2.js +142 -0
- package/dist/chunk-AEOZIDEB.cjs +32 -0
- package/dist/chunk-APYG5QD7.cjs +50 -0
- package/dist/{chunk-MNYKI4CI.js → chunk-BPKCU575.js} +29 -0
- package/dist/{chunk-SN3YWBX7.cjs → chunk-DKPXN34V.cjs} +2108 -538
- package/dist/{chunk-4NBS6KPV.cjs → chunk-DQ5VAYZ6.cjs} +7 -8
- package/dist/chunk-E3UCVHLP.cjs +142 -0
- package/dist/chunk-FCR77GYM.cjs +33 -0
- package/dist/{chunk-74TMJA7Z.js → chunk-HRRYG2AX.js} +8 -4
- package/dist/chunk-HUZZZ3JL.js +32 -0
- package/dist/{chunk-KUU2RNG6.cjs → chunk-HYN75H6G.cjs} +3 -0
- package/dist/{chunk-QOCNX236.js → chunk-IAXWICZU.js} +24 -1
- package/dist/{chunk-JO5NLTLY.js → chunk-IK3KE3AU.js} +3 -0
- package/dist/{chunk-V5KPWNYX.cjs → chunk-JMJBSACD.cjs} +3 -3
- package/dist/chunk-K5NM7VAH.js +33 -0
- package/dist/{chunk-N3V2J5ZO.cjs → chunk-KFI44N2R.cjs} +8 -4
- package/dist/chunk-L74VDN4A.cjs +32 -0
- package/dist/chunk-OCEUVQHW.cjs +112 -0
- package/dist/chunk-OE6TDIWW.js +22 -0
- package/dist/chunk-OZFM4X3S.js +18 -0
- package/dist/{chunk-LKZJEL6E.cjs → chunk-Q27JY5RG.cjs} +6 -4
- package/dist/{chunk-SPVWWUHX.cjs → chunk-QWBWGODS.cjs} +24 -1
- package/dist/{chunk-2FEVTJWG.js → chunk-QYTT6GE3.js} +1929 -359
- package/dist/{chunk-UYPEN5XE.cjs → chunk-RGTR7CIO.cjs} +6 -6
- package/dist/chunk-RPII3E6Z.cjs +145 -0
- package/dist/{chunk-XBSYYZIY.cjs → chunk-SNYBEXLB.cjs} +31 -2
- package/dist/{chunk-2DCNB7DF.cjs → chunk-SU2GCLAC.cjs} +30 -10
- package/dist/{chunk-5HTVET6E.js → chunk-TIER4SUC.js} +24 -4
- package/dist/chunk-TKJMZBAH.js +32 -0
- package/dist/{chunk-ZSVQT3PW.js → chunk-UBWEBKRC.js} +5 -6
- package/dist/chunk-UHGVBFU3.js +385 -0
- package/dist/chunk-UIBD2YY5.cjs +22 -0
- package/dist/chunk-UNEFIWXI.cjs +32 -0
- package/dist/chunk-VACWOIRE.cjs +385 -0
- package/dist/{chunk-O466Y272.js → chunk-VPBAUQ2M.js} +7 -7
- package/dist/chunk-VQY5W4YW.cjs +311 -0
- package/dist/chunk-WLYIIEAF.js +50 -0
- package/dist/chunk-WNY4WMRF.js +32 -0
- package/dist/chunk-XEKD23J5.js +9 -0
- package/dist/chunk-XK5CIRMQ.js +112 -0
- package/dist/chunk-XSVNC2UD.cjs +18 -0
- package/dist/chunk-XTEI64OU.js +145 -0
- package/dist/chunk-XX6NQJMA.js +92 -0
- package/dist/{chunk-745DV5FL.js → chunk-Y7FO65VT.js} +3 -3
- package/dist/{chunk-PXUJF5HS.js → chunk-ZY6KU6P3.js} +4 -2
- package/dist/completion/CompletionService.cjs +30 -17
- package/dist/completion/CompletionService.js +29 -16
- package/dist/completion/NativeSearchInjector.cjs +3 -3
- package/dist/completion/NativeSearchInjector.js +2 -2
- package/dist/completion/openrouter-headers.cjs +3 -6
- package/dist/completion/openrouter-headers.d.cts +9 -12
- package/dist/completion/openrouter-headers.d.ts +9 -12
- package/dist/completion/openrouter-headers.js +2 -5
- package/dist/completion/openrouter-models.cjs +4 -3
- package/dist/completion/openrouter-models.js +2 -1
- package/dist/completion.cjs +30 -17
- package/dist/completion.js +29 -16
- package/dist/index.cjs +151 -20
- package/dist/index.d.cts +44 -10
- package/dist/index.d.ts +44 -10
- package/dist/index.js +160 -29
- package/dist/keyPolicy-Cp0FntZl.d.cts +90 -0
- package/dist/keyPolicy-Cp0FntZl.d.ts +90 -0
- package/dist/outbound-api/auditCapture.cjs +9 -0
- package/dist/outbound-api/auditCapture.d.cts +52 -0
- package/dist/outbound-api/auditCapture.d.ts +52 -0
- package/dist/outbound-api/auditCapture.js +9 -0
- package/dist/outbound-api/auditRedact.cjs +8 -0
- package/dist/outbound-api/auditRedact.d.cts +30 -0
- package/dist/outbound-api/auditRedact.d.ts +30 -0
- package/dist/outbound-api/auditRedact.js +8 -0
- package/dist/outbound-api/billingCapture.cjs +8 -0
- package/dist/outbound-api/billingCapture.d.cts +61 -0
- package/dist/outbound-api/billingCapture.d.ts +61 -0
- package/dist/outbound-api/billingCapture.js +8 -0
- package/dist/outbound-api/quotaWarn.cjs +12 -0
- package/dist/outbound-api/quotaWarn.d.cts +43 -0
- package/dist/outbound-api/quotaWarn.d.ts +43 -0
- package/dist/outbound-api/quotaWarn.js +12 -0
- package/dist/outbound-api/routeResolver.cjs +5 -2
- package/dist/outbound-api/routeResolver.d.cts +9 -2
- package/dist/outbound-api/routeResolver.d.ts +9 -2
- package/dist/outbound-api/routeResolver.js +4 -1
- package/dist/outbound-api/types.cjs +6 -1
- package/dist/outbound-api/types.d.cts +12 -144
- package/dist/outbound-api/types.d.ts +12 -144
- package/dist/outbound-api/types.js +6 -0
- package/dist/outbound-api.cjs +144 -17
- package/dist/outbound-api.d.cts +655 -25
- package/dist/outbound-api.d.ts +655 -25
- package/dist/outbound-api.js +148 -21
- package/dist/pipeline/AuthSource.d.cts +29 -1
- package/dist/pipeline/AuthSource.d.ts +29 -1
- package/dist/pipeline/LlmConfigProviderAuth.cjs +3 -3
- package/dist/pipeline/LlmConfigProviderAuth.js +2 -2
- package/dist/pipeline/SubscriptionAccountHealth.cjs +22 -0
- package/dist/pipeline/SubscriptionAccountHealth.d.cts +235 -0
- package/dist/pipeline/SubscriptionAccountHealth.d.ts +235 -0
- package/dist/pipeline/SubscriptionAccountHealth.js +22 -0
- package/dist/pipeline/SubscriptionAuthSource.cjs +2 -2
- package/dist/pipeline/SubscriptionAuthSource.d.cts +3 -2
- package/dist/pipeline/SubscriptionAuthSource.d.ts +3 -2
- package/dist/pipeline/SubscriptionAuthSource.js +1 -1
- package/dist/pipeline/SubscriptionAuthStrategy.d.cts +30 -1
- package/dist/pipeline/SubscriptionAuthStrategy.d.ts +30 -1
- package/dist/pipeline/auditSink.cjs +14 -0
- package/dist/pipeline/auditSink.d.cts +48 -0
- package/dist/pipeline/auditSink.d.ts +48 -0
- package/dist/pipeline/auditSink.js +14 -0
- package/dist/pipeline/auditUsageStash.cjs +10 -0
- package/dist/pipeline/auditUsageStash.d.cts +37 -0
- package/dist/pipeline/auditUsageStash.d.ts +37 -0
- package/dist/pipeline/auditUsageStash.js +10 -0
- package/dist/pipeline/billingEmit.cjs +14 -0
- package/dist/pipeline/billingEmit.d.cts +49 -0
- package/dist/pipeline/billingEmit.d.ts +49 -0
- package/dist/pipeline/billingEmit.js +14 -0
- package/dist/pipeline/executeProviderCall.cjs +2 -2
- package/dist/pipeline/executeProviderCall.js +1 -1
- package/dist/pipeline/upstreamFetch.cjs +14 -0
- package/dist/pipeline/upstreamFetch.d.cts +83 -0
- package/dist/pipeline/upstreamFetch.d.ts +83 -0
- package/dist/pipeline/upstreamFetch.js +14 -0
- package/dist/pipeline/webhookEmit.cjs +10 -0
- package/dist/pipeline/webhookEmit.d.cts +36 -0
- package/dist/pipeline/webhookEmit.d.ts +36 -0
- package/dist/pipeline/webhookEmit.js +10 -0
- package/dist/ports/usage-event-store.d.cts +26 -1
- package/dist/ports/usage-event-store.d.ts +26 -1
- package/dist/ports.d.cts +8 -1
- package/dist/ports.d.ts +8 -1
- package/dist/provider-proxy/ProviderProxy.cjs +30 -17
- package/dist/provider-proxy/ProviderProxy.js +29 -16
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.cjs +15 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.cts +121 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.ts +121 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.js +15 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.cjs +20 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.d.cts +89 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.d.ts +89 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.js +20 -0
- package/dist/provider-proxy/ingress/providerProxyShared.cjs +30 -17
- package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -2
- package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -2
- package/dist/provider-proxy/ingress/providerProxyShared.js +29 -16
- package/dist/provider-proxy/matchText.cjs +4 -2
- package/dist/provider-proxy/matchText.d.cts +14 -1
- package/dist/provider-proxy/matchText.d.ts +14 -1
- package/dist/provider-proxy/matchText.js +3 -1
- package/dist/provider-proxy/types.d.cts +30 -0
- package/dist/provider-proxy/types.d.ts +30 -0
- package/dist/provider-proxy.cjs +30 -17
- package/dist/provider-proxy.js +29 -16
- package/dist/{routeResolver-HE-ZO0fO.d.ts → routeResolver-C4T7yClx.d.ts} +36 -10
- package/dist/{routeResolver-BrbK6ja9.d.cts → routeResolver-CB3tvJKy.d.cts} +36 -10
- package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +2 -2
- package/dist/transformer/transformers/OpenAIResponseTransformer.js +1 -1
- package/dist/transformer/transformers.cjs +7 -7
- package/dist/transformer/transformers.js +8 -8
- package/dist/transformer.cjs +9 -9
- package/dist/transformer.js +8 -8
- package/dist/types-B8Arpxn0.d.cts +754 -0
- package/dist/types-lgPYQuZS.d.ts +754 -0
- package/dist/usage/usage-recorder.cjs +3 -2
- package/dist/usage/usage-recorder.d.cts +19 -1
- package/dist/usage/usage-recorder.d.ts +19 -1
- package/dist/usage/usage-recorder.js +2 -1
- package/dist/usage.cjs +3 -2
- package/dist/usage.js +2 -1
- package/package.json +64 -62
- package/dist/chunk-3MEACFK3.js +0 -193
- package/dist/chunk-6VIXXLMX.cjs +0 -14
- package/dist/chunk-E3WHL7CO.js +0 -14
- package/dist/chunk-G2FUJNA2.cjs +0 -193
|
@@ -1,39 +1,52 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProviderProxy,
|
|
3
3
|
isLoopbackAddress
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-QOCNX236.js";
|
|
4
|
+
} from "../chunk-QYTT6GE3.js";
|
|
6
5
|
import "../chunk-VVEHS2LI.js";
|
|
7
6
|
import "../chunk-46RLHI7D.js";
|
|
8
|
-
import "../chunk-G2UTNSGU.js";
|
|
9
|
-
import "../chunk-MZNPGW5Q.js";
|
|
10
7
|
import "../chunk-DK4A7DLE.js";
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-C7PSERMH.js";
|
|
13
|
-
import "../chunk-5HTVET6E.js";
|
|
14
|
-
import "../chunk-Z7LUNECE.js";
|
|
8
|
+
import "../chunk-VPBAUQ2M.js";
|
|
15
9
|
import "../chunk-ZJZAOKI7.js";
|
|
16
10
|
import "../chunk-FTQ7IQUC.js";
|
|
11
|
+
import "../chunk-C7PSERMH.js";
|
|
12
|
+
import "../chunk-TIER4SUC.js";
|
|
13
|
+
import "../chunk-Z7LUNECE.js";
|
|
17
14
|
import "../chunk-7VU7V2E4.js";
|
|
18
15
|
import "../chunk-ZLX3KGXX.js";
|
|
19
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-BPKCU575.js";
|
|
17
|
+
import "../chunk-G2UTNSGU.js";
|
|
18
|
+
import "../chunk-MZNPGW5Q.js";
|
|
19
|
+
import "../chunk-XTEI64OU.js";
|
|
20
|
+
import "../chunk-XX6NQJMA.js";
|
|
21
|
+
import "../chunk-IAXWICZU.js";
|
|
22
|
+
import "../chunk-OE6TDIWW.js";
|
|
20
23
|
import "../chunk-DRWHTIIZ.js";
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
24
|
+
import "../chunk-IK3KE3AU.js";
|
|
25
|
+
import "../chunk-ZY6KU6P3.js";
|
|
23
26
|
import "../chunk-JWC6APFQ.js";
|
|
24
27
|
import "../chunk-5ERIZW3D.js";
|
|
25
|
-
import "../chunk-
|
|
28
|
+
import "../chunk-5ENKBSWO.js";
|
|
29
|
+
import "../chunk-HRRYG2AX.js";
|
|
26
30
|
import "../chunk-AVYJ4YBN.js";
|
|
27
|
-
import "../chunk-
|
|
28
|
-
import "../chunk-
|
|
31
|
+
import "../chunk-WLYIIEAF.js";
|
|
32
|
+
import "../chunk-TKJMZBAH.js";
|
|
33
|
+
import "../chunk-3QFXFCHG.js";
|
|
34
|
+
import "../chunk-UHGVBFU3.js";
|
|
29
35
|
import "../chunk-AQ5TNQB7.js";
|
|
36
|
+
import "../chunk-XEKD23J5.js";
|
|
37
|
+
import "../chunk-H5JUT3KV.js";
|
|
38
|
+
import "../chunk-7Y47UCF2.js";
|
|
39
|
+
import "../chunk-K5NM7VAH.js";
|
|
40
|
+
import "../chunk-WNY4WMRF.js";
|
|
41
|
+
import "../chunk-OZFM4X3S.js";
|
|
30
42
|
import "../chunk-5ZQBEOMD.js";
|
|
31
43
|
import "../chunk-Z7Y2NPHY.js";
|
|
32
44
|
import "../chunk-S4WBV25P.js";
|
|
45
|
+
import "../chunk-XK5CIRMQ.js";
|
|
33
46
|
import "../chunk-CDHS2QDC.js";
|
|
34
|
-
import "../chunk-
|
|
35
|
-
import "../chunk-E3WHL7CO.js";
|
|
47
|
+
import "../chunk-Y7FO65VT.js";
|
|
36
48
|
import "../chunk-FMOBD2OQ.js";
|
|
49
|
+
import "../chunk-HUZZZ3JL.js";
|
|
37
50
|
export {
|
|
38
51
|
ProviderProxy,
|
|
39
52
|
isLoopbackAddress
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkRPII3E6Zcjs = require('../../chunk-RPII3E6Z.cjs');
|
|
8
|
+
require('../../chunk-6RPZADX3.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
exports.CC_HEADER_TTL_MS = _chunkRPII3E6Zcjs.CC_HEADER_TTL_MS; exports.SubscriptionIdentityStore = _chunkRPII3E6Zcjs.SubscriptionIdentityStore; exports.__resetSharedIdentityStoreForTests = _chunkRPII3E6Zcjs.__resetSharedIdentityStoreForTests; exports.getSharedIdentityStore = _chunkRPII3E6Zcjs.getSharedIdentityStore; exports.setSharedIdentityStore = _chunkRPII3E6Zcjs.setSharedIdentityStore;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubscriptionIdentityStore — the per-account client-identity capture/freeze/replay
|
|
3
|
+
* store for claude-subscription outbound traffic (subscription-client-fingerprint
|
|
4
|
+
* #7, design D1/D4/D5/D7).
|
|
5
|
+
*
|
|
6
|
+
* Shaped like the existing in-memory `SubscriptionAccountHealth` tracker: an
|
|
7
|
+
* in-memory `Map`, an injectable `now` clock, NO external deps. It is keyed by an
|
|
8
|
+
* opaque `providerId + '\0' + accountId` string — core never learns "account"
|
|
9
|
+
* semantics (exactly the health-tracker precedent), and there is NO
|
|
10
|
+
* `@omnicross/subscriptions` import. It carries NO token/secret: the capture
|
|
11
|
+
* whitelist + `sanitizeFrozenHeaders` exclude `authorization`/`x-api-key`/`cookie`
|
|
12
|
+
* at BOTH ingress and store-normalize.
|
|
13
|
+
*
|
|
14
|
+
* Freeze/replay model (D4 — never fabricate):
|
|
15
|
+
* - The FIRST captured fingerprint set for an account is FROZEN; every later
|
|
16
|
+
* outbound request for that account REPLAYS that frozen set → a stable
|
|
17
|
+
* per-account identity. Stainless headers are frozen-stable forever; the
|
|
18
|
+
* non-stainless (CC) headers refresh on a 7-day TTL from a newer real
|
|
19
|
+
* observation (P2, `refreshNonStainless`).
|
|
20
|
+
* - Values are ONLY ever REAL captured client values — nothing here invents a
|
|
21
|
+
* `x-stainless-*`. An un-captured account replays NOTHING (the caller then
|
|
22
|
+
* applies at most the operator UA baseline).
|
|
23
|
+
*
|
|
24
|
+
* Persistence (P2, D5): OPTIONAL. When a persistence port is installed
|
|
25
|
+
* (`setPersistence`), a first-seen freeze / TTL refresh is written through to the
|
|
26
|
+
* account entry (additive NON-secret metadata) so the identity survives restart;
|
|
27
|
+
* at boot the daemon `seed()`s the store from the persisted entries. In-memory-only
|
|
28
|
+
* (no port) is the P1 default — a real client re-captures after restart.
|
|
29
|
+
*
|
|
30
|
+
* @module provider-proxy/identity/SubscriptionIdentityStore
|
|
31
|
+
*/
|
|
32
|
+
/** A frozen per-account client identity (the captured fingerprint headers). */
|
|
33
|
+
interface FrozenIdentity {
|
|
34
|
+
/** The captured fingerprint headers (lowercased keys; token/secret excluded). */
|
|
35
|
+
headers: Record<string, string>;
|
|
36
|
+
/** Epoch ms of the freeze (or last TTL refresh). */
|
|
37
|
+
capturedAt: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write-through persistence port (P2, D5). The store calls `persist` on a
|
|
41
|
+
* first-seen freeze / TTL refresh; the daemon implementation writes the identity
|
|
42
|
+
* onto the account entry. Fire-and-forget — the store swallows any throw so the
|
|
43
|
+
* hot path is never affected. Core defines the port; the daemon supplies it (the
|
|
44
|
+
* `setUpstreamProxyResolver` / `setWebhookSink` precedent — no daemon import).
|
|
45
|
+
*/
|
|
46
|
+
interface IdentityPersistencePort {
|
|
47
|
+
persist(providerId: string, accountId: string, identity: FrozenIdentity): void;
|
|
48
|
+
}
|
|
49
|
+
/** The CC-header (non-stainless) refresh TTL — 7 days (design D6/P2). */
|
|
50
|
+
declare const CC_HEADER_TTL_MS: number;
|
|
51
|
+
/** Constructor knobs (all optional). */
|
|
52
|
+
interface SubscriptionIdentityStoreOptions {
|
|
53
|
+
/** Injectable clock (ms). Default `Date.now`. */
|
|
54
|
+
now?: () => number;
|
|
55
|
+
/** Whether capture/replay engages. Default `false` (byte-identical outbound). */
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
/** Operator UA baseline applied ONLY when nothing was captured (piece 4). */
|
|
58
|
+
ua?: string;
|
|
59
|
+
/** The CC-header refresh TTL (ms). Default {@link CC_HEADER_TTL_MS}. */
|
|
60
|
+
ccHeaderTtlMs?: number;
|
|
61
|
+
}
|
|
62
|
+
declare class SubscriptionIdentityStore {
|
|
63
|
+
private readonly identities;
|
|
64
|
+
private readonly now;
|
|
65
|
+
private enabled;
|
|
66
|
+
private ua;
|
|
67
|
+
private ccHeaderTtlMs;
|
|
68
|
+
private persistence;
|
|
69
|
+
constructor(opts?: SubscriptionIdentityStoreOptions);
|
|
70
|
+
/** Whether capture/replay is engaged (config flag). */
|
|
71
|
+
isEnabled(): boolean;
|
|
72
|
+
/** The operator UA baseline (piece 4), or undefined when unset. */
|
|
73
|
+
uaBaseline(): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Re-apply config to the LIVE shared instance (bootstrap, mirroring the health
|
|
76
|
+
* tracker's `configure`). Only defined fields override; `ua: null` clears the
|
|
77
|
+
* baseline.
|
|
78
|
+
*/
|
|
79
|
+
configure(opts: {
|
|
80
|
+
enabled?: boolean;
|
|
81
|
+
ua?: string | null;
|
|
82
|
+
}): void;
|
|
83
|
+
/** Install (or clear) the write-through persistence port (P2). */
|
|
84
|
+
setPersistence(port: IdentityPersistencePort | null): void;
|
|
85
|
+
/**
|
|
86
|
+
* Boot seed (P2, D5): install a PERSISTED identity for an account, but NEVER
|
|
87
|
+
* over a live in-memory capture (a re-captured identity from this session wins).
|
|
88
|
+
* A no-op for an empty/absent identity. Does NOT write back through the port.
|
|
89
|
+
*/
|
|
90
|
+
seed(providerId: string, accountId: string, identity: FrozenIdentity | undefined): void;
|
|
91
|
+
/**
|
|
92
|
+
* Capture a real client's fingerprint headers for an account. First-seen ⇒
|
|
93
|
+
* FREEZE the whole (sanitized) bag. Already-frozen ⇒ within the TTL, no change
|
|
94
|
+
* (stable identity); past the TTL, refresh the NON-stainless headers from the
|
|
95
|
+
* new observation while keeping stainless frozen-stable (P2). An empty/absent
|
|
96
|
+
* account id or an empty sanitized bag is a no-op (so an account with no
|
|
97
|
+
* fingerprint headers never freezes an empty identity → the caller falls back
|
|
98
|
+
* to the UA baseline). Fires the persistence port on a freeze/refresh.
|
|
99
|
+
*/
|
|
100
|
+
capture(providerId: string, accountId: string, incoming: Record<string, string>, now?: number): void;
|
|
101
|
+
/**
|
|
102
|
+
* The frozen identity headers for an account, or `undefined` when none is
|
|
103
|
+
* frozen (or the frozen set is empty). Returns a COPY (the caller merges it into
|
|
104
|
+
* a mutable outbound header bag).
|
|
105
|
+
*/
|
|
106
|
+
replay(providerId: string, accountId: string): Record<string, string> | undefined;
|
|
107
|
+
/** Whether an identity is frozen for an account (admin coarse status — D7). */
|
|
108
|
+
hasIdentity(providerId: string, accountId: string): boolean;
|
|
109
|
+
/** The freeze/refresh time for an account's identity (admin coarse status). */
|
|
110
|
+
capturedAt(providerId: string, accountId: string): number | undefined;
|
|
111
|
+
private emitPersist;
|
|
112
|
+
private key;
|
|
113
|
+
}
|
|
114
|
+
/** The shared identity store; lazily constructs a default (disabled) instance. */
|
|
115
|
+
declare function getSharedIdentityStore(): SubscriptionIdentityStore;
|
|
116
|
+
/** Install a specific store at bootstrap (idempotent; last write wins). */
|
|
117
|
+
declare function setSharedIdentityStore(instance: SubscriptionIdentityStore): void;
|
|
118
|
+
/** Reset the shared singleton (tests / teardown only). */
|
|
119
|
+
declare function __resetSharedIdentityStoreForTests(): void;
|
|
120
|
+
|
|
121
|
+
export { CC_HEADER_TTL_MS, type FrozenIdentity, type IdentityPersistencePort, SubscriptionIdentityStore, type SubscriptionIdentityStoreOptions, __resetSharedIdentityStoreForTests, getSharedIdentityStore, setSharedIdentityStore };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubscriptionIdentityStore — the per-account client-identity capture/freeze/replay
|
|
3
|
+
* store for claude-subscription outbound traffic (subscription-client-fingerprint
|
|
4
|
+
* #7, design D1/D4/D5/D7).
|
|
5
|
+
*
|
|
6
|
+
* Shaped like the existing in-memory `SubscriptionAccountHealth` tracker: an
|
|
7
|
+
* in-memory `Map`, an injectable `now` clock, NO external deps. It is keyed by an
|
|
8
|
+
* opaque `providerId + '\0' + accountId` string — core never learns "account"
|
|
9
|
+
* semantics (exactly the health-tracker precedent), and there is NO
|
|
10
|
+
* `@omnicross/subscriptions` import. It carries NO token/secret: the capture
|
|
11
|
+
* whitelist + `sanitizeFrozenHeaders` exclude `authorization`/`x-api-key`/`cookie`
|
|
12
|
+
* at BOTH ingress and store-normalize.
|
|
13
|
+
*
|
|
14
|
+
* Freeze/replay model (D4 — never fabricate):
|
|
15
|
+
* - The FIRST captured fingerprint set for an account is FROZEN; every later
|
|
16
|
+
* outbound request for that account REPLAYS that frozen set → a stable
|
|
17
|
+
* per-account identity. Stainless headers are frozen-stable forever; the
|
|
18
|
+
* non-stainless (CC) headers refresh on a 7-day TTL from a newer real
|
|
19
|
+
* observation (P2, `refreshNonStainless`).
|
|
20
|
+
* - Values are ONLY ever REAL captured client values — nothing here invents a
|
|
21
|
+
* `x-stainless-*`. An un-captured account replays NOTHING (the caller then
|
|
22
|
+
* applies at most the operator UA baseline).
|
|
23
|
+
*
|
|
24
|
+
* Persistence (P2, D5): OPTIONAL. When a persistence port is installed
|
|
25
|
+
* (`setPersistence`), a first-seen freeze / TTL refresh is written through to the
|
|
26
|
+
* account entry (additive NON-secret metadata) so the identity survives restart;
|
|
27
|
+
* at boot the daemon `seed()`s the store from the persisted entries. In-memory-only
|
|
28
|
+
* (no port) is the P1 default — a real client re-captures after restart.
|
|
29
|
+
*
|
|
30
|
+
* @module provider-proxy/identity/SubscriptionIdentityStore
|
|
31
|
+
*/
|
|
32
|
+
/** A frozen per-account client identity (the captured fingerprint headers). */
|
|
33
|
+
interface FrozenIdentity {
|
|
34
|
+
/** The captured fingerprint headers (lowercased keys; token/secret excluded). */
|
|
35
|
+
headers: Record<string, string>;
|
|
36
|
+
/** Epoch ms of the freeze (or last TTL refresh). */
|
|
37
|
+
capturedAt: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write-through persistence port (P2, D5). The store calls `persist` on a
|
|
41
|
+
* first-seen freeze / TTL refresh; the daemon implementation writes the identity
|
|
42
|
+
* onto the account entry. Fire-and-forget — the store swallows any throw so the
|
|
43
|
+
* hot path is never affected. Core defines the port; the daemon supplies it (the
|
|
44
|
+
* `setUpstreamProxyResolver` / `setWebhookSink` precedent — no daemon import).
|
|
45
|
+
*/
|
|
46
|
+
interface IdentityPersistencePort {
|
|
47
|
+
persist(providerId: string, accountId: string, identity: FrozenIdentity): void;
|
|
48
|
+
}
|
|
49
|
+
/** The CC-header (non-stainless) refresh TTL — 7 days (design D6/P2). */
|
|
50
|
+
declare const CC_HEADER_TTL_MS: number;
|
|
51
|
+
/** Constructor knobs (all optional). */
|
|
52
|
+
interface SubscriptionIdentityStoreOptions {
|
|
53
|
+
/** Injectable clock (ms). Default `Date.now`. */
|
|
54
|
+
now?: () => number;
|
|
55
|
+
/** Whether capture/replay engages. Default `false` (byte-identical outbound). */
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
/** Operator UA baseline applied ONLY when nothing was captured (piece 4). */
|
|
58
|
+
ua?: string;
|
|
59
|
+
/** The CC-header refresh TTL (ms). Default {@link CC_HEADER_TTL_MS}. */
|
|
60
|
+
ccHeaderTtlMs?: number;
|
|
61
|
+
}
|
|
62
|
+
declare class SubscriptionIdentityStore {
|
|
63
|
+
private readonly identities;
|
|
64
|
+
private readonly now;
|
|
65
|
+
private enabled;
|
|
66
|
+
private ua;
|
|
67
|
+
private ccHeaderTtlMs;
|
|
68
|
+
private persistence;
|
|
69
|
+
constructor(opts?: SubscriptionIdentityStoreOptions);
|
|
70
|
+
/** Whether capture/replay is engaged (config flag). */
|
|
71
|
+
isEnabled(): boolean;
|
|
72
|
+
/** The operator UA baseline (piece 4), or undefined when unset. */
|
|
73
|
+
uaBaseline(): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Re-apply config to the LIVE shared instance (bootstrap, mirroring the health
|
|
76
|
+
* tracker's `configure`). Only defined fields override; `ua: null` clears the
|
|
77
|
+
* baseline.
|
|
78
|
+
*/
|
|
79
|
+
configure(opts: {
|
|
80
|
+
enabled?: boolean;
|
|
81
|
+
ua?: string | null;
|
|
82
|
+
}): void;
|
|
83
|
+
/** Install (or clear) the write-through persistence port (P2). */
|
|
84
|
+
setPersistence(port: IdentityPersistencePort | null): void;
|
|
85
|
+
/**
|
|
86
|
+
* Boot seed (P2, D5): install a PERSISTED identity for an account, but NEVER
|
|
87
|
+
* over a live in-memory capture (a re-captured identity from this session wins).
|
|
88
|
+
* A no-op for an empty/absent identity. Does NOT write back through the port.
|
|
89
|
+
*/
|
|
90
|
+
seed(providerId: string, accountId: string, identity: FrozenIdentity | undefined): void;
|
|
91
|
+
/**
|
|
92
|
+
* Capture a real client's fingerprint headers for an account. First-seen ⇒
|
|
93
|
+
* FREEZE the whole (sanitized) bag. Already-frozen ⇒ within the TTL, no change
|
|
94
|
+
* (stable identity); past the TTL, refresh the NON-stainless headers from the
|
|
95
|
+
* new observation while keeping stainless frozen-stable (P2). An empty/absent
|
|
96
|
+
* account id or an empty sanitized bag is a no-op (so an account with no
|
|
97
|
+
* fingerprint headers never freezes an empty identity → the caller falls back
|
|
98
|
+
* to the UA baseline). Fires the persistence port on a freeze/refresh.
|
|
99
|
+
*/
|
|
100
|
+
capture(providerId: string, accountId: string, incoming: Record<string, string>, now?: number): void;
|
|
101
|
+
/**
|
|
102
|
+
* The frozen identity headers for an account, or `undefined` when none is
|
|
103
|
+
* frozen (or the frozen set is empty). Returns a COPY (the caller merges it into
|
|
104
|
+
* a mutable outbound header bag).
|
|
105
|
+
*/
|
|
106
|
+
replay(providerId: string, accountId: string): Record<string, string> | undefined;
|
|
107
|
+
/** Whether an identity is frozen for an account (admin coarse status — D7). */
|
|
108
|
+
hasIdentity(providerId: string, accountId: string): boolean;
|
|
109
|
+
/** The freeze/refresh time for an account's identity (admin coarse status). */
|
|
110
|
+
capturedAt(providerId: string, accountId: string): number | undefined;
|
|
111
|
+
private emitPersist;
|
|
112
|
+
private key;
|
|
113
|
+
}
|
|
114
|
+
/** The shared identity store; lazily constructs a default (disabled) instance. */
|
|
115
|
+
declare function getSharedIdentityStore(): SubscriptionIdentityStore;
|
|
116
|
+
/** Install a specific store at bootstrap (idempotent; last write wins). */
|
|
117
|
+
declare function setSharedIdentityStore(instance: SubscriptionIdentityStore): void;
|
|
118
|
+
/** Reset the shared singleton (tests / teardown only). */
|
|
119
|
+
declare function __resetSharedIdentityStoreForTests(): void;
|
|
120
|
+
|
|
121
|
+
export { CC_HEADER_TTL_MS, type FrozenIdentity, type IdentityPersistencePort, SubscriptionIdentityStore, type SubscriptionIdentityStoreOptions, __resetSharedIdentityStoreForTests, getSharedIdentityStore, setSharedIdentityStore };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CC_HEADER_TTL_MS,
|
|
3
|
+
SubscriptionIdentityStore,
|
|
4
|
+
__resetSharedIdentityStoreForTests,
|
|
5
|
+
getSharedIdentityStore,
|
|
6
|
+
setSharedIdentityStore
|
|
7
|
+
} from "../../chunk-XTEI64OU.js";
|
|
8
|
+
import "../../chunk-XX6NQJMA.js";
|
|
9
|
+
export {
|
|
10
|
+
CC_HEADER_TTL_MS,
|
|
11
|
+
SubscriptionIdentityStore,
|
|
12
|
+
__resetSharedIdentityStoreForTests,
|
|
13
|
+
getSharedIdentityStore,
|
|
14
|
+
setSharedIdentityStore
|
|
15
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
var _chunk6RPZADX3cjs = require('../../chunk-6RPZADX3.cjs');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
exports.STAINLESS_PREFIX = _chunk6RPZADX3cjs.STAINLESS_PREFIX; exports.applyFingerprint = _chunk6RPZADX3cjs.applyFingerprint; exports.captureCallerIdentity = _chunk6RPZADX3cjs.captureCallerIdentity; exports.extractFingerprintHeaders = _chunk6RPZADX3cjs.extractFingerprintHeaders; exports.isStainless = _chunk6RPZADX3cjs.isStainless; exports.mergeFrozenIdentity = _chunk6RPZADX3cjs.mergeFrozenIdentity; exports.refreshNonStainless = _chunk6RPZADX3cjs.refreshNonStainless; exports.sanitizeFrozenHeaders = _chunk6RPZADX3cjs.sanitizeFrozenHeaders;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { SubscriptionIdentityStore } from './SubscriptionIdentityStore.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* fingerprintHeaders — the PURE half of subscription client-fingerprint replay
|
|
5
|
+
* (subscription-client-fingerprint #7, design D2/D3/D4/D7).
|
|
6
|
+
*
|
|
7
|
+
* Holds ONLY pure functions (no state, no store): the capture WHITELIST
|
|
8
|
+
* (`extractFingerprintHeaders`), the store-normalizer (`sanitizeFrozenHeaders`),
|
|
9
|
+
* the TTL refresh split (`refreshNonStainless`), the outbound merge
|
|
10
|
+
* (`mergeFrozenIdentity`), and the one composition entrypoint the relay calls
|
|
11
|
+
* (`applyFingerprint`, which takes the store INSTANCE as a parameter so this file
|
|
12
|
+
* never imports the store at runtime — no cycle).
|
|
13
|
+
*
|
|
14
|
+
* SAFETY CORE (non-negotiable):
|
|
15
|
+
* - The capture whitelist is POSITIVE (`x-stainless-*` + a small set of
|
|
16
|
+
* Claude-Code / Anthropic-SDK header names) AND has an explicit EXCLUSION of
|
|
17
|
+
* `authorization` / `x-api-key` / `cookie` (the token/secret) — belt AND
|
|
18
|
+
* suspenders, so widening the whitelist can never leak auth.
|
|
19
|
+
* - The outbound merge NEVER overwrites `authorization` / `content-type`
|
|
20
|
+
* (the auth strategy owns auth; content-type is fixed) and never overwrites a
|
|
21
|
+
* header the outbound build already set (case-insensitive).
|
|
22
|
+
* - Values are only ever REAL captured client headers — nothing here fabricates
|
|
23
|
+
* a `x-stainless-*` value. The only synthesizable piece is the operator-set UA
|
|
24
|
+
* baseline, applied in `applyFingerprint` ONLY when NOTHING was captured.
|
|
25
|
+
*
|
|
26
|
+
* @module provider-proxy/identity/fingerprintHeaders
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Header-name prefix that marks a stainless (SDK-runtime) fingerprint header. */
|
|
30
|
+
declare const STAINLESS_PREFIX = "x-stainless-";
|
|
31
|
+
/** Whether a header name (any case) is a stainless fingerprint header. */
|
|
32
|
+
declare function isStainless(name: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Capture: extract the WHITELISTED fingerprint headers from an incoming client
|
|
35
|
+
* request's header bag (`http.IncomingHttpHeaders`-shaped). Array values (rare —
|
|
36
|
+
* duplicate headers) are joined with `, `. Keys are lowercased. The auth/secret
|
|
37
|
+
* exclusion is applied FIRST so it wins over any whitelist entry. Never throws.
|
|
38
|
+
*/
|
|
39
|
+
declare function extractFingerprintHeaders(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* Ingress capture gate (subscription-client-fingerprint #7): extract the caller's
|
|
42
|
+
* fingerprint headers ONLY when replay is enabled — returns `undefined` when
|
|
43
|
+
* disabled so the ingress does NO extraction work on the default/BYO path (and
|
|
44
|
+
* threads nothing to the relay). Behavior when enabled is identical to calling
|
|
45
|
+
* `extractFingerprintHeaders` directly.
|
|
46
|
+
*/
|
|
47
|
+
declare function captureCallerIdentity(store: SubscriptionIdentityStore, reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Store-normalize a header bag before freezing/seeding: lowercase keys, drop
|
|
50
|
+
* empty/non-string values, and HARD-EXCLUDE the auth/secret + protected-outbound
|
|
51
|
+
* sets. This is the second line of defense (after the capture whitelist) so a
|
|
52
|
+
* persisted/seeded identity can never carry a token even if a bad bag was handed
|
|
53
|
+
* in. Idempotent.
|
|
54
|
+
*/
|
|
55
|
+
declare function sanitizeFrozenHeaders(headers: Record<string, string>): Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* TTL refresh split (P2, piece 2): produce the refreshed frozen set when a newer
|
|
58
|
+
* real capture is observed after the CC-header TTL. The STAINLESS set stays
|
|
59
|
+
* frozen-stable (only the original values survive — a real client keeps a stable
|
|
60
|
+
* stainless identity); the NON-stainless headers (user-agent / anthropic-beta /
|
|
61
|
+
* x-app / …) are refreshed from the newer observation, falling back to the frozen
|
|
62
|
+
* value when the new bag omits one. New stainless headers in the incoming bag are
|
|
63
|
+
* IGNORED (stainless never grows/changes after the first freeze).
|
|
64
|
+
*/
|
|
65
|
+
declare function refreshNonStainless(frozen: Record<string, string>, incoming: Record<string, string>): Record<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Merge a frozen identity into the outbound `headers` in place. NEVER overwrites
|
|
68
|
+
* `authorization` / `content-type`, and never overwrites a header already present
|
|
69
|
+
* (case-insensitive) — so a header the auth strategy or the relay already set
|
|
70
|
+
* always wins. The identity keys are already lowercased (`sanitizeFrozenHeaders`).
|
|
71
|
+
*/
|
|
72
|
+
declare function mergeFrozenIdentity(headers: Record<string, string>, identity: Record<string, string>): void;
|
|
73
|
+
/**
|
|
74
|
+
* The ONE composition entrypoint the claude same-format relay calls, AFTER
|
|
75
|
+
* `applyHeaders` reported the selected account and BEFORE `fetchUpstream`.
|
|
76
|
+
*
|
|
77
|
+
* Disabled (default) OR no account id ⇒ a strict no-op — the `headers` object is
|
|
78
|
+
* left BYTE-IDENTICAL (the zero-regression guarantee). When enabled:
|
|
79
|
+
* 1. capture the caller's real fingerprint headers for this account (first-seen
|
|
80
|
+
* freeze; P2 TTL refresh) — per-account, keyed by the reported account id;
|
|
81
|
+
* 2. replay the frozen identity for the account into `headers` (never
|
|
82
|
+
* overwriting auth/content-type). On the FIRST request this is the client's
|
|
83
|
+
* own just-captured headers (honest); later requests replay the frozen set;
|
|
84
|
+
* 3. if NOTHING is captured for the account, apply ONLY the operator-configured
|
|
85
|
+
* UA baseline (never a fabricated stainless value).
|
|
86
|
+
*/
|
|
87
|
+
declare function applyFingerprint(store: SubscriptionIdentityStore, headers: Record<string, string>, providerId: string, accountId: string | undefined, callerIdentity: Record<string, string> | undefined, now?: number): void;
|
|
88
|
+
|
|
89
|
+
export { STAINLESS_PREFIX, applyFingerprint, captureCallerIdentity, extractFingerprintHeaders, isStainless, mergeFrozenIdentity, refreshNonStainless, sanitizeFrozenHeaders };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { SubscriptionIdentityStore } from './SubscriptionIdentityStore.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* fingerprintHeaders — the PURE half of subscription client-fingerprint replay
|
|
5
|
+
* (subscription-client-fingerprint #7, design D2/D3/D4/D7).
|
|
6
|
+
*
|
|
7
|
+
* Holds ONLY pure functions (no state, no store): the capture WHITELIST
|
|
8
|
+
* (`extractFingerprintHeaders`), the store-normalizer (`sanitizeFrozenHeaders`),
|
|
9
|
+
* the TTL refresh split (`refreshNonStainless`), the outbound merge
|
|
10
|
+
* (`mergeFrozenIdentity`), and the one composition entrypoint the relay calls
|
|
11
|
+
* (`applyFingerprint`, which takes the store INSTANCE as a parameter so this file
|
|
12
|
+
* never imports the store at runtime — no cycle).
|
|
13
|
+
*
|
|
14
|
+
* SAFETY CORE (non-negotiable):
|
|
15
|
+
* - The capture whitelist is POSITIVE (`x-stainless-*` + a small set of
|
|
16
|
+
* Claude-Code / Anthropic-SDK header names) AND has an explicit EXCLUSION of
|
|
17
|
+
* `authorization` / `x-api-key` / `cookie` (the token/secret) — belt AND
|
|
18
|
+
* suspenders, so widening the whitelist can never leak auth.
|
|
19
|
+
* - The outbound merge NEVER overwrites `authorization` / `content-type`
|
|
20
|
+
* (the auth strategy owns auth; content-type is fixed) and never overwrites a
|
|
21
|
+
* header the outbound build already set (case-insensitive).
|
|
22
|
+
* - Values are only ever REAL captured client headers — nothing here fabricates
|
|
23
|
+
* a `x-stainless-*` value. The only synthesizable piece is the operator-set UA
|
|
24
|
+
* baseline, applied in `applyFingerprint` ONLY when NOTHING was captured.
|
|
25
|
+
*
|
|
26
|
+
* @module provider-proxy/identity/fingerprintHeaders
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Header-name prefix that marks a stainless (SDK-runtime) fingerprint header. */
|
|
30
|
+
declare const STAINLESS_PREFIX = "x-stainless-";
|
|
31
|
+
/** Whether a header name (any case) is a stainless fingerprint header. */
|
|
32
|
+
declare function isStainless(name: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Capture: extract the WHITELISTED fingerprint headers from an incoming client
|
|
35
|
+
* request's header bag (`http.IncomingHttpHeaders`-shaped). Array values (rare —
|
|
36
|
+
* duplicate headers) are joined with `, `. Keys are lowercased. The auth/secret
|
|
37
|
+
* exclusion is applied FIRST so it wins over any whitelist entry. Never throws.
|
|
38
|
+
*/
|
|
39
|
+
declare function extractFingerprintHeaders(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* Ingress capture gate (subscription-client-fingerprint #7): extract the caller's
|
|
42
|
+
* fingerprint headers ONLY when replay is enabled — returns `undefined` when
|
|
43
|
+
* disabled so the ingress does NO extraction work on the default/BYO path (and
|
|
44
|
+
* threads nothing to the relay). Behavior when enabled is identical to calling
|
|
45
|
+
* `extractFingerprintHeaders` directly.
|
|
46
|
+
*/
|
|
47
|
+
declare function captureCallerIdentity(store: SubscriptionIdentityStore, reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Store-normalize a header bag before freezing/seeding: lowercase keys, drop
|
|
50
|
+
* empty/non-string values, and HARD-EXCLUDE the auth/secret + protected-outbound
|
|
51
|
+
* sets. This is the second line of defense (after the capture whitelist) so a
|
|
52
|
+
* persisted/seeded identity can never carry a token even if a bad bag was handed
|
|
53
|
+
* in. Idempotent.
|
|
54
|
+
*/
|
|
55
|
+
declare function sanitizeFrozenHeaders(headers: Record<string, string>): Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* TTL refresh split (P2, piece 2): produce the refreshed frozen set when a newer
|
|
58
|
+
* real capture is observed after the CC-header TTL. The STAINLESS set stays
|
|
59
|
+
* frozen-stable (only the original values survive — a real client keeps a stable
|
|
60
|
+
* stainless identity); the NON-stainless headers (user-agent / anthropic-beta /
|
|
61
|
+
* x-app / …) are refreshed from the newer observation, falling back to the frozen
|
|
62
|
+
* value when the new bag omits one. New stainless headers in the incoming bag are
|
|
63
|
+
* IGNORED (stainless never grows/changes after the first freeze).
|
|
64
|
+
*/
|
|
65
|
+
declare function refreshNonStainless(frozen: Record<string, string>, incoming: Record<string, string>): Record<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Merge a frozen identity into the outbound `headers` in place. NEVER overwrites
|
|
68
|
+
* `authorization` / `content-type`, and never overwrites a header already present
|
|
69
|
+
* (case-insensitive) — so a header the auth strategy or the relay already set
|
|
70
|
+
* always wins. The identity keys are already lowercased (`sanitizeFrozenHeaders`).
|
|
71
|
+
*/
|
|
72
|
+
declare function mergeFrozenIdentity(headers: Record<string, string>, identity: Record<string, string>): void;
|
|
73
|
+
/**
|
|
74
|
+
* The ONE composition entrypoint the claude same-format relay calls, AFTER
|
|
75
|
+
* `applyHeaders` reported the selected account and BEFORE `fetchUpstream`.
|
|
76
|
+
*
|
|
77
|
+
* Disabled (default) OR no account id ⇒ a strict no-op — the `headers` object is
|
|
78
|
+
* left BYTE-IDENTICAL (the zero-regression guarantee). When enabled:
|
|
79
|
+
* 1. capture the caller's real fingerprint headers for this account (first-seen
|
|
80
|
+
* freeze; P2 TTL refresh) — per-account, keyed by the reported account id;
|
|
81
|
+
* 2. replay the frozen identity for the account into `headers` (never
|
|
82
|
+
* overwriting auth/content-type). On the FIRST request this is the client's
|
|
83
|
+
* own just-captured headers (honest); later requests replay the frozen set;
|
|
84
|
+
* 3. if NOTHING is captured for the account, apply ONLY the operator-configured
|
|
85
|
+
* UA baseline (never a fabricated stainless value).
|
|
86
|
+
*/
|
|
87
|
+
declare function applyFingerprint(store: SubscriptionIdentityStore, headers: Record<string, string>, providerId: string, accountId: string | undefined, callerIdentity: Record<string, string> | undefined, now?: number): void;
|
|
88
|
+
|
|
89
|
+
export { STAINLESS_PREFIX, applyFingerprint, captureCallerIdentity, extractFingerprintHeaders, isStainless, mergeFrozenIdentity, refreshNonStainless, sanitizeFrozenHeaders };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STAINLESS_PREFIX,
|
|
3
|
+
applyFingerprint,
|
|
4
|
+
captureCallerIdentity,
|
|
5
|
+
extractFingerprintHeaders,
|
|
6
|
+
isStainless,
|
|
7
|
+
mergeFrozenIdentity,
|
|
8
|
+
refreshNonStainless,
|
|
9
|
+
sanitizeFrozenHeaders
|
|
10
|
+
} from "../../chunk-XX6NQJMA.js";
|
|
11
|
+
export {
|
|
12
|
+
STAINLESS_PREFIX,
|
|
13
|
+
applyFingerprint,
|
|
14
|
+
captureCallerIdentity,
|
|
15
|
+
extractFingerprintHeaders,
|
|
16
|
+
isStainless,
|
|
17
|
+
mergeFrozenIdentity,
|
|
18
|
+
refreshNonStainless,
|
|
19
|
+
sanitizeFrozenHeaders
|
|
20
|
+
};
|
|
@@ -7,39 +7,52 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
11
|
-
require('../../chunk-SPVWWUHX.cjs');
|
|
10
|
+
var _chunkDKPXN34Vcjs = require('../../chunk-DKPXN34V.cjs');
|
|
12
11
|
require('../../chunk-HQP3K7PU.cjs');
|
|
13
12
|
require('../../chunk-FZ46M34D.cjs');
|
|
14
|
-
require('../../chunk-46ZIFWYG.cjs');
|
|
15
|
-
require('../../chunk-GBHYAGX3.cjs');
|
|
16
13
|
require('../../chunk-3OPYJG76.cjs');
|
|
17
|
-
require('../../chunk-
|
|
18
|
-
require('../../chunk-7YN22L2H.cjs');
|
|
19
|
-
require('../../chunk-2DCNB7DF.cjs');
|
|
20
|
-
require('../../chunk-C72S6TTV.cjs');
|
|
14
|
+
require('../../chunk-RGTR7CIO.cjs');
|
|
21
15
|
require('../../chunk-DWKQZ2SK.cjs');
|
|
22
16
|
require('../../chunk-4VAVYUZS.cjs');
|
|
17
|
+
require('../../chunk-7YN22L2H.cjs');
|
|
18
|
+
require('../../chunk-SU2GCLAC.cjs');
|
|
19
|
+
require('../../chunk-C72S6TTV.cjs');
|
|
23
20
|
require('../../chunk-EYZYXJTJ.cjs');
|
|
24
21
|
require('../../chunk-YMFAJFQT.cjs');
|
|
25
|
-
require('../../chunk-
|
|
22
|
+
require('../../chunk-SNYBEXLB.cjs');
|
|
23
|
+
require('../../chunk-46ZIFWYG.cjs');
|
|
24
|
+
require('../../chunk-GBHYAGX3.cjs');
|
|
25
|
+
require('../../chunk-RPII3E6Z.cjs');
|
|
26
|
+
require('../../chunk-6RPZADX3.cjs');
|
|
27
|
+
require('../../chunk-QWBWGODS.cjs');
|
|
28
|
+
require('../../chunk-UIBD2YY5.cjs');
|
|
26
29
|
require('../../chunk-R3HK6R4B.cjs');
|
|
27
|
-
require('../../chunk-
|
|
28
|
-
require('../../chunk-
|
|
30
|
+
require('../../chunk-HYN75H6G.cjs');
|
|
31
|
+
require('../../chunk-Q27JY5RG.cjs');
|
|
29
32
|
require('../../chunk-QXD4MV2X.cjs');
|
|
30
33
|
require('../../chunk-NYUNU75A.cjs');
|
|
31
|
-
require('../../chunk-
|
|
34
|
+
require('../../chunk-VQY5W4YW.cjs');
|
|
35
|
+
require('../../chunk-KFI44N2R.cjs');
|
|
32
36
|
require('../../chunk-SVNDB62D.cjs');
|
|
33
|
-
require('../../chunk-
|
|
34
|
-
require('../../chunk-
|
|
37
|
+
require('../../chunk-APYG5QD7.cjs');
|
|
38
|
+
require('../../chunk-L74VDN4A.cjs');
|
|
39
|
+
require('../../chunk-4YINUUKQ.cjs');
|
|
40
|
+
require('../../chunk-VACWOIRE.cjs');
|
|
35
41
|
require('../../chunk-QBZJ7P2T.cjs');
|
|
42
|
+
require('../../chunk-4IH4EL7M.cjs');
|
|
43
|
+
require('../../chunk-A2YMUCBT.cjs');
|
|
44
|
+
require('../../chunk-E3UCVHLP.cjs');
|
|
45
|
+
require('../../chunk-FCR77GYM.cjs');
|
|
46
|
+
require('../../chunk-AEOZIDEB.cjs');
|
|
47
|
+
require('../../chunk-XSVNC2UD.cjs');
|
|
36
48
|
require('../../chunk-SUEGJ75D.cjs');
|
|
37
49
|
require('../../chunk-RSJ3TWJQ.cjs');
|
|
38
50
|
require('../../chunk-YGXJGRFI.cjs');
|
|
51
|
+
require('../../chunk-OCEUVQHW.cjs');
|
|
39
52
|
require('../../chunk-NZYN7C3P.cjs');
|
|
40
|
-
require('../../chunk-
|
|
41
|
-
require('../../chunk-6VIXXLMX.cjs');
|
|
53
|
+
require('../../chunk-JMJBSACD.cjs');
|
|
42
54
|
require('../../chunk-GMMT7RVN.cjs');
|
|
55
|
+
require('../../chunk-UNEFIWXI.cjs');
|
|
43
56
|
|
|
44
57
|
|
|
45
58
|
|
|
@@ -49,4 +62,4 @@ require('../../chunk-GMMT7RVN.cjs');
|
|
|
49
62
|
|
|
50
63
|
|
|
51
64
|
|
|
52
|
-
exports.getAnthropicEndpointTransformer =
|
|
65
|
+
exports.getAnthropicEndpointTransformer = _chunkDKPXN34Vcjs.getAnthropicEndpointTransformer; exports.getGeminiEndpointTransformer = _chunkDKPXN34Vcjs.getGeminiEndpointTransformer; exports.getResponsesEndpointTransformer = _chunkDKPXN34Vcjs.getResponsesEndpointTransformer; exports.getSharedExecutor = _chunkDKPXN34Vcjs.getSharedExecutor; exports.readBody = _chunkDKPXN34Vcjs.readBody; exports.relayResponse = _chunkDKPXN34Vcjs.relayResponse; exports.resolvePoolBoundKey = _chunkDKPXN34Vcjs.resolvePoolBoundKey; exports.writeError = _chunkDKPXN34Vcjs.writeError;
|