@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
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/provider-proxy/identity/fingerprintHeaders.ts
|
|
2
|
+
var STAINLESS_PREFIX = "x-stainless-";
|
|
3
|
+
var FINGERPRINT_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
4
|
+
"user-agent",
|
|
5
|
+
"anthropic-beta",
|
|
6
|
+
"anthropic-version",
|
|
7
|
+
"anthropic-dangerous-direct-browser-access",
|
|
8
|
+
"x-app"
|
|
9
|
+
]);
|
|
10
|
+
var EXCLUDED_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
11
|
+
"authorization",
|
|
12
|
+
"x-api-key",
|
|
13
|
+
"cookie",
|
|
14
|
+
"proxy-authorization",
|
|
15
|
+
"set-cookie"
|
|
16
|
+
]);
|
|
17
|
+
var PROTECTED_OUTBOUND = /* @__PURE__ */ new Set(["authorization", "content-type"]);
|
|
18
|
+
function isStainless(name) {
|
|
19
|
+
return name.toLowerCase().startsWith(STAINLESS_PREFIX);
|
|
20
|
+
}
|
|
21
|
+
function extractFingerprintHeaders(reqHeaders) {
|
|
22
|
+
const out = {};
|
|
23
|
+
for (const [rawKey, rawVal] of Object.entries(reqHeaders)) {
|
|
24
|
+
if (rawVal === void 0) continue;
|
|
25
|
+
const key = rawKey.toLowerCase();
|
|
26
|
+
if (EXCLUDED_HEADER_NAMES.has(key)) continue;
|
|
27
|
+
const whitelisted = FINGERPRINT_HEADER_NAMES.has(key) || key.startsWith(STAINLESS_PREFIX);
|
|
28
|
+
if (!whitelisted) continue;
|
|
29
|
+
const value = Array.isArray(rawVal) ? rawVal.filter((v) => typeof v === "string").join(", ") : rawVal;
|
|
30
|
+
if (typeof value === "string" && value.length > 0) out[key] = value;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
function captureCallerIdentity(store, reqHeaders) {
|
|
35
|
+
if (!store.isEnabled()) return void 0;
|
|
36
|
+
return extractFingerprintHeaders(reqHeaders);
|
|
37
|
+
}
|
|
38
|
+
function sanitizeFrozenHeaders(headers) {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
41
|
+
if (typeof v !== "string" || v.length === 0) continue;
|
|
42
|
+
const lower = k.toLowerCase();
|
|
43
|
+
if (EXCLUDED_HEADER_NAMES.has(lower) || PROTECTED_OUTBOUND.has(lower)) continue;
|
|
44
|
+
out[lower] = v;
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function refreshNonStainless(frozen, incoming) {
|
|
49
|
+
const out = {};
|
|
50
|
+
for (const [k, v] of Object.entries(frozen)) {
|
|
51
|
+
if (isStainless(k)) out[k] = v;
|
|
52
|
+
}
|
|
53
|
+
const nonStainlessKeys = /* @__PURE__ */ new Set();
|
|
54
|
+
for (const k of Object.keys(frozen)) if (!isStainless(k)) nonStainlessKeys.add(k);
|
|
55
|
+
for (const k of Object.keys(incoming)) if (!isStainless(k)) nonStainlessKeys.add(k);
|
|
56
|
+
for (const k of nonStainlessKeys) {
|
|
57
|
+
const v = _nullishCoalesce(incoming[k], () => ( frozen[k]));
|
|
58
|
+
if (typeof v === "string" && v.length > 0) out[k] = v;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
function mergeFrozenIdentity(headers, identity) {
|
|
63
|
+
const present = new Set(Object.keys(headers).map((k) => k.toLowerCase()));
|
|
64
|
+
for (const [k, v] of Object.entries(identity)) {
|
|
65
|
+
const lower = k.toLowerCase();
|
|
66
|
+
if (PROTECTED_OUTBOUND.has(lower)) continue;
|
|
67
|
+
if (present.has(lower)) continue;
|
|
68
|
+
headers[k] = v;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function applyFingerprint(store, headers, providerId, accountId, callerIdentity, now) {
|
|
72
|
+
if (!store.isEnabled() || !accountId) return;
|
|
73
|
+
if (callerIdentity) store.capture(providerId, accountId, callerIdentity, now);
|
|
74
|
+
const identity = store.replay(providerId, accountId);
|
|
75
|
+
if (identity) {
|
|
76
|
+
mergeFrozenIdentity(headers, identity);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const ua = store.uaBaseline();
|
|
80
|
+
if (ua) mergeFrozenIdentity(headers, { "user-agent": ua });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
exports.STAINLESS_PREFIX = STAINLESS_PREFIX; exports.isStainless = isStainless; exports.extractFingerprintHeaders = extractFingerprintHeaders; exports.captureCallerIdentity = captureCallerIdentity; exports.sanitizeFrozenHeaders = sanitizeFrozenHeaders; exports.refreshNonStainless = refreshNonStainless; exports.mergeFrozenIdentity = mergeFrozenIdentity; exports.applyFingerprint = applyFingerprint;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
redactAuditText
|
|
3
|
+
} from "./chunk-K5NM7VAH.js";
|
|
4
|
+
import {
|
|
5
|
+
getAuditCaptureConfig,
|
|
6
|
+
recordAudit
|
|
7
|
+
} from "./chunk-WNY4WMRF.js";
|
|
8
|
+
import {
|
|
9
|
+
readAuditUsage
|
|
10
|
+
} from "./chunk-OZFM4X3S.js";
|
|
11
|
+
|
|
12
|
+
// src/outbound-api/auditCapture.ts
|
|
13
|
+
import { randomUUID } from "crypto";
|
|
14
|
+
function isStreamingContentType(res) {
|
|
15
|
+
const ct = res.getHeader("content-type");
|
|
16
|
+
const value = Array.isArray(ct) ? ct.join(";") : String(ct ?? "");
|
|
17
|
+
return value.toLowerCase().includes("text/event-stream");
|
|
18
|
+
}
|
|
19
|
+
function resolveClientIp(req, trustForwardedFor) {
|
|
20
|
+
if (trustForwardedFor) {
|
|
21
|
+
const xff = req.headers["x-forwarded-for"];
|
|
22
|
+
const raw = Array.isArray(xff) ? xff[0] : xff;
|
|
23
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
24
|
+
const first = raw.split(",")[0]?.trim();
|
|
25
|
+
if (first) return first;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return req.socket?.remoteAddress ?? void 0;
|
|
29
|
+
}
|
|
30
|
+
function truncateToBytes(text, maxBytes) {
|
|
31
|
+
const buf = Buffer.from(text, "utf8");
|
|
32
|
+
if (buf.length <= maxBytes) return text;
|
|
33
|
+
return buf.subarray(0, maxBytes).toString("utf8");
|
|
34
|
+
}
|
|
35
|
+
function beginAuditCapture(req, res, now) {
|
|
36
|
+
const config = getAuditCaptureConfig();
|
|
37
|
+
if (!config) return null;
|
|
38
|
+
let rawRequestBody;
|
|
39
|
+
const responseChunks = [];
|
|
40
|
+
let responseBytes = 0;
|
|
41
|
+
let streamDetected = false;
|
|
42
|
+
let finished = false;
|
|
43
|
+
const ctx = {
|
|
44
|
+
setRequestBody(raw) {
|
|
45
|
+
if (config.captureBodies) rawRequestBody = raw;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
if (config.captureBodies) {
|
|
49
|
+
installResponseCapture(res, config.maxBodyBytes, {
|
|
50
|
+
push(chunk) {
|
|
51
|
+
responseBytes += chunk.length;
|
|
52
|
+
responseChunks.push(chunk);
|
|
53
|
+
},
|
|
54
|
+
get bytes() {
|
|
55
|
+
return responseBytes;
|
|
56
|
+
},
|
|
57
|
+
markStream() {
|
|
58
|
+
streamDetected = true;
|
|
59
|
+
},
|
|
60
|
+
get isStream() {
|
|
61
|
+
return streamDetected;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const finalize = () => {
|
|
66
|
+
if (finished) return;
|
|
67
|
+
finished = true;
|
|
68
|
+
try {
|
|
69
|
+
const record = {
|
|
70
|
+
id: randomUUID(),
|
|
71
|
+
ts: now,
|
|
72
|
+
method: req.method ?? "",
|
|
73
|
+
path: (req.url ?? "").split("?")[0] ?? "",
|
|
74
|
+
status: res.statusCode,
|
|
75
|
+
latencyMs: Math.max(0, Date.now() - now)
|
|
76
|
+
};
|
|
77
|
+
if (ctx.keyId != null) record.keyId = ctx.keyId;
|
|
78
|
+
const ip = resolveClientIp(req, config.trustForwardedFor);
|
|
79
|
+
if (ip) record.ip = ip;
|
|
80
|
+
const ua = req.headers["user-agent"];
|
|
81
|
+
if (typeof ua === "string" && ua) record.ua = ua;
|
|
82
|
+
if (ctx.model) record.model = ctx.model;
|
|
83
|
+
if (ctx.provider) record.provider = ctx.provider;
|
|
84
|
+
const usage = readAuditUsage(res);
|
|
85
|
+
if (usage) {
|
|
86
|
+
if (typeof usage.inputTokens === "number") record.inputTokens = usage.inputTokens;
|
|
87
|
+
if (typeof usage.outputTokens === "number") record.outputTokens = usage.outputTokens;
|
|
88
|
+
if (typeof usage.costUsd === "number") record.costUsd = usage.costUsd;
|
|
89
|
+
if (!record.model && usage.model) record.model = usage.model;
|
|
90
|
+
if (!record.provider && usage.provider) record.provider = usage.provider;
|
|
91
|
+
}
|
|
92
|
+
if (ctx.error) record.error = redactAuditText(ctx.error);
|
|
93
|
+
if (config.captureBodies) {
|
|
94
|
+
if (rawRequestBody != null && rawRequestBody.length > 0) {
|
|
95
|
+
record.requestBody = redactAuditText(truncateToBytes(rawRequestBody, config.maxBodyBytes));
|
|
96
|
+
}
|
|
97
|
+
if (!streamDetected && responseChunks.length > 0) {
|
|
98
|
+
const body = Buffer.concat(responseChunks).toString("utf8");
|
|
99
|
+
record.responseBody = redactAuditText(body);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
recordAudit(record);
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
res.once("close", finalize);
|
|
107
|
+
return ctx;
|
|
108
|
+
}
|
|
109
|
+
function installResponseCapture(res, maxBodyBytes, sink) {
|
|
110
|
+
let contentTypeChecked = false;
|
|
111
|
+
const capture = (chunk) => {
|
|
112
|
+
if (sink.isStream) return;
|
|
113
|
+
if (!contentTypeChecked) {
|
|
114
|
+
contentTypeChecked = true;
|
|
115
|
+
if (isStreamingContentType(res)) {
|
|
116
|
+
sink.markStream();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (sink.bytes >= maxBodyBytes) return;
|
|
121
|
+
let buf = null;
|
|
122
|
+
if (Buffer.isBuffer(chunk)) buf = chunk;
|
|
123
|
+
else if (typeof chunk === "string") buf = Buffer.from(chunk, "utf8");
|
|
124
|
+
if (!buf || buf.length === 0) return;
|
|
125
|
+
const remaining = maxBodyBytes - sink.bytes;
|
|
126
|
+
sink.push(buf.length > remaining ? buf.subarray(0, remaining) : buf);
|
|
127
|
+
};
|
|
128
|
+
const originalWrite = res.write.bind(res);
|
|
129
|
+
const originalEnd = res.end.bind(res);
|
|
130
|
+
res.write = ((chunk, ...args) => {
|
|
131
|
+
if (chunk != null) capture(chunk);
|
|
132
|
+
return originalWrite(chunk, ...args);
|
|
133
|
+
});
|
|
134
|
+
res.end = ((chunk, ...args) => {
|
|
135
|
+
if (chunk != null && typeof chunk !== "function") capture(chunk);
|
|
136
|
+
return originalEnd(chunk, ...args);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
beginAuditCapture
|
|
142
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/pipeline/auditSink.ts
|
|
2
|
+
var sink = null;
|
|
3
|
+
var captureConfig = null;
|
|
4
|
+
function setAuditSink(fn) {
|
|
5
|
+
sink = fn;
|
|
6
|
+
}
|
|
7
|
+
function setAuditCaptureConfig(config) {
|
|
8
|
+
captureConfig = config && config.enabled ? config : null;
|
|
9
|
+
}
|
|
10
|
+
function getAuditCaptureConfig() {
|
|
11
|
+
return captureConfig;
|
|
12
|
+
}
|
|
13
|
+
function recordAudit(record) {
|
|
14
|
+
const active = sink;
|
|
15
|
+
if (!active) return;
|
|
16
|
+
try {
|
|
17
|
+
active(record);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function __resetAuditSinkForTests() {
|
|
22
|
+
sink = null;
|
|
23
|
+
captureConfig = null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
exports.setAuditSink = setAuditSink; exports.setAuditCaptureConfig = setAuditCaptureConfig; exports.getAuditCaptureConfig = getAuditCaptureConfig; exports.recordAudit = recordAudit; exports.__resetAuditSinkForTests = __resetAuditSinkForTests;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkL74VDN4Acjs = require('./chunk-L74VDN4A.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkXSVNC2UDcjs = require('./chunk-XSVNC2UD.cjs');
|
|
8
|
+
|
|
9
|
+
// src/outbound-api/billingCapture.ts
|
|
10
|
+
var _crypto = require('crypto');
|
|
11
|
+
var defaultDefer = (fn) => {
|
|
12
|
+
setTimeout(fn, 0);
|
|
13
|
+
};
|
|
14
|
+
function beginBillingCapture(_req, res, now, defer = defaultDefer) {
|
|
15
|
+
if (!_chunkL74VDN4Acjs.getBillingCaptureConfig.call(void 0, )) return null;
|
|
16
|
+
const ctx = {};
|
|
17
|
+
let finished = false;
|
|
18
|
+
const finalize = () => {
|
|
19
|
+
if (finished) return;
|
|
20
|
+
finished = true;
|
|
21
|
+
const status = res.statusCode;
|
|
22
|
+
defer(() => {
|
|
23
|
+
try {
|
|
24
|
+
const usage = _chunkXSVNC2UDcjs.readAuditUsage.call(void 0, res);
|
|
25
|
+
if (!usage) return;
|
|
26
|
+
const event = {
|
|
27
|
+
id: _crypto.randomUUID.call(void 0, ),
|
|
28
|
+
ts: now,
|
|
29
|
+
model: _nullishCoalesce(_nullishCoalesce(ctx.model, () => ( usage.model)), () => ( "")),
|
|
30
|
+
authMode: _nullishCoalesce(ctx.authMode, () => ( "byo")),
|
|
31
|
+
inputTokens: _nullishCoalesce(usage.inputTokens, () => ( 0)),
|
|
32
|
+
outputTokens: _nullishCoalesce(usage.outputTokens, () => ( 0)),
|
|
33
|
+
costUsd: _nullishCoalesce(usage.costUsd, () => ( 0)),
|
|
34
|
+
status
|
|
35
|
+
};
|
|
36
|
+
if (ctx.keyId != null) event.keyId = ctx.keyId;
|
|
37
|
+
const provider = _nullishCoalesce(ctx.provider, () => ( usage.provider));
|
|
38
|
+
if (provider) event.provider = provider;
|
|
39
|
+
_chunkL74VDN4Acjs.publishBillingEvent.call(void 0, event);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
res.once("close", finalize);
|
|
45
|
+
return ctx;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
exports.beginBillingCapture = beginBillingCapture;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
stashAuditUsage
|
|
3
|
+
} from "./chunk-OZFM4X3S.js";
|
|
4
|
+
|
|
1
5
|
// src/usage/usage-recorder.ts
|
|
2
6
|
var UsageRecorder = class {
|
|
3
7
|
constructor(store, pricing, logger, options = {}) {
|
|
@@ -5,11 +9,13 @@ var UsageRecorder = class {
|
|
|
5
9
|
this.pricing = pricing;
|
|
6
10
|
this.logger = logger;
|
|
7
11
|
this.defer = options.defer ?? ((fn) => setTimeout(fn, 0));
|
|
12
|
+
this.onRecord = options.onRecord;
|
|
8
13
|
}
|
|
9
14
|
store;
|
|
10
15
|
pricing;
|
|
11
16
|
logger;
|
|
12
17
|
defer;
|
|
18
|
+
onRecord;
|
|
13
19
|
/**
|
|
14
20
|
* Record one LLM request. Returns immediately — the actual store insert is
|
|
15
21
|
* deferred so the caller's response path is unblocked.
|
|
@@ -17,6 +23,14 @@ var UsageRecorder = class {
|
|
|
17
23
|
* Errors during the insert are logged but never thrown.
|
|
18
24
|
*/
|
|
19
25
|
record(input) {
|
|
26
|
+
if (input.auditResponse) {
|
|
27
|
+
stashAuditUsage(input.auditResponse, {
|
|
28
|
+
inputTokens: input.usage.inputTokens,
|
|
29
|
+
outputTokens: input.usage.outputTokens,
|
|
30
|
+
model: input.model,
|
|
31
|
+
provider: input.providerId
|
|
32
|
+
});
|
|
33
|
+
}
|
|
20
34
|
this.defer(() => {
|
|
21
35
|
void this.recordAsync(input).catch((err) => {
|
|
22
36
|
this.logger.warn("[UsageRecorder] failed to persist usage event", {
|
|
@@ -35,6 +49,18 @@ var UsageRecorder = class {
|
|
|
35
49
|
input.model,
|
|
36
50
|
input.usage
|
|
37
51
|
);
|
|
52
|
+
if (input.auditResponse) {
|
|
53
|
+
try {
|
|
54
|
+
stashAuditUsage(input.auditResponse, { costUsd });
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (this.onRecord && input.apiKeyId) {
|
|
59
|
+
try {
|
|
60
|
+
this.onRecord(input.apiKeyId, costUsd, Date.now());
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
38
64
|
const row = {
|
|
39
65
|
messageId: input.messageId ?? null,
|
|
40
66
|
parentMessageId: input.parentMessageId ?? null,
|
|
@@ -73,6 +99,9 @@ var UsageRecorder = class {
|
|
|
73
99
|
getByApiKey(range) {
|
|
74
100
|
return this.store.getByApiKey(range);
|
|
75
101
|
}
|
|
102
|
+
getTimeSeries(range, bucket) {
|
|
103
|
+
return this.store.getTimeSeries(range, bucket);
|
|
104
|
+
}
|
|
76
105
|
getMessagesForSession(sessionId) {
|
|
77
106
|
return this.store.getMessagesForSession(sessionId);
|
|
78
107
|
}
|