@apifuse/provider-sdk 2.2.0-beta.58 → 2.2.0-beta.60
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/AUTHORING.md +25 -0
- package/CHANGELOG.md +8 -0
- package/README.md +18 -2
- package/bin/apifuse-dev.ts +2 -1
- package/bin/apifuse-pack-types.ts +49 -0
- package/bin/apifuse-perf.ts +41 -4
- package/bin/apifuse-record.ts +9 -2
- package/dist/cli/templates/provider/README.md.tpl +15 -3
- package/dist/config/loader.d.ts +7 -0
- package/dist/config/loader.js +43 -18
- package/dist/declaration-validation.d.ts +2 -1
- package/dist/declaration-validation.js +39 -0
- package/dist/define.d.ts +4 -4
- package/dist/define.js +25 -1
- package/dist/engine.d.ts +16 -0
- package/dist/engine.js +59 -3
- package/dist/error-resolution.js +13 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +4 -2
- package/dist/lint.js +38 -17
- package/dist/provider.d.ts +3 -3
- package/dist/provider.js +2 -2
- package/dist/runtime/bounded-expiring-map.d.ts +21 -0
- package/dist/runtime/bounded-expiring-map.js +64 -0
- package/dist/runtime/browser.js +2 -1
- package/dist/runtime/cache.d.ts +2 -0
- package/dist/runtime/cache.js +11 -3
- package/dist/runtime/diagnostic-env-values.d.ts +5 -0
- package/dist/runtime/diagnostic-env-values.js +57 -0
- package/dist/runtime/diagnostic-env.d.ts +11 -0
- package/dist/runtime/diagnostic-env.js +35 -0
- package/dist/runtime/diagnostic-redactor.d.ts +49 -0
- package/dist/runtime/diagnostic-redactor.js +569 -0
- package/dist/runtime/egress-lease.d.ts +65 -0
- package/dist/runtime/egress-lease.js +236 -0
- package/dist/runtime/env.js +2 -1
- package/dist/runtime/http.js +1 -0
- package/dist/runtime/instrumentation.js +3 -0
- package/dist/runtime/ocr.js +2 -1
- package/dist/runtime/otlp.js +5 -4
- package/dist/runtime/proxy-nodemaven.js +3 -2
- package/dist/runtime/proxy-retry-policy.d.ts +4 -1
- package/dist/runtime/proxy-retry-policy.js +11 -2
- package/dist/runtime/request-options.d.ts +7 -0
- package/dist/runtime/request-options.js +62 -22
- package/dist/runtime/request-telemetry.d.ts +7 -9
- package/dist/runtime/resolver-config.d.ts +7 -0
- package/dist/runtime/resolver-config.js +8 -0
- package/dist/runtime/resolver-public.d.ts +3 -1
- package/dist/runtime/resolver-public.js +1 -1
- package/dist/runtime/resolver-shared.d.ts +9 -0
- package/dist/runtime/resolver-shared.js +57 -0
- package/dist/runtime/resolver-telemetry.d.ts +134 -0
- package/dist/runtime/resolver-telemetry.js +204 -0
- package/dist/runtime/resolver-usage.d.ts +24 -0
- package/dist/runtime/resolver-usage.js +60 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +5 -0
- package/dist/runtime/resolver-vendors/bindings.js +5 -0
- package/dist/runtime/resolver-vendors/browser.js +0 -1
- package/dist/runtime/resolver-vendors/capsolver.d.ts +2 -2
- package/dist/runtime/resolver-vendors/capsolver.js +21 -9
- package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
- package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -2
- package/dist/runtime/resolver-vendors/twocaptcha.js +26 -10
- package/dist/runtime/resolver-vendors/types.d.ts +35 -5
- package/dist/runtime/resolver-vendors/types.js +20 -10
- package/dist/runtime/resolver.d.ts +5 -1
- package/dist/runtime/resolver.js +400 -111
- package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
- package/dist/runtime/stealth-akamai-sbsd.js +142 -0
- package/dist/runtime/stealth.js +547 -53
- package/dist/runtime/stt.js +3 -2
- package/dist/runtime/trace.d.ts +5 -0
- package/dist/runtime/trace.js +115 -20
- package/dist/schema.d.ts +20 -0
- package/dist/schema.js +72 -2
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +1 -0
- package/dist/server/self-test-redaction.js +8 -33
- package/dist/server/self-test.d.ts +4 -0
- package/dist/server/self-test.js +10 -1
- package/dist/server/sensitive-values.d.ts +26 -0
- package/dist/server/sensitive-values.js +131 -0
- package/dist/server/serve-implementation.d.ts +7 -1
- package/dist/server/serve-implementation.js +394 -125
- package/dist/server/trace-output.d.ts +2 -1
- package/dist/server/trace-output.js +46 -14
- package/dist/server/types.d.ts +6 -0
- package/dist/server/types.js +14 -0
- package/dist/stealth/profiles.d.ts +7 -1
- package/dist/stealth/profiles.js +9 -0
- package/dist/testing/run.js +6 -0
- package/dist/trace-sanitization.d.ts +4 -3
- package/dist/trace-sanitization.js +45 -22
- package/dist/types.d.ts +106 -10
- package/package.json +2 -1
- package/src/cli/templates/provider/README.md.tpl +15 -3
- package/src/config/loader.ts +47 -18
- package/src/declaration-validation.ts +47 -1
- package/src/define.ts +45 -3
- package/src/engine.ts +78 -3
- package/src/error-resolution.ts +13 -0
- package/src/index.ts +34 -1
- package/src/lint.ts +44 -18
- package/src/provider.ts +10 -0
- package/src/runtime/bounded-expiring-map.ts +67 -0
- package/src/runtime/browser.ts +2 -1
- package/src/runtime/cache.ts +13 -3
- package/src/runtime/diagnostic-env-values.ts +56 -0
- package/src/runtime/diagnostic-env.ts +55 -0
- package/src/runtime/diagnostic-redactor.ts +662 -0
- package/src/runtime/egress-lease.ts +341 -0
- package/src/runtime/env.ts +2 -1
- package/src/runtime/http.ts +1 -0
- package/src/runtime/instrumentation.ts +3 -0
- package/src/runtime/ocr.ts +2 -1
- package/src/runtime/otlp.ts +5 -4
- package/src/runtime/proxy-nodemaven.ts +3 -2
- package/src/runtime/proxy-retry-policy.ts +12 -1
- package/src/runtime/request-options.ts +76 -28
- package/src/runtime/request-telemetry.ts +5 -7
- package/src/runtime/resolver-config.ts +12 -0
- package/src/runtime/resolver-public.ts +21 -0
- package/src/runtime/resolver-shared.ts +75 -0
- package/src/runtime/resolver-telemetry.ts +362 -0
- package/src/runtime/resolver-usage.ts +96 -0
- package/src/runtime/resolver-vendors/bindings.ts +5 -0
- package/src/runtime/resolver-vendors/browser.ts +0 -1
- package/src/runtime/resolver-vendors/capsolver.ts +22 -3
- package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +26 -12
- package/src/runtime/resolver-vendors/types.ts +60 -12
- package/src/runtime/resolver.ts +468 -126
- package/src/runtime/stealth-akamai-sbsd.ts +207 -0
- package/src/runtime/stealth.ts +727 -95
- package/src/runtime/stt.ts +3 -2
- package/src/runtime/trace.ts +168 -26
- package/src/schema.ts +80 -2
- package/src/server/index.ts +21 -0
- package/src/server/self-test-redaction.ts +10 -40
- package/src/server/self-test.ts +13 -0
- package/src/server/sensitive-values.ts +200 -0
- package/src/server/serve-implementation.ts +561 -136
- package/src/server/trace-output.ts +77 -17
- package/src/server/types.ts +14 -0
- package/src/stealth/profiles.ts +10 -0
- package/src/testing/run.ts +6 -0
- package/src/trace-sanitization.ts +70 -23
- package/src/types.ts +124 -19
package/dist/runtime/stt.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readDiagnosticEnv } from "./diagnostic-env.js";
|
|
1
2
|
import { ProviderError, TransportError, ValidationError } from "../errors.js";
|
|
2
3
|
import { createTimeoutController, isTimeoutLikeError } from "./timeout.js";
|
|
3
4
|
export const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
|
|
@@ -32,7 +33,7 @@ export function createUnsupportedSttClient(reason) {
|
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
function normalizedEnvValue(env, key) {
|
|
35
|
-
const value = env
|
|
36
|
+
const value = readDiagnosticEnv(key, env)?.trim();
|
|
36
37
|
return value ? value : undefined;
|
|
37
38
|
}
|
|
38
39
|
export function createSttClientFromEnv(config, env = process.env) {
|
|
@@ -53,7 +54,7 @@ export function createSttClientFromEnv(config, env = process.env) {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
const accountId = env.APIFUSE__CLOUDFLARE__ACCOUNT_ID?.trim();
|
|
56
|
-
const apiToken = env
|
|
57
|
+
const apiToken = readDiagnosticEnv(APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, env)?.trim();
|
|
57
58
|
if (!accountId || !apiToken) {
|
|
58
59
|
return createUnsupportedSttClient(`STT backend ${backend} requires ${CLOUDFLARE_ACCOUNT_ID_ENV} and ${APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV}`);
|
|
59
60
|
}
|
package/dist/runtime/trace.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TraceContext as BaseTraceContext, TraceAttributeValue, TraceConfig, TraceSpan } from "../types.js";
|
|
2
|
+
import { type DiagnosticRedactor } from "./diagnostic-redactor.js";
|
|
2
3
|
import { type OTLPExportOptions } from "./otlp.js";
|
|
3
4
|
export type SpanAttributeValue = TraceAttributeValue;
|
|
4
5
|
export type Span = TraceSpan;
|
|
@@ -8,6 +9,8 @@ export interface TraceContext extends BaseTraceContext {
|
|
|
8
9
|
export interface CreateTraceContextOptions {
|
|
9
10
|
maxSpans?: number;
|
|
10
11
|
onSpan?: (span: Span) => void;
|
|
12
|
+
/** Redacts diagnostic attribute values and errors before recording or calling onSpan. */
|
|
13
|
+
redact?: DiagnosticRedactor;
|
|
11
14
|
exportOptions?: OTLPExportOptions;
|
|
12
15
|
resourceAttributes?: Record<string, string>;
|
|
13
16
|
/** W3C-compatible 32-character lowercase hexadecimal trace id used for export. */
|
|
@@ -34,5 +37,7 @@ export declare function updateTraceContextExportMetadata(trace: BaseTraceContext
|
|
|
34
37
|
}): void;
|
|
35
38
|
export declare function resolveTraceContextOptions(config?: TraceConfig): CreateTraceContextOptions;
|
|
36
39
|
export declare function getTraceRecorder(trace: BaseTraceContext): TraceRecorder | null;
|
|
40
|
+
/** Internal, read-only process counters; no reset can re-arm a warning. */
|
|
41
|
+
export declare function getDroppedOTLPSpanCount(reason: string): number;
|
|
37
42
|
export declare function createTraceContext(options?: CreateTraceContextOptions): TraceContext;
|
|
38
43
|
export {};
|
package/dist/runtime/trace.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { sanitizeSpanNameForOutput } from "../trace-sanitization.js";
|
|
3
|
+
import { diagnosticStructuredRedactor, redactDiagnosticAttributeKey, copyDiagnosticAttributeTypes, redactedKeyAllocator, isRedactedKey, redactCriticalDiagnosticText, diagnosticAttributeRedactor, REDACTION_FAILED, redactDiagnosticText, } from "./diagnostic-redactor.js";
|
|
2
4
|
import { exportSpansOTLP } from "./otlp.js";
|
|
5
|
+
import { REDACTED_QUERY_VALUE } from "./request-options.js";
|
|
6
|
+
const TRACE_RESOURCE_ATTRIBUTE_SANITIZER = Symbol.for("@apifuse/provider-sdk/runtime/trace-resource-attribute-sanitizer");
|
|
3
7
|
export const TRACE_RECORDER = Symbol.for("@apifuse/provider-sdk/runtime/trace-recorder");
|
|
4
8
|
const TRACE_EXPORT_METADATA = Symbol.for("@apifuse/provider-sdk/runtime/trace-export-metadata");
|
|
5
9
|
function assertValidTraceId(traceId) {
|
|
@@ -32,23 +36,76 @@ export function resolveTraceContextOptions(config) {
|
|
|
32
36
|
exportOptions: buildOTLPExportOptions(config),
|
|
33
37
|
};
|
|
34
38
|
}
|
|
35
|
-
function normalizeAttributeValue(value) {
|
|
36
|
-
if (typeof value === "
|
|
37
|
-
|
|
39
|
+
function normalizeAttributeValue(value, redact, retainBigints = false) {
|
|
40
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
41
|
+
// Typed columns are contracts: unlike string tokens, number/boolean/bigint
|
|
42
|
+
// values only consult the registry at >=8 characters in string form.
|
|
43
|
+
const text = String(value);
|
|
44
|
+
if (text.length < 8)
|
|
45
|
+
return value;
|
|
46
|
+
const redacted = redactDiagnosticText(text, diagnosticStructuredRedactor(redact));
|
|
47
|
+
return redacted === text ? value : redacted;
|
|
48
|
+
}
|
|
49
|
+
if (typeof value === "bigint") {
|
|
50
|
+
// Bigints are not valid OTLP attribute primitives, so retain their prior
|
|
51
|
+
// string normalization while still checking their diagnostic form.
|
|
52
|
+
const text = String(value);
|
|
53
|
+
if (text.length < 8)
|
|
54
|
+
return retainBigints ? value : text;
|
|
55
|
+
const redacted = redactDiagnosticText(text, diagnosticStructuredRedactor(redact));
|
|
56
|
+
return retainBigints && redacted === text ? value : redacted;
|
|
38
57
|
}
|
|
39
58
|
if (value === null || value === undefined) {
|
|
40
59
|
return undefined;
|
|
41
60
|
}
|
|
42
|
-
return String(value);
|
|
61
|
+
return redactDiagnosticText(String(value), redact);
|
|
43
62
|
}
|
|
44
|
-
function normalizeAttributes(attributes) {
|
|
63
|
+
function normalizeAttributes(attributes, redact, retainBigints = false) {
|
|
45
64
|
if (!attributes) {
|
|
46
65
|
return {};
|
|
47
66
|
}
|
|
67
|
+
const nextKey = redactedKeyAllocator(Object.keys(attributes));
|
|
48
68
|
const normalizedEntries = Object.entries(attributes)
|
|
49
|
-
.map(([key, value]) =>
|
|
69
|
+
.map(([key, value]) => {
|
|
70
|
+
const redactedKey = isRedactedKey(key) ? key : redactDiagnosticAttributeKey(key, redact);
|
|
71
|
+
const keyChanged = redactedKey !== key;
|
|
72
|
+
const normalizedKey = keyChanged ? nextKey() : key;
|
|
73
|
+
// Once a key changes, its original sensitivity classification is no
|
|
74
|
+
// longer available to later output sanitizers. Suppress the value here.
|
|
75
|
+
const normalizedValue = keyChanged
|
|
76
|
+
? redactedKey === REDACTION_FAILED
|
|
77
|
+
? REDACTION_FAILED
|
|
78
|
+
: REDACTED_QUERY_VALUE
|
|
79
|
+
: normalizeAttributeValue(value, diagnosticAttributeRedactor(key, redact), retainBigints);
|
|
80
|
+
return [normalizedKey, normalizedValue];
|
|
81
|
+
})
|
|
50
82
|
.filter((entry) => entry[1] !== undefined);
|
|
51
|
-
return Object.fromEntries(normalizedEntries);
|
|
83
|
+
return copyDiagnosticAttributeTypes(attributes, Object.fromEntries(normalizedEntries));
|
|
84
|
+
}
|
|
85
|
+
function prepareResourceAttributesForExport(attributes, redact, sanitize) {
|
|
86
|
+
if (!attributes)
|
|
87
|
+
return undefined;
|
|
88
|
+
if (sanitize) {
|
|
89
|
+
const sanitized = sanitize({ ...attributes });
|
|
90
|
+
if (!sanitized || typeof sanitized !== "object") {
|
|
91
|
+
throw new Error("resource attribute sanitizer returned no attributes");
|
|
92
|
+
}
|
|
93
|
+
return sanitized;
|
|
94
|
+
}
|
|
95
|
+
const nextKey = redactedKeyAllocator(Object.keys(attributes));
|
|
96
|
+
return Object.fromEntries(Object.entries(attributes).map(([key, value]) => {
|
|
97
|
+
const redactedKey = isRedactedKey(key) ? key : redactDiagnosticAttributeKey(key, redact);
|
|
98
|
+
const keyChanged = redactedKey !== key;
|
|
99
|
+
const sanitizedKey = keyChanged ? nextKey() : sanitizeSpanNameForOutput(key);
|
|
100
|
+
return [
|
|
101
|
+
sanitizedKey,
|
|
102
|
+
keyChanged
|
|
103
|
+
? redactedKey === REDACTION_FAILED
|
|
104
|
+
? REDACTION_FAILED
|
|
105
|
+
: REDACTED_QUERY_VALUE
|
|
106
|
+
: sanitizeSpanNameForOutput(value, diagnosticAttributeRedactor(key, redact)),
|
|
107
|
+
];
|
|
108
|
+
}));
|
|
52
109
|
}
|
|
53
110
|
function insertCompletedSpan(completed, entry, maxSpans) {
|
|
54
111
|
const insertAt = completed.findIndex((existingEntry) => existingEntry.sequence > entry.sequence);
|
|
@@ -64,7 +121,10 @@ function insertCompletedSpan(completed, entry, maxSpans) {
|
|
|
64
121
|
}
|
|
65
122
|
/** Hands the hook a copy whose attributes are detached from the recorded span; a hook that returns nothing fails closed. */
|
|
66
123
|
function prepareSpanForExport(span, sanitize) {
|
|
67
|
-
const copy = {
|
|
124
|
+
const copy = {
|
|
125
|
+
...span,
|
|
126
|
+
attributes: copyDiagnosticAttributeTypes(span.attributes, { ...span.attributes }),
|
|
127
|
+
};
|
|
68
128
|
if (!sanitize)
|
|
69
129
|
return copy;
|
|
70
130
|
const sanitized = sanitize(copy);
|
|
@@ -76,6 +136,24 @@ function prepareSpanForExport(span, sanitize) {
|
|
|
76
136
|
export function getTraceRecorder(trace) {
|
|
77
137
|
return trace[TRACE_RECORDER] ?? null;
|
|
78
138
|
}
|
|
139
|
+
const droppedOTLPSpans = new Map();
|
|
140
|
+
/** Internal, read-only process counters; no reset can re-arm a warning. */
|
|
141
|
+
export function getDroppedOTLPSpanCount(reason) {
|
|
142
|
+
return droppedOTLPSpans.get(reason) ?? 0;
|
|
143
|
+
}
|
|
144
|
+
function warnDroppedOTLPSpans(reason, count) {
|
|
145
|
+
const previous = getDroppedOTLPSpanCount(reason);
|
|
146
|
+
const total = previous + count;
|
|
147
|
+
droppedOTLPSpans.set(reason, total);
|
|
148
|
+
if (previous !== 0)
|
|
149
|
+
return;
|
|
150
|
+
try {
|
|
151
|
+
console.warn(`[apifuse] OTLP export skipped; reason=${reason}; dropped_spans=${total}`);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Warning sinks are best-effort. The counter/latch survives a failed sink.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
79
157
|
export function createTraceContext(options = {}) {
|
|
80
158
|
if (options.traceId !== undefined)
|
|
81
159
|
assertValidTraceId(options.traceId);
|
|
@@ -86,9 +164,11 @@ export function createTraceContext(options = {}) {
|
|
|
86
164
|
// Export configuration (which can carry collector credentials) stays in this closure;
|
|
87
165
|
// the context object handed to provider code never exposes it.
|
|
88
166
|
const exportOptions = options.exportOptions;
|
|
89
|
-
const
|
|
90
|
-
|
|
167
|
+
const resourceAttributeOptions = options.resourceAttributes;
|
|
168
|
+
const exportResourceAttributes = resourceAttributeOptions
|
|
169
|
+
? { ...resourceAttributeOptions }
|
|
91
170
|
: undefined;
|
|
171
|
+
const exportResourceAttributeSanitizer = resourceAttributeOptions?.[TRACE_RESOURCE_ATTRIBUTE_SANITIZER];
|
|
92
172
|
// One trace id per context so every export batch of this request shares it and
|
|
93
173
|
// two processes can never mint the same id.
|
|
94
174
|
let exportTraceId = options.traceId ?? crypto.randomUUID().replace(/-/g, "");
|
|
@@ -109,46 +189,61 @@ export function createTraceContext(options = {}) {
|
|
|
109
189
|
return;
|
|
110
190
|
// Sanitization runs off the request path; a faulty sanitizer drops the batch, never the request.
|
|
111
191
|
let spans;
|
|
192
|
+
let resourceAttributes;
|
|
112
193
|
try {
|
|
113
194
|
spans = pending.map((entry) => prepareSpanForExport(entry.span, options.sanitizeSpanForExport));
|
|
195
|
+
resourceAttributes = prepareResourceAttributesForExport(exportResourceAttributes, options.redact, exportResourceAttributeSanitizer);
|
|
114
196
|
}
|
|
115
197
|
catch {
|
|
116
|
-
|
|
198
|
+
try {
|
|
199
|
+
console.warn("[apifuse] OTLP export skipped; span sanitization failed.");
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// A broken diagnostic sink must not escape this detached callback.
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// A matching trace ID cannot be replaced with non-hex text on the wire. Emit less.
|
|
207
|
+
if (redactCriticalDiagnosticText(exportTraceId, options.redact) !== exportTraceId) {
|
|
208
|
+
warnDroppedOTLPSpans("unverifiable_trace_id", pending.length);
|
|
117
209
|
return;
|
|
118
210
|
}
|
|
119
|
-
void exportSpansOTLP(spans, exportOptions,
|
|
211
|
+
void exportSpansOTLP(spans, exportOptions, resourceAttributes, exportTraceId);
|
|
120
212
|
});
|
|
121
213
|
};
|
|
122
214
|
const recorder = {
|
|
123
215
|
async runSpan(name, fn, spanOptions = {}) {
|
|
124
216
|
const pendingSpan = {
|
|
125
217
|
id: crypto.randomUUID(),
|
|
126
|
-
name,
|
|
218
|
+
name: redactCriticalDiagnosticText(name, options.redact),
|
|
127
219
|
startedAt: Date.now(),
|
|
128
220
|
parentId: activeSpanStorage.getStore()?.id,
|
|
129
221
|
sequence: sequence++,
|
|
130
|
-
attributes: normalizeAttributes(spanOptions.attributes),
|
|
222
|
+
attributes: normalizeAttributes(spanOptions.attributes, options.redact, true),
|
|
131
223
|
};
|
|
132
224
|
const finalize = (status, extraAttributes, error) => {
|
|
133
225
|
const endedAt = Date.now();
|
|
134
226
|
const duration = endedAt - pendingSpan.startedAt;
|
|
135
227
|
const attributes = {
|
|
136
228
|
...pendingSpan.attributes,
|
|
137
|
-
...
|
|
229
|
+
...extraAttributes,
|
|
138
230
|
};
|
|
139
231
|
if (attributes.duration_ms === undefined) {
|
|
140
232
|
attributes.duration_ms = duration;
|
|
141
233
|
}
|
|
142
234
|
const span = {
|
|
143
|
-
id: pendingSpan.id,
|
|
144
|
-
|
|
235
|
+
id: redactCriticalDiagnosticText(pendingSpan.id, options.redact),
|
|
236
|
+
// Recheck at recording: harvest and live env reads may follow span start.
|
|
237
|
+
name: redactCriticalDiagnosticText(pendingSpan.name, options.redact),
|
|
145
238
|
startedAt: pendingSpan.startedAt,
|
|
146
239
|
endedAt,
|
|
147
240
|
duration_ms: duration,
|
|
148
241
|
status,
|
|
149
|
-
attributes,
|
|
150
|
-
...(error ? { error } : {}),
|
|
151
|
-
...(pendingSpan.parentId
|
|
242
|
+
attributes: normalizeAttributes(attributes, options.redact),
|
|
243
|
+
...(error ? { error: redactDiagnosticText(error, options.redact) } : {}),
|
|
244
|
+
...(pendingSpan.parentId
|
|
245
|
+
? { parentId: redactCriticalDiagnosticText(pendingSpan.parentId, options.redact) }
|
|
246
|
+
: {}),
|
|
152
247
|
};
|
|
153
248
|
insertCompletedSpan(completed, { sequence: pendingSpan.sequence, span, exported: false }, maxSpans);
|
|
154
249
|
options.onSpan?.(span);
|
package/dist/schema.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export declare function safeParseSchemaSync<TSchema extends SchemaLike>(schema:
|
|
|
13
13
|
export declare const APIFUSE_SENSITIVE_META_KEY = "x-apifuse-sensitive";
|
|
14
14
|
export declare const APIFUSE_SENSITIVE_KIND_META_KEY = "x-apifuse-sensitive-kind";
|
|
15
15
|
export declare const APIFUSE_DESCRIPTION_KEY_META_KEY = "x-apifuse-description-key";
|
|
16
|
+
export declare const APIFUSE_CONTENT_TRUST_META_KEY = "x-apifuse-content-trust";
|
|
17
|
+
export declare const APIFUSE_CONTENT_PROVENANCE_META_KEY = "x-apifuse-content-provenance";
|
|
16
18
|
export declare const APIFUSE_REDACTION_MARKER = "<redacted>";
|
|
17
19
|
export type SensitivePathSegment = string | "*";
|
|
18
20
|
export type SensitivePath = readonly SensitivePathSegment[];
|
|
@@ -20,6 +22,8 @@ export type SensitiveFieldKind = "api_key" | "authorization" | "cookie" | "crede
|
|
|
20
22
|
export interface SensitiveFieldOptions {
|
|
21
23
|
/**
|
|
22
24
|
* Mark this schema as sensitive. Defaults to true for the helper presets.
|
|
25
|
+
* An explicit `false` emits `x-apifuse-sensitive: false` (reviewed public
|
|
26
|
+
* data, never redacted) and drops any sensitivity kind.
|
|
23
27
|
*/
|
|
24
28
|
sensitive?: boolean;
|
|
25
29
|
/**
|
|
@@ -32,6 +36,13 @@ export interface SensitiveFieldOptions {
|
|
|
32
36
|
description?: string;
|
|
33
37
|
}
|
|
34
38
|
export declare function describeKey<TSchema extends ZodType>(schema: TSchema, key: ProviderLocaleKey | string): TSchema;
|
|
39
|
+
/**
|
|
40
|
+
* Mark an output field as externally authored text (listing bodies, reviews,
|
|
41
|
+
* posts) that the provider relays verbatim. Sets both content-trust JSON Schema
|
|
42
|
+
* meta keys on the field node so the platform can enforce the boundary when it
|
|
43
|
+
* assembles tool output; validation and the parsed value are unchanged.
|
|
44
|
+
*/
|
|
45
|
+
export declare function untrustedContent<TSchema extends ZodType>(schema: TSchema): TSchema;
|
|
35
46
|
declare module "zod" {
|
|
36
47
|
interface ZodType {
|
|
37
48
|
describeKey(key: ProviderLocaleKey | string): this;
|
|
@@ -39,6 +50,15 @@ declare module "zod" {
|
|
|
39
50
|
}
|
|
40
51
|
export declare function field<TSchema extends ZodType>(schema: TSchema, options?: SensitiveFieldOptions): TSchema;
|
|
41
52
|
export declare function sensitive<TSchema extends ZodType>(schema: TSchema, kind?: SensitiveFieldKind): TSchema;
|
|
53
|
+
/**
|
|
54
|
+
* Declare a field as reviewed public data (business, facility, product, or
|
|
55
|
+
* place names and contacts) so a key-based privacy classifier hit counts as
|
|
56
|
+
* declared instead of undeclared. Emits `x-apifuse-sensitive: false` on the
|
|
57
|
+
* JSON Schema leaf; nothing is redacted. Use `sensitive()` for anything that
|
|
58
|
+
* identifies a person. Apply it to the leaf, before `.optional()` or
|
|
59
|
+
* `.nullable()`; wrapping a `sensitive()` declaration throws at definition time.
|
|
60
|
+
*/
|
|
61
|
+
export declare function publicField<TSchema extends ZodType>(schema: TSchema): TSchema;
|
|
42
62
|
export declare const fields: {
|
|
43
63
|
readonly apiKey: (options?: {
|
|
44
64
|
description?: string;
|
package/dist/schema.js
CHANGED
|
@@ -41,6 +41,8 @@ export function safeParseSchemaSync(schema, value, fieldPath) {
|
|
|
41
41
|
export const APIFUSE_SENSITIVE_META_KEY = "x-apifuse-sensitive";
|
|
42
42
|
export const APIFUSE_SENSITIVE_KIND_META_KEY = "x-apifuse-sensitive-kind";
|
|
43
43
|
export const APIFUSE_DESCRIPTION_KEY_META_KEY = "x-apifuse-description-key";
|
|
44
|
+
export const APIFUSE_CONTENT_TRUST_META_KEY = "x-apifuse-content-trust";
|
|
45
|
+
export const APIFUSE_CONTENT_PROVENANCE_META_KEY = "x-apifuse-content-provenance";
|
|
44
46
|
export const APIFUSE_REDACTION_MARKER = "<redacted>";
|
|
45
47
|
export function describeKey(schema, key) {
|
|
46
48
|
const descriptionKey = providerLocaleKey(key);
|
|
@@ -50,6 +52,20 @@ export function describeKey(schema, key) {
|
|
|
50
52
|
[APIFUSE_DESCRIPTION_KEY_META_KEY]: descriptionKey,
|
|
51
53
|
});
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Mark an output field as externally authored text (listing bodies, reviews,
|
|
57
|
+
* posts) that the provider relays verbatim. Sets both content-trust JSON Schema
|
|
58
|
+
* meta keys on the field node so the platform can enforce the boundary when it
|
|
59
|
+
* assembles tool output; validation and the parsed value are unchanged.
|
|
60
|
+
*/
|
|
61
|
+
export function untrustedContent(schema) {
|
|
62
|
+
const metadata = schema.meta() ?? {};
|
|
63
|
+
return schema.meta({
|
|
64
|
+
...metadata,
|
|
65
|
+
[APIFUSE_CONTENT_TRUST_META_KEY]: "untrusted",
|
|
66
|
+
[APIFUSE_CONTENT_PROVENANCE_META_KEY]: "external",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
53
69
|
const describeKeyMethod = function (key) {
|
|
54
70
|
return describeKey(this, key);
|
|
55
71
|
};
|
|
@@ -97,15 +113,41 @@ export function field(schema, options = {}) {
|
|
|
97
113
|
? schema.describe(options.description)
|
|
98
114
|
: schema;
|
|
99
115
|
const metadata = described.meta() ?? {};
|
|
116
|
+
const isSensitive = options.sensitive ?? true;
|
|
117
|
+
// A public declaration only rewrites the meta of the node it receives;
|
|
118
|
+
// z.toJSONSchema folds that over the inner leaf, so `false` on a wrapper
|
|
119
|
+
// around a sensitive() leaf would publish `false` next to the leaf's kind
|
|
120
|
+
// while collectSensitivePaths() still redacts. Refuse the contradiction.
|
|
121
|
+
if (!isSensitive && wrapsSensitiveDeclaration(described)) {
|
|
122
|
+
throw new TypeError("publicField()/field({ sensitive: false }) wraps a sensitive() declaration; apply it to the leaf, before .optional(), .nullable(), .default(), .pipe(), z.lazy() or similar wrappers.");
|
|
123
|
+
}
|
|
124
|
+
// Zod merges meta with the parent chain, so an inherited kind can only be
|
|
125
|
+
// cleared by writing undefined over it (dropped from JSON Schema output).
|
|
126
|
+
const kind = isSensitive
|
|
127
|
+
? (options.kind ?? Reflect.get(metadata, APIFUSE_SENSITIVE_KIND_META_KEY))
|
|
128
|
+
: undefined;
|
|
100
129
|
return described.meta({
|
|
101
130
|
...metadata,
|
|
102
|
-
|
|
103
|
-
...(
|
|
131
|
+
[APIFUSE_SENSITIVE_META_KEY]: isSensitive,
|
|
132
|
+
...(kind !== undefined || APIFUSE_SENSITIVE_KIND_META_KEY in metadata
|
|
133
|
+
? { [APIFUSE_SENSITIVE_KIND_META_KEY]: kind }
|
|
134
|
+
: {}),
|
|
104
135
|
});
|
|
105
136
|
}
|
|
106
137
|
export function sensitive(schema, kind) {
|
|
107
138
|
return field(schema, { sensitive: true, kind });
|
|
108
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Declare a field as reviewed public data (business, facility, product, or
|
|
142
|
+
* place names and contacts) so a key-based privacy classifier hit counts as
|
|
143
|
+
* declared instead of undeclared. Emits `x-apifuse-sensitive: false` on the
|
|
144
|
+
* JSON Schema leaf; nothing is redacted. Use `sensitive()` for anything that
|
|
145
|
+
* identifies a person. Apply it to the leaf, before `.optional()` or
|
|
146
|
+
* `.nullable()`; wrapping a `sensitive()` declaration throws at definition time.
|
|
147
|
+
*/
|
|
148
|
+
export function publicField(schema) {
|
|
149
|
+
return field(schema, { sensitive: false });
|
|
150
|
+
}
|
|
109
151
|
function sensitiveString(kind, description, options = {}) {
|
|
110
152
|
const schema = options.minLength === undefined ? z.string() : z.string().min(options.minLength);
|
|
111
153
|
return field(schema, {
|
|
@@ -222,6 +264,34 @@ function readZodMetadata(schema) {
|
|
|
222
264
|
const metadata = maybeMeta.call(schema);
|
|
223
265
|
return metadata && typeof metadata === "object" ? metadata : undefined;
|
|
224
266
|
}
|
|
267
|
+
// Same-path wrappers (optional, nullable, default, catch, readonly, pipe,
|
|
268
|
+
// lazy, ...) share the JSON Schema leaf with the schema they wrap.
|
|
269
|
+
function wrapsSensitiveDeclaration(schema, seen = new Set()) {
|
|
270
|
+
const def = readZodDef(schema);
|
|
271
|
+
if (!def || seen.has(schema))
|
|
272
|
+
return false;
|
|
273
|
+
seen.add(schema);
|
|
274
|
+
return sameLeafChildren(def).some((child) => isSensitiveSchema(child) || wrapsSensitiveDeclaration(child, seen));
|
|
275
|
+
}
|
|
276
|
+
function sameLeafChildren(def) {
|
|
277
|
+
switch (Reflect.get(def, "type")) {
|
|
278
|
+
case "pipe":
|
|
279
|
+
return [Reflect.get(def, "in"), Reflect.get(def, "out")];
|
|
280
|
+
case "lazy": {
|
|
281
|
+
// A forward-reference getter can throw before its target is
|
|
282
|
+
// initialised; treat that as no declaration rather than failing.
|
|
283
|
+
const getter = Reflect.get(def, "getter");
|
|
284
|
+
try {
|
|
285
|
+
return typeof getter === "function" ? [getter()] : [];
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
default:
|
|
292
|
+
return [Reflect.get(def, "innerType")];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
225
295
|
function readZodDef(schema) {
|
|
226
296
|
if (!schema || typeof schema !== "object")
|
|
227
297
|
return undefined;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type { ProxyCacheStatus, ProxyProtocol, ProxyUserAgentSource, ProxyVendorName, SmartproxyAllocatorBodyClass, } from "../config/loader.js";
|
|
2
2
|
export type { ProxyTelemetryHeaderPayload, ProxyHash, ProxyTelemetryLogPayload, ProxyTelemetryResolvedPayload, ProxyTelemetryUnresolvedPayload, } from "../runtime/proxy-telemetry.js";
|
|
3
3
|
export { RequestTelemetry, closedEnum, type ClosedEnum, type GatewayIngestible, type RequestTelemetryLogPayload, type SpanIndex, type TelemetryContributor, type TelemetryKey, type TenantNeutral, } from "../runtime/request-telemetry.js";
|
|
4
|
+
export { ResolverTelemetryCollector, type ResolverAttemptSample, type ResolverCacheReadTelemetryEvent, type ResolverCacheWriteTelemetryEvent, type ResolverFailoverTelemetryEvent, type ResolverIdentityTelemetryEvent, type ResolverOutcomeTelemetryEvent, type ResolverTelemetryAttemptOutcome, type ResolverTelemetryCacheStatus, type ResolverTelemetryCacheWriteReason, type ResolverTelemetryErrorClass, type ResolverTelemetryHeaderPayload, type ResolverTelemetryIdentitySource, type ResolverTelemetryLogPayload, type ResolverTelemetryOutcome, type ResolverTelemetryPhase, type ResolverTelemetrySink, type ResolverVendorAttemptTelemetryEvent, } from "../runtime/resolver-telemetry.js";
|
|
5
|
+
export type { ResolverVendorUnavailableReason } from "../runtime/resolver-vendors/types.js";
|
|
4
6
|
export type { Span, TraceContext } from "../runtime/trace.js";
|
|
5
7
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ErrorObservabilityDetails, type ProviderServerCloseOptions, type ProviderServerHandle, type ProviderErrorCauseFrame, type ProviderServerLogEvent, type ProviderServerLogger, type ProviderServerOperationExecutor, type ProviderServerOperationExecutorInput, type ProviderServerOptions, type ProviderServerStatefulForwardEnvelope, type ServeOptions, serve, } from "./serve.js";
|
|
6
8
|
export type { ProviderErrorObservability } from "../errors.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { RequestTelemetry, closedEnum, } from "../runtime/request-telemetry.js";
|
|
2
|
+
export { ResolverTelemetryCollector, } from "../runtime/resolver-telemetry.js";
|
|
2
3
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serve, } from "./serve.js";
|
|
3
4
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
4
5
|
export { resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { collectDiagnosticSensitiveValues, SELF_TEST_SENSITIVE_SOURCE_KINDS, } from "./sensitive-values.js";
|
|
2
2
|
export const SELF_TEST_REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
3
3
|
/** Maximum length of any string echoed in a self-test response. */
|
|
4
4
|
export const SELF_TEST_MAX_TEXT_LENGTH = 300;
|
|
@@ -16,37 +16,12 @@ const HEADER_SHAPED_SECRETS = [
|
|
|
16
16
|
* credential inputs.
|
|
17
17
|
*/
|
|
18
18
|
export function collectSelfTestSensitiveValues(provider, options = {}) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
envNames.add(secret.name);
|
|
26
|
-
}
|
|
27
|
-
const healthProbe = provider.healthProbe ?? provider.healthMonitor;
|
|
28
|
-
for (const name of healthProbe?.requiredSecrets ?? []) {
|
|
29
|
-
envNames.add(name);
|
|
30
|
-
}
|
|
31
|
-
for (const name of Object.values(healthProbe?.credentialInputs ?? {})) {
|
|
32
|
-
envNames.add(name);
|
|
33
|
-
}
|
|
34
|
-
const values = new Set();
|
|
35
|
-
for (const name of envNames) {
|
|
36
|
-
const value = env[name];
|
|
37
|
-
if (typeof value === "string" && value.length >= MIN_SENSITIVE_VALUE_LENGTH) {
|
|
38
|
-
values.add(value);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
for (const value of Object.values(options.credentialInputs ?? {})) {
|
|
42
|
-
if (value.length >= MIN_SENSITIVE_VALUE_LENGTH) {
|
|
43
|
-
values.add(value);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return [...values];
|
|
47
|
-
}
|
|
48
|
-
function escapeRegExp(value) {
|
|
49
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
return collectDiagnosticSensitiveValues(provider, {
|
|
20
|
+
...options,
|
|
21
|
+
sourceKinds: SELF_TEST_SENSITIVE_SOURCE_KINDS,
|
|
22
|
+
minimumLength: MIN_SENSITIVE_VALUE_LENGTH,
|
|
23
|
+
includeResolvedEnvVariants: false,
|
|
24
|
+
});
|
|
50
25
|
}
|
|
51
26
|
/**
|
|
52
27
|
* Scrubs known secret values and header-shaped credentials from a string and
|
|
@@ -58,7 +33,7 @@ export function redactSelfTestText(text, sensitiveValues, maxLength = SELF_TEST_
|
|
|
58
33
|
for (const value of sensitiveValues) {
|
|
59
34
|
if (value.length < MIN_SENSITIVE_VALUE_LENGTH)
|
|
60
35
|
continue;
|
|
61
|
-
redacted = redacted.
|
|
36
|
+
redacted = redacted.replaceAll(value, SELF_TEST_REDACTED_PLACEHOLDER);
|
|
62
37
|
}
|
|
63
38
|
for (const pattern of HEADER_SHAPED_SECRETS) {
|
|
64
39
|
redacted = redacted.replace(pattern, (_match, prefix) => `${prefix}${SELF_TEST_REDACTED_PLACEHOLDER}`);
|
|
@@ -88,6 +88,10 @@ export type SelfTestAuthFlowInvoke = (args: {
|
|
|
88
88
|
externalRef?: string;
|
|
89
89
|
input?: Record<string, unknown>;
|
|
90
90
|
context?: Record<string, unknown>;
|
|
91
|
+
/** Opaque engine state from the previous turn (`engine` in the auth response), sent verbatim. */
|
|
92
|
+
engine?: {
|
|
93
|
+
egressLease: string;
|
|
94
|
+
};
|
|
91
95
|
signal?: AbortSignal;
|
|
92
96
|
}) => Promise<{
|
|
93
97
|
status: number;
|
package/dist/server/self-test.js
CHANGED
|
@@ -187,17 +187,21 @@ function logSelfTestCancellation(provider, options, requestId, selected, signal,
|
|
|
187
187
|
}
|
|
188
188
|
/** Binds the self-test auth-flow driver to a tenant app's /auth pipeline in-process. */
|
|
189
189
|
export function createSelfTestAuthFlowInvoke(app) {
|
|
190
|
-
return async ({ route, requestId, flowId, connectionId, externalRef, input, context, signal, }) => {
|
|
190
|
+
return async ({ route, requestId, flowId, connectionId, externalRef, input, context, engine, signal, }) => {
|
|
191
191
|
const response = await app.request(`/auth/${route}`, {
|
|
192
192
|
method: "POST",
|
|
193
193
|
headers: { "content-type": "application/json" },
|
|
194
194
|
body: JSON.stringify({
|
|
195
195
|
requestId,
|
|
196
196
|
flowId,
|
|
197
|
+
// Engine ceremony leases are scoped to a tenant; the self-test has no
|
|
198
|
+
// customer tenant, so it presents a fixed one that never collides.
|
|
199
|
+
tenantId: "self-test",
|
|
197
200
|
...(connectionId ? { connectionId } : {}),
|
|
198
201
|
...(externalRef ? { externalRef } : {}),
|
|
199
202
|
...(input ? { input } : {}),
|
|
200
203
|
...(context ? { context } : {}),
|
|
204
|
+
...(engine ? { engine } : {}),
|
|
201
205
|
}),
|
|
202
206
|
...(signal ? { signal } : {}),
|
|
203
207
|
});
|
|
@@ -329,6 +333,7 @@ function parseAuthFlowResponse(result) {
|
|
|
329
333
|
};
|
|
330
334
|
}
|
|
331
335
|
const contextPatch = objectProperty(result.body, "contextPatch");
|
|
336
|
+
const egressLease = objectProperty(objectProperty(result.body, "engine"), "egressLease");
|
|
332
337
|
return {
|
|
333
338
|
ok: true,
|
|
334
339
|
turn: {
|
|
@@ -339,6 +344,7 @@ function parseAuthFlowResponse(result) {
|
|
|
339
344
|
...(contextPatch && typeof contextPatch === "object" && !Array.isArray(contextPatch)
|
|
340
345
|
? { contextPatch: contextPatch }
|
|
341
346
|
: {}),
|
|
347
|
+
...(typeof egressLease === "string" && egressLease ? { engine: { egressLease } } : {}),
|
|
342
348
|
};
|
|
343
349
|
}
|
|
344
350
|
function applyAuthFlowContextPatch(base, patch) {
|
|
@@ -499,6 +505,9 @@ async function materializeFlowCredential(execution, inputs, options = {}) {
|
|
|
499
505
|
...(options.externalRef ? { externalRef: options.externalRef } : {}),
|
|
500
506
|
input: submitInputs,
|
|
501
507
|
...(Object.keys(flowContext).length > 0 ? { context: flowContext } : {}),
|
|
508
|
+
// The ceremony egress lease is engine state, not flow context: carry it the
|
|
509
|
+
// way the gateway does so the continue turn stays on the start turn's egress.
|
|
510
|
+
...(started.engine ? { engine: started.engine } : {}),
|
|
502
511
|
...(options.signal ? { signal: options.signal } : {}),
|
|
503
512
|
}));
|
|
504
513
|
if (!continued.ok) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ProviderDefinition } from "../types.js";
|
|
2
|
+
export declare const SELF_TEST_SENSITIVE_SOURCE_KINDS: readonly ["selfTestMasterSecrets", "providerSecrets", "healthProbeSecrets", "requestCredentials"];
|
|
3
|
+
/** Explicit source allowlist: no environment-name or payload-shape secret sweep. */
|
|
4
|
+
export declare const DIAGNOSTIC_SENSITIVE_SOURCE_KINDS: readonly ["selfTestMasterSecrets", "providerSecrets", "healthProbeSecrets", "requestCredentials", "engineProxyCredentials", "engineSolverKeys", "engineCeremonyLeaseCredentials", "choiceMasterSecret", "ocrCredentials", "sttCredentials", "cdpCredentials", "statefulForwardingSecret", "redisCredentials", "otlpHeaders", "cacheKeyPepper", "sensitiveParams"];
|
|
5
|
+
export type DiagnosticSensitiveSourceKind = (typeof DIAGNOSTIC_SENSITIVE_SOURCE_KINDS)[number];
|
|
6
|
+
/**
|
|
7
|
+
* Startup inventory; request-scoped readers additionally register live values on access.
|
|
8
|
+
*/
|
|
9
|
+
export declare function collectStaticDiagnosticSensitiveValues(provider: ProviderDefinition, options?: {
|
|
10
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
11
|
+
statefulForwardingSecret?: string;
|
|
12
|
+
}): string[];
|
|
13
|
+
/** Generalised self-test collector, also used to seed and enrich ordinary request scopes. */
|
|
14
|
+
export declare function collectDiagnosticSensitiveValues(provider: ProviderDefinition, options?: {
|
|
15
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
16
|
+
credentialInputs?: Readonly<Record<string, unknown>>;
|
|
17
|
+
connectionSecrets?: Readonly<Record<string, string | undefined>>;
|
|
18
|
+
sensitiveParams?: readonly string[];
|
|
19
|
+
statefulForwardingSecret?: string;
|
|
20
|
+
sourceKinds?: readonly DiagnosticSensitiveSourceKind[];
|
|
21
|
+
minimumLength?: number;
|
|
22
|
+
/** Preserve the legacy self-test response collector when false. */
|
|
23
|
+
includeResolvedEnvVariants?: boolean;
|
|
24
|
+
}): string[];
|
|
25
|
+
/** Derive the live-read allowlist from the same collector as the startup inventory. */
|
|
26
|
+
export declare function createDiagnosticEnvObserver(provider: ProviderDefinition, register: (values: readonly string[]) => void, has?: (value: string) => boolean): (name: string, value: string) => void;
|