@apifuse/provider-sdk 2.2.0-beta.59 → 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 +16 -0
- package/CHANGELOG.md +4 -0
- package/bin/apifuse-dev.ts +2 -1
- package/bin/apifuse-perf.ts +41 -4
- package/bin/apifuse-record.ts +3 -2
- package/dist/config/loader.js +13 -12
- package/dist/engine.js +3 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/lint.js +36 -15
- package/dist/provider.d.ts +1 -1
- package/dist/provider.js +1 -1
- package/dist/runtime/browser.js +2 -1
- package/dist/runtime/cache.js +3 -2
- 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 +2 -0
- package/dist/runtime/egress-lease.js +4 -1
- package/dist/runtime/env.js +2 -1
- 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/request-options.d.ts +7 -0
- package/dist/runtime/request-options.js +62 -22
- package/dist/runtime/resolver-vendors/browser.js +0 -1
- package/dist/runtime/resolver.js +3 -2
- 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 +11 -0
- package/dist/schema.js +56 -2
- package/dist/server/self-test-redaction.js +8 -33
- package/dist/server/sensitive-values.d.ts +26 -0
- package/dist/server/sensitive-values.js +131 -0
- package/dist/server/serve-implementation.js +219 -78
- package/dist/server/trace-output.d.ts +2 -1
- package/dist/server/trace-output.js +46 -14
- package/dist/trace-sanitization.d.ts +4 -3
- package/dist/trace-sanitization.js +45 -22
- package/package.json +2 -1
- package/src/config/loader.ts +13 -12
- package/src/engine.ts +3 -2
- package/src/index.ts +2 -0
- package/src/lint.ts +42 -16
- package/src/provider.ts +1 -0
- package/src/runtime/browser.ts +2 -1
- package/src/runtime/cache.ts +3 -2
- 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 +6 -1
- package/src/runtime/env.ts +2 -1
- 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/request-options.ts +76 -28
- package/src/runtime/resolver-vendors/browser.ts +0 -1
- package/src/runtime/resolver.ts +3 -2
- package/src/runtime/stt.ts +3 -2
- package/src/runtime/trace.ts +168 -26
- package/src/schema.ts +63 -2
- package/src/server/self-test-redaction.ts +10 -40
- package/src/server/sensitive-values.ts +200 -0
- package/src/server/serve-implementation.ts +301 -96
- package/src/server/trace-output.ts +77 -17
- package/src/trace-sanitization.ts +70 -23
package/AUTHORING.md
CHANGED
|
@@ -226,6 +226,22 @@ const utcInput = resolveHealthCheckInputDateTokens({ date: "+45d" }, new Date(),
|
|
|
226
226
|
Do not re-resolve a health assertion's dates in UTC when its case input used the
|
|
227
227
|
default KST calendar.
|
|
228
228
|
|
|
229
|
+
### Sensitive vs public fields
|
|
230
|
+
|
|
231
|
+
The platform fixture-privacy ratchet flags name-, phone-, and address-shaped keys
|
|
232
|
+
unless the schema at that path declares them one way or the other. Declare every hit:
|
|
233
|
+
|
|
234
|
+
- `sensitive(schema, kind)` / `fields.*()` — anything about a person: user, profile,
|
|
235
|
+
passenger, driver, or member names, emails, member ids, personal phone numbers.
|
|
236
|
+
Emits `x-apifuse-sensitive: true`; the value is redacted in published artifacts.
|
|
237
|
+
- `publicField(schema)` — reviewed public data: business, shop, product, artist, or
|
|
238
|
+
facility names, hospital/hotel/station phones, timezone names. Emits
|
|
239
|
+
`x-apifuse-sensitive: false`; nothing is redacted. It is a review verdict, not a mute.
|
|
240
|
+
Credential-shaped keys (token, password, apiKey, …) cannot be declared public.
|
|
241
|
+
|
|
242
|
+
Apply either helper to the leaf, before `.optional()`/`.nullable()`/`.default()`;
|
|
243
|
+
`publicField()` over a wrapper that hides a `sensitive()` leaf throws at definition time.
|
|
244
|
+
|
|
229
245
|
### Real-handler E2E in standard tests
|
|
230
246
|
|
|
231
247
|
`runStandardTests(provider)` validates declarations and fixtures but reports a
|
package/CHANGELOG.md
CHANGED
package/bin/apifuse-dev.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { readDiagnosticEnv } from "../src/runtime/diagnostic-env.js";
|
|
2
3
|
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
import { dirname, relative, resolve } from "node:path";
|
|
@@ -87,7 +88,7 @@ export function createProviderContext(provider: ProviderDefinition): {
|
|
|
87
88
|
process.env,
|
|
88
89
|
provider.secrets?.map((secret) => secret.name) ?? [],
|
|
89
90
|
);
|
|
90
|
-
const providerEnv = { get: (key: string) =>
|
|
91
|
+
const providerEnv = { get: (key: string) => readDiagnosticEnv(key, providerEnvironment) };
|
|
91
92
|
const engineEnv = createEnvContext([PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV]);
|
|
92
93
|
const engineCredentials = readEngineProxyCredentials();
|
|
93
94
|
const credential = createCredentialContext();
|
package/bin/apifuse-perf.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @ts-nocheck
|
|
3
|
+
import { readDiagnosticEnv } from "../src/runtime/diagnostic-env.js";
|
|
3
4
|
|
|
4
5
|
import { existsSync } from "node:fs";
|
|
5
6
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -25,11 +26,20 @@ import {
|
|
|
25
26
|
type StealthResponse,
|
|
26
27
|
wrapWithInstrumentation,
|
|
27
28
|
} from "../src/index.js";
|
|
29
|
+
import {
|
|
30
|
+
bindDiagnosticSensitiveRegistry,
|
|
31
|
+
type CompiledDiagnosticSensitiveValues,
|
|
32
|
+
compileProcessDiagnosticSensitiveValues,
|
|
33
|
+
createDiagnosticRedactor,
|
|
34
|
+
redactDiagnosticText,
|
|
35
|
+
} from "../src/runtime/diagnostic-redactor.js";
|
|
28
36
|
import { computeStats, groupSpansByName, type PerfStats } from "../src/runtime/perf.js";
|
|
29
37
|
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
30
38
|
import { createStealthClient } from "../src/runtime/stealth.js";
|
|
31
39
|
import { createTraceContext, resolveTraceContextOptions } from "../src/runtime/trace.js";
|
|
32
40
|
import { renderWaterfall } from "../src/runtime/waterfall.js";
|
|
41
|
+
import { collectStaticDiagnosticSensitiveValues } from "../src/server/sensitive-values.js";
|
|
42
|
+
import { sanitizeSpanForOutput } from "../src/trace-sanitization.js";
|
|
33
43
|
import type { BrowserClient } from "../src/types.js";
|
|
34
44
|
|
|
35
45
|
type CliArgs = {
|
|
@@ -100,6 +110,9 @@ export async function main() {
|
|
|
100
110
|
const providerDirectory = resolve(process.cwd(), args.providerPath);
|
|
101
111
|
const providerEntry = resolveProviderEntry(providerDirectory);
|
|
102
112
|
const provider = await loadProvider(providerEntry);
|
|
113
|
+
const staticSensitiveValues = compileProcessDiagnosticSensitiveValues(
|
|
114
|
+
collectStaticDiagnosticSensitiveValues(provider),
|
|
115
|
+
);
|
|
103
116
|
const providerId = basename(providerDirectory);
|
|
104
117
|
const config = await loadApiFuseConfig(process.cwd());
|
|
105
118
|
const operation = getOperation(provider, args.operation);
|
|
@@ -119,6 +132,7 @@ export async function main() {
|
|
|
119
132
|
operationName: args.operation,
|
|
120
133
|
outputSchema,
|
|
121
134
|
proxyEnabled: false,
|
|
135
|
+
staticSensitiveValues,
|
|
122
136
|
});
|
|
123
137
|
|
|
124
138
|
let proxySuite: ProfileSuite | undefined;
|
|
@@ -135,6 +149,7 @@ export async function main() {
|
|
|
135
149
|
operationName: args.operation,
|
|
136
150
|
outputSchema,
|
|
137
151
|
proxyEnabled: true,
|
|
152
|
+
staticSensitiveValues,
|
|
138
153
|
});
|
|
139
154
|
}
|
|
140
155
|
|
|
@@ -170,8 +185,8 @@ export async function main() {
|
|
|
170
185
|
runs: args.runs,
|
|
171
186
|
warmup: args.warmup,
|
|
172
187
|
concurrency: args.concurrency,
|
|
173
|
-
direct: directSuite,
|
|
174
|
-
proxy: proxySuite,
|
|
188
|
+
direct: sanitizeProfileSuiteForExport(directSuite),
|
|
189
|
+
proxy: proxySuite ? sanitizeProfileSuiteForExport(proxySuite) : undefined,
|
|
175
190
|
flamePath,
|
|
176
191
|
});
|
|
177
192
|
console.log(`Exported JSON: ${resolve(process.cwd(), args.exportPath)}`);
|
|
@@ -480,6 +495,7 @@ async function runProfileSuite(options: {
|
|
|
480
495
|
operationName: string;
|
|
481
496
|
outputSchema: { parse(input: unknown): unknown };
|
|
482
497
|
proxyEnabled: boolean;
|
|
498
|
+
staticSensitiveValues: CompiledDiagnosticSensitiveValues;
|
|
483
499
|
}): Promise<ProfileSuite> {
|
|
484
500
|
for (let index = 0; index < options.args.warmup; index += 1) {
|
|
485
501
|
await profileRun({
|
|
@@ -492,6 +508,7 @@ async function runProfileSuite(options: {
|
|
|
492
508
|
operationName: options.operationName,
|
|
493
509
|
outputSchema: options.outputSchema,
|
|
494
510
|
proxyEnabled: options.proxyEnabled,
|
|
511
|
+
staticSensitiveValues: options.staticSensitiveValues,
|
|
495
512
|
});
|
|
496
513
|
}
|
|
497
514
|
|
|
@@ -509,6 +526,7 @@ async function runProfileSuite(options: {
|
|
|
509
526
|
operationName: options.operationName,
|
|
510
527
|
outputSchema: options.outputSchema,
|
|
511
528
|
proxyEnabled: options.proxyEnabled,
|
|
529
|
+
staticSensitiveValues: options.staticSensitiveValues,
|
|
512
530
|
}),
|
|
513
531
|
);
|
|
514
532
|
runs.push(...(await Promise.all(batch)));
|
|
@@ -545,6 +563,7 @@ async function profileRun(options: {
|
|
|
545
563
|
operationName: string;
|
|
546
564
|
outputSchema: { parse(input: unknown): unknown };
|
|
547
565
|
proxyEnabled: boolean;
|
|
566
|
+
staticSensitiveValues: CompiledDiagnosticSensitiveValues;
|
|
548
567
|
}): Promise<RunResult> {
|
|
549
568
|
try {
|
|
550
569
|
return await executeProfileRun({ ...options, forceFixtureReplay: false });
|
|
@@ -576,9 +595,16 @@ async function executeProfileRun(options: {
|
|
|
576
595
|
operationName: string;
|
|
577
596
|
outputSchema: { parse(input: unknown): unknown };
|
|
578
597
|
proxyEnabled: boolean;
|
|
598
|
+
staticSensitiveValues: CompiledDiagnosticSensitiveValues;
|
|
579
599
|
}): Promise<RunResult> {
|
|
580
600
|
const _operation = getOperation(options.provider, options.operationName);
|
|
581
|
-
const
|
|
601
|
+
const sensitiveRegistry = createDiagnosticRedactor([], options.staticSensitiveValues);
|
|
602
|
+
const redact = (text: string) => redactDiagnosticText(text, sensitiveRegistry.redact);
|
|
603
|
+
const traceContext = createTraceContext({
|
|
604
|
+
...resolveTraceContextOptions(options.config.trace),
|
|
605
|
+
redact,
|
|
606
|
+
});
|
|
607
|
+
bindDiagnosticSensitiveRegistry(traceContext, sensitiveRegistry);
|
|
582
608
|
const baseContext = createBaseContext({
|
|
583
609
|
config: options.config,
|
|
584
610
|
provider: options.provider,
|
|
@@ -650,7 +676,7 @@ function createBaseContext(options: {
|
|
|
650
676
|
});
|
|
651
677
|
|
|
652
678
|
const env = {
|
|
653
|
-
get: (key: string) =>
|
|
679
|
+
get: (key: string) => readDiagnosticEnv(key),
|
|
654
680
|
};
|
|
655
681
|
const credential = {
|
|
656
682
|
mode: "none" as const,
|
|
@@ -925,6 +951,17 @@ function selectRepresentativeRun(runs: RunResult[]): RunResult {
|
|
|
925
951
|
return first;
|
|
926
952
|
}
|
|
927
953
|
|
|
954
|
+
function sanitizeProfileSuiteForExport(suite: ProfileSuite): ProfileSuite {
|
|
955
|
+
// The perf CLI has no server request scope; retain the shared output policy on disk.
|
|
956
|
+
return {
|
|
957
|
+
...suite,
|
|
958
|
+
runs: suite.runs.map((run) => ({
|
|
959
|
+
...run,
|
|
960
|
+
spans: run.spans.map((span) => sanitizeSpanForOutput(span)),
|
|
961
|
+
})),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
928
965
|
async function writeExport(filePath: string, payload: unknown): Promise<void> {
|
|
929
966
|
const absolutePath = resolve(process.cwd(), filePath);
|
|
930
967
|
await mkdir(dirname(absolutePath), { recursive: true });
|
package/bin/apifuse-record.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { readDiagnosticEnv } from "../src/runtime/diagnostic-env.js";
|
|
2
3
|
|
|
3
4
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
5
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
@@ -519,8 +520,8 @@ export function createCaptureContext(
|
|
|
519
520
|
process.env,
|
|
520
521
|
provider.secrets?.map((secret) => secret.name) ?? [],
|
|
521
522
|
);
|
|
522
|
-
const env = { get: (key: string) =>
|
|
523
|
-
const engineEnv = { get: (key: string) =>
|
|
523
|
+
const env = { get: (key: string) => readDiagnosticEnv(key, providerEnvironment) };
|
|
524
|
+
const engineEnv = { get: (key: string) => readDiagnosticEnv(key) };
|
|
524
525
|
const engineCredentials = readEngineProxyCredentials();
|
|
525
526
|
const credential = {
|
|
526
527
|
mode: "none" as const,
|
package/dist/config/loader.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readDiagnosticEnv } from "../runtime/diagnostic-env.js";
|
|
1
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
@@ -63,17 +64,17 @@ const SMARTPROXY_ALLOCATOR_RETRY_BASE_MS = 25;
|
|
|
63
64
|
const SMARTPROXY_EXTRACTION_CACHE_TTL_MS = 15_000;
|
|
64
65
|
const SMARTPROXY_EXTRACTION_SOFT_REFRESH_MS = 10_000;
|
|
65
66
|
function redisUrlFromEnv() {
|
|
66
|
-
return (
|
|
67
|
-
|
|
67
|
+
return (readDiagnosticEnv(PROVIDER_CACHE_REDIS_URL_ENV)?.trim() ||
|
|
68
|
+
readDiagnosticEnv(REDIS_URL_ENV)?.trim() ||
|
|
68
69
|
undefined);
|
|
69
70
|
}
|
|
70
71
|
export function providerCacheRedisUrlFromEnv() {
|
|
71
72
|
return redisUrlFromEnv();
|
|
72
73
|
}
|
|
73
74
|
export function providerStateRedisUrlFromEnv() {
|
|
74
|
-
return (
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
return (readDiagnosticEnv(PROVIDER_STATE_REDIS_URL_ENV)?.trim() ||
|
|
76
|
+
readDiagnosticEnv(PROVIDER_CACHE_REDIS_URL_ENV)?.trim() ||
|
|
77
|
+
readDiagnosticEnv(REDIS_URL_ENV)?.trim() ||
|
|
77
78
|
undefined);
|
|
78
79
|
}
|
|
79
80
|
/** @internal Test-only hook for exercising shared proxy-cache behavior. */
|
|
@@ -407,10 +408,10 @@ export async function resolveWithVendor(vendor, policy, options, context) {
|
|
|
407
408
|
if (vendor === "nodemaven") {
|
|
408
409
|
const startedAt = Date.now();
|
|
409
410
|
const username = (context.credentials === undefined
|
|
410
|
-
?
|
|
411
|
+
? readDiagnosticEnv(NODEMAVEN_USERNAME_ENV)
|
|
411
412
|
: context.credentials[NODEMAVEN_USERNAME_ENV])?.trim();
|
|
412
413
|
const password = (context.credentials === undefined
|
|
413
|
-
?
|
|
414
|
+
? readDiagnosticEnv(NODEMAVEN_PASSWORD_ENV)
|
|
414
415
|
: context.credentials[NODEMAVEN_PASSWORD_ENV])?.trim();
|
|
415
416
|
const filter = context.credentials === undefined
|
|
416
417
|
? process.env[NODEMAVEN_FILTER_ENV]
|
|
@@ -453,7 +454,7 @@ export async function resolveWithVendor(vendor, policy, options, context) {
|
|
|
453
454
|
}
|
|
454
455
|
// smartproxy allocation-style vendor.
|
|
455
456
|
const appKey = (context.credentials === undefined
|
|
456
|
-
?
|
|
457
|
+
? readDiagnosticEnv(SMARTPROXY_APP_KEY_ENV)
|
|
457
458
|
: context.credentials[SMARTPROXY_APP_KEY_ENV])?.trim();
|
|
458
459
|
if (!appKey) {
|
|
459
460
|
// Guarded by vendorHasCredentials; treated as a vendor-internal failure.
|
|
@@ -520,14 +521,14 @@ function envDefaultProvider() {
|
|
|
520
521
|
function vendorHasCredentials(vendor, credentials) {
|
|
521
522
|
if (vendor === "nodemaven") {
|
|
522
523
|
return Boolean((credentials === undefined
|
|
523
|
-
?
|
|
524
|
+
? readDiagnosticEnv(NODEMAVEN_USERNAME_ENV)
|
|
524
525
|
: credentials[NODEMAVEN_USERNAME_ENV])?.trim() &&
|
|
525
526
|
(credentials === undefined
|
|
526
|
-
?
|
|
527
|
+
? readDiagnosticEnv(NODEMAVEN_PASSWORD_ENV)
|
|
527
528
|
: credentials[NODEMAVEN_PASSWORD_ENV])?.trim());
|
|
528
529
|
}
|
|
529
530
|
return Boolean((credentials === undefined
|
|
530
|
-
?
|
|
531
|
+
? readDiagnosticEnv(SMARTPROXY_APP_KEY_ENV)
|
|
531
532
|
: credentials[SMARTPROXY_APP_KEY_ENV])?.trim());
|
|
532
533
|
}
|
|
533
534
|
function missingCredentialEnv(vendor) {
|
|
@@ -1178,7 +1179,7 @@ function markSmartproxyCacheInvalidated(options = {}) {
|
|
|
1178
1179
|
}
|
|
1179
1180
|
const lifetimeMinutes = resolveSmartproxyLifetime(policy);
|
|
1180
1181
|
const appKey = (options.engineCredentials === undefined
|
|
1181
|
-
?
|
|
1182
|
+
? readDiagnosticEnv(SMARTPROXY_APP_KEY_ENV)
|
|
1182
1183
|
: options.engineCredentials[SMARTPROXY_APP_KEY_ENV])?.trim();
|
|
1183
1184
|
if (!appKey)
|
|
1184
1185
|
return undefined;
|
package/dist/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readDiagnosticEnv } from "./runtime/diagnostic-env.js";
|
|
1
2
|
import { ProviderError } from "./errors.js";
|
|
2
3
|
import { APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY, } from "./runtime/resolver-config.js";
|
|
3
4
|
import { OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_HEADERS, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME, } from "./runtime/otlp.js";
|
|
@@ -99,7 +100,7 @@ export function isEngineOwnedEnvName(name) {
|
|
|
99
100
|
/** Capture credentials in the engine host before constructing provider bindings. */
|
|
100
101
|
export function readEngineProxyCredentials(environment = process.env) {
|
|
101
102
|
return Object.fromEntries(ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES.flatMap((name) => {
|
|
102
|
-
const value = environment
|
|
103
|
+
const value = readDiagnosticEnv(name, environment)?.trim();
|
|
103
104
|
return value ? [[name, value]] : [];
|
|
104
105
|
}));
|
|
105
106
|
}
|
|
@@ -108,7 +109,7 @@ export function createProviderEnvironment(environment, declaredNames) {
|
|
|
108
109
|
return Object.fromEntries(declaredNames.flatMap((name) => {
|
|
109
110
|
if (isEngineOwnedEnvName(name))
|
|
110
111
|
return [];
|
|
111
|
-
const value = environment
|
|
112
|
+
const value = readDiagnosticEnv(name, environment);
|
|
112
113
|
return value === undefined ? [] : [[name, value]];
|
|
113
114
|
}));
|
|
114
115
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -45,7 +45,8 @@ export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, }
|
|
|
45
45
|
export { APIFUSE__OCR__API_KEY_ENV, APIFUSE__OCR__BACKEND_ENV, APIFUSE__OCR__BASE_URL_ENV, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__OCR__MODEL_ENV, CLOUDFLARE_ACCOUNT_ID_ENV, CLOUDFLARE_WORKERS_AI_OCR_BACKEND, createCloudflareWorkersAiOcrClient, createOcrClientFromEnv, createOpenAiCompatibleOcrClient, createUnsupportedOcrClient, DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL, extractCaptchaCandidates, OPENAI_COMPATIBLE_OCR_BACKEND, } from "./runtime/ocr.js";
|
|
46
46
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
|
47
47
|
export { type CreateTraceContextOptions, createTraceContext, type Span, type TraceContext, } from "./runtime/trace.js";
|
|
48
|
-
export
|
|
48
|
+
export type { DiagnosticRedactor } from "./runtime/diagnostic-redactor.js";
|
|
49
|
+
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, untrustedContent, z, } from "./schema.js";
|
|
49
50
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ProviderErrorCauseFrame, type ServeOptions, serve, } from "./server/serve.js";
|
|
50
51
|
export { DEFAULT_STEALTH_BROWSER, DEFAULT_STEALTH_OS, getStealthProfile, listStealthProfiles, } from "./stealth/profiles.js";
|
|
51
52
|
export * from "./stream.js";
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, }
|
|
|
36
36
|
export { APIFUSE__OCR__API_KEY_ENV, APIFUSE__OCR__BACKEND_ENV, APIFUSE__OCR__BASE_URL_ENV, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__OCR__MODEL_ENV, CLOUDFLARE_ACCOUNT_ID_ENV, CLOUDFLARE_WORKERS_AI_OCR_BACKEND, createCloudflareWorkersAiOcrClient, createOcrClientFromEnv, createOpenAiCompatibleOcrClient, createUnsupportedOcrClient, DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL, extractCaptchaCandidates, OPENAI_COMPATIBLE_OCR_BACKEND, } from "./runtime/ocr.js";
|
|
37
37
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
|
38
38
|
export { createTraceContext, } from "./runtime/trace.js";
|
|
39
|
-
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
|
|
39
|
+
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
|
|
40
40
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serve, } from "./server/serve.js";
|
|
41
41
|
export { DEFAULT_STEALTH_BROWSER, DEFAULT_STEALTH_OS, getStealthProfile, listStealthProfiles, } from "./stealth/profiles.js";
|
|
42
42
|
export * from "./stream.js";
|
package/dist/lint.js
CHANGED
|
@@ -380,17 +380,28 @@ function getChildSchemas(schema) {
|
|
|
380
380
|
function uniqueFields(fields) {
|
|
381
381
|
return Array.from(new Set(fields));
|
|
382
382
|
}
|
|
383
|
-
function
|
|
384
|
-
|
|
385
|
-
|
|
383
|
+
function readSensitivityDeclaration(schema, seen = new Set()) {
|
|
384
|
+
// Declarations sit on the leaf; same-path wrappers such as .optional(),
|
|
385
|
+
// .nullable(), .pipe() or z.lazy() carry no metadata of their own, so look
|
|
386
|
+
// through them.
|
|
387
|
+
if (!isSchema(schema) || seen.has(schema))
|
|
388
|
+
return undefined;
|
|
389
|
+
seen.add(schema);
|
|
390
|
+
const value = Reflect.get(getSchemaMetadata(schema), APIFUSE_SENSITIVE_META_KEY);
|
|
391
|
+
if (typeof value === "boolean")
|
|
392
|
+
return value;
|
|
393
|
+
const def = getSchemaDef(schema);
|
|
394
|
+
const children = def.type === "pipe"
|
|
395
|
+
? [def.in, def.out]
|
|
396
|
+
: def.type === "lazy" && typeof def.getter === "function"
|
|
397
|
+
? [def.getter()]
|
|
398
|
+
: [def.innerType];
|
|
399
|
+
for (const child of children) {
|
|
400
|
+
const declaration = readSensitivityDeclaration(child, seen);
|
|
401
|
+
if (declaration !== undefined)
|
|
402
|
+
return declaration;
|
|
386
403
|
}
|
|
387
|
-
|
|
388
|
-
if (typeof meta !== "function")
|
|
389
|
-
return false;
|
|
390
|
-
const metadata = meta.call(schema);
|
|
391
|
-
return (!!metadata &&
|
|
392
|
-
typeof metadata === "object" &&
|
|
393
|
-
Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true);
|
|
404
|
+
return undefined;
|
|
394
405
|
}
|
|
395
406
|
function getSchemaMetadata(schema) {
|
|
396
407
|
return schema.meta?.() ?? {};
|
|
@@ -416,9 +427,19 @@ const SENSITIVE_FIELD_NAMES = new Set([
|
|
|
416
427
|
"phonenumber",
|
|
417
428
|
"paymenturl",
|
|
418
429
|
]);
|
|
430
|
+
// Only phone-shaped keys can hold reviewed public data (facility phones); the
|
|
431
|
+
// rest are credentials, which a public declaration must not launder.
|
|
432
|
+
const PUBLIC_DECLARABLE_FIELD_NAMES = new Set(["phone", "phonenumber"]);
|
|
433
|
+
function normalizeFieldName(name) {
|
|
434
|
+
return name.toLowerCase().replace(/[-_\s]/g, "");
|
|
435
|
+
}
|
|
419
436
|
function isSensitiveFieldName(name) {
|
|
420
|
-
|
|
421
|
-
|
|
437
|
+
return SENSITIVE_FIELD_NAMES.has(normalizeFieldName(name));
|
|
438
|
+
}
|
|
439
|
+
function isDeclaredSensitiveField(key, schema) {
|
|
440
|
+
const declaration = readSensitivityDeclaration(schema);
|
|
441
|
+
return (declaration === true ||
|
|
442
|
+
(declaration === false && PUBLIC_DECLARABLE_FIELD_NAMES.has(normalizeFieldName(key))));
|
|
422
443
|
}
|
|
423
444
|
function collectUnmarkedSensitiveFields(schema, basePath, seen = new Set()) {
|
|
424
445
|
if (!isSchema(schema) || seen.has(schema)) {
|
|
@@ -428,7 +449,7 @@ function collectUnmarkedSensitiveFields(schema, basePath, seen = new Set()) {
|
|
|
428
449
|
const out = [];
|
|
429
450
|
for (const [key, child] of Object.entries(getObjectShape(schema))) {
|
|
430
451
|
const childPath = basePath ? `${basePath}.${key}` : key;
|
|
431
|
-
if (isSensitiveFieldName(key) && !
|
|
452
|
+
if (isSensitiveFieldName(key) && !isDeclaredSensitiveField(key, child)) {
|
|
432
453
|
out.push(childPath);
|
|
433
454
|
}
|
|
434
455
|
out.push(...collectUnmarkedSensitiveFields(child, childPath, seen));
|
|
@@ -1086,7 +1107,7 @@ export function lintOperation(op) {
|
|
|
1086
1107
|
rule: "sensitive-field-unmarked",
|
|
1087
1108
|
level: "warn",
|
|
1088
1109
|
field,
|
|
1089
|
-
message: `Schema field "${field}" looks sensitive; mark it with fields.*()
|
|
1110
|
+
message: `Schema field "${field}" looks sensitive; mark it with fields.*() or sensitive(...); publicField(...) is accepted only for reviewed public phone-shaped fields.`,
|
|
1090
1111
|
});
|
|
1091
1112
|
}
|
|
1092
1113
|
for (const field of uniqueFields(collectUnmarkedSensitiveFields(op.output, "output"))) {
|
|
@@ -1094,7 +1115,7 @@ export function lintOperation(op) {
|
|
|
1094
1115
|
rule: "sensitive-field-unmarked",
|
|
1095
1116
|
level: "warn",
|
|
1096
1117
|
field,
|
|
1097
|
-
message: `Schema field "${field}" looks sensitive; mark it with fields.*()
|
|
1118
|
+
message: `Schema field "${field}" looks sensitive; mark it with fields.*() or sensitive(...); publicField(...) is accepted only for reviewed public phone-shaped fields.`,
|
|
1098
1119
|
});
|
|
1099
1120
|
}
|
|
1100
1121
|
return diagnostics;
|
package/dist/provider.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_
|
|
|
12
12
|
export type { ProviderCapabilityKey, ProviderEngine, ProviderEngineAttachmentInput, ProviderEngineBindingCandidates, ProviderEngineCapabilitySurface, ProviderEngineRequest, ProviderEngineResidentSurface, ProviderEngineSession, ProviderEngineTransport, } from "./engine.js";
|
|
13
13
|
export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
14
14
|
export { type CreateProviderChoiceContextOptions, createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
15
|
-
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, untrustedContent, z, } from "./schema.js";
|
|
15
|
+
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, untrustedContent, z, } from "./schema.js";
|
|
16
16
|
export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationExample, OperationErrorCode, ProviderErrorStatus, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceConsumeMode, ProviderChoiceConsumeResult, ProviderChoiceContext, ProviderChoiceExplicitParseResult, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderContextFor, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProxiedOAuthConfig, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderResolvedFile, ProviderRuntimeTarget, ProviderRuntimeState, ProviderStealthConfig, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, RedirectRunReason, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateNamespaceScope, StateValue, StateWriteOptions, StealthChallengeClassification, } from "./types.js";
|
|
17
17
|
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
18
18
|
export type { NativeGatewayProxy, NativeGatewayProxyResolutionInput, NativeGatewayProxySkipReason, NativeGatewayProxySynthesizer, NativeGatewayProxySynthesisResult, NativeGatewayProxySynthesisInput, NativeNetworkClientOptions, NativeNetworkErrorCode, VendorCredentialLookup, VendorCredentialResolver, } from "./runtime/native-network.js";
|
package/dist/provider.js
CHANGED
|
@@ -7,6 +7,6 @@ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, i
|
|
|
7
7
|
export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
|
|
8
8
|
export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
9
9
|
export { createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
10
|
-
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
|
|
10
|
+
export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
|
|
11
11
|
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
12
12
|
export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
|
package/dist/runtime/browser.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readDiagnosticEnv } from "./diagnostic-env.js";
|
|
1
2
|
import { createRequire } from "node:module";
|
|
2
3
|
import { ProviderError } from "../errors.js";
|
|
3
4
|
const require = createRequire(import.meta.url);
|
|
@@ -289,7 +290,7 @@ function createResourcePolicyHandler(policy, allowedMethods) {
|
|
|
289
290
|
};
|
|
290
291
|
}
|
|
291
292
|
function getDefaultCdpPoolUrl(env = process.env) {
|
|
292
|
-
return env
|
|
293
|
+
return readDiagnosticEnv("APIFUSE__CDP_POOL__URL", env);
|
|
293
294
|
}
|
|
294
295
|
async function importOptionalModule(moduleName) {
|
|
295
296
|
return (await import(moduleName));
|
package/dist/runtime/cache.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readDiagnosticEnv } from "./diagnostic-env.js";
|
|
1
2
|
import { createHash, createHmac } from "node:crypto";
|
|
2
3
|
import { providerCacheRedisUrlFromEnv } from "../config/loader.js";
|
|
3
4
|
import { ProviderError } from "../errors.js";
|
|
@@ -279,7 +280,7 @@ async function withRedisFallback(operation) {
|
|
|
279
280
|
}
|
|
280
281
|
export function createProviderCache(options) {
|
|
281
282
|
const redisUrl = options.redisUrl ?? providerCacheRedisUrlFromEnv();
|
|
282
|
-
const configuredPepper =
|
|
283
|
+
const configuredPepper = readDiagnosticEnv(APIFUSE__CACHE__KEY_PEPPER_ENV);
|
|
283
284
|
const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
|
|
284
285
|
const backend = getSharedBackend(redisUrl);
|
|
285
286
|
const memoryMaxEntries = Math.max(1, options.memoryMaxEntries ?? DEFAULT_MEMORY_MAX_ENTRIES);
|
|
@@ -471,7 +472,7 @@ export function isProviderCacheBypassed(cache) {
|
|
|
471
472
|
return bypassCaches.has(cache);
|
|
472
473
|
}
|
|
473
474
|
export function createBypassProviderCache(options) {
|
|
474
|
-
const configuredPepper =
|
|
475
|
+
const configuredPepper = readDiagnosticEnv(APIFUSE__CACHE__KEY_PEPPER_ENV);
|
|
475
476
|
const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
|
|
476
477
|
const events = [];
|
|
477
478
|
const secretScopedKeys = new Set();
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function resolvedStringVariants(value: string | undefined): string[];
|
|
2
|
+
export declare function urlCredentialComponents(value: string, options: {
|
|
3
|
+
includePathAndQuery: boolean;
|
|
4
|
+
}): string[];
|
|
5
|
+
export declare function otlpHeaderCredentialValues(value: string): string[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function resolvedStringVariants(value) {
|
|
2
|
+
if (value === undefined)
|
|
3
|
+
return [];
|
|
4
|
+
return [...new Set([value, value.trim()])].filter((candidate) => candidate.length > 0);
|
|
5
|
+
}
|
|
6
|
+
function decodedComponent(value) {
|
|
7
|
+
try {
|
|
8
|
+
return decodeURIComponent(value);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function urlCredentialComponents(value, options) {
|
|
15
|
+
let url;
|
|
16
|
+
try {
|
|
17
|
+
url = new URL(value.trim());
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const username = decodedComponent(url.username);
|
|
23
|
+
const password = decodedComponent(url.password);
|
|
24
|
+
const components = [username, password, username && password ? `${username}:${password}` : ""];
|
|
25
|
+
if (options.includePathAndQuery) {
|
|
26
|
+
for (const segment of url.pathname.split("/")) {
|
|
27
|
+
if (segment)
|
|
28
|
+
components.push(decodedComponent(segment));
|
|
29
|
+
}
|
|
30
|
+
for (const [key, entryValue] of url.searchParams) {
|
|
31
|
+
if (key)
|
|
32
|
+
components.push(key);
|
|
33
|
+
if (entryValue) {
|
|
34
|
+
components.push(entryValue, `${key}=${entryValue}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [...new Set(components.flatMap((component) => resolvedStringVariants(component)))];
|
|
39
|
+
}
|
|
40
|
+
export function otlpHeaderCredentialValues(value) {
|
|
41
|
+
const variants = resolvedStringVariants(value);
|
|
42
|
+
for (const member of value.split(",")) {
|
|
43
|
+
const separator = member.indexOf("=");
|
|
44
|
+
if (separator <= 0)
|
|
45
|
+
continue;
|
|
46
|
+
const headerValue = decodedComponent(member.slice(separator + 1).trim());
|
|
47
|
+
variants.push(...resolvedStringVariants(headerValue));
|
|
48
|
+
const headerName = decodedComponent(member.slice(0, separator).trim()).toLowerCase();
|
|
49
|
+
if (headerName === "authorization" || headerName === "proxy-authorization") {
|
|
50
|
+
// A transport may echo just the credential without its HTTP auth scheme.
|
|
51
|
+
const credential = /^(?:Bearer|Basic)\s+(.+)$/i.exec(headerValue)?.[1];
|
|
52
|
+
if (credential)
|
|
53
|
+
variants.push(...resolvedStringVariants(credential));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...new Set(variants)];
|
|
57
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CompiledDiagnosticSensitiveValues } from "./diagnostic-redactor.js";
|
|
2
|
+
type EnvObserver = (name: string, value: string) => void;
|
|
3
|
+
export interface DiagnosticEnvScope {
|
|
4
|
+
observe: EnvObserver;
|
|
5
|
+
finished: boolean;
|
|
6
|
+
staticValues?: CompiledDiagnosticSensitiveValues;
|
|
7
|
+
}
|
|
8
|
+
/** Resolve and register atomically, before any consumer can use a live env credential. */
|
|
9
|
+
export declare function readDiagnosticEnv(name: string, env?: Readonly<Record<string, string | undefined>>): string | undefined;
|
|
10
|
+
export declare function withDiagnosticEnv<T>(observer: EnvObserver | DiagnosticEnvScope, fn: () => T): T;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { resolvedStringVariants, urlCredentialComponents, otlpHeaderCredentialValues, } from "./diagnostic-env-values.js";
|
|
3
|
+
import { registerProcessDiagnosticValues, suppressProcessDiagnosticValues, withAppDiagnosticFallback, } from "./diagnostic-redactor.js";
|
|
4
|
+
const observers = new AsyncLocalStorage();
|
|
5
|
+
/** Resolve and register atomically, before any consumer can use a live env credential. */
|
|
6
|
+
export function readDiagnosticEnv(name, env = process.env) {
|
|
7
|
+
const value = env[name];
|
|
8
|
+
if (value !== undefined) {
|
|
9
|
+
const scope = observers.getStore();
|
|
10
|
+
if (scope && !scope.finished)
|
|
11
|
+
scope.observe(name, value);
|
|
12
|
+
else {
|
|
13
|
+
// ALS survives the response. Finished requests register into the app's
|
|
14
|
+
// inherited fallback lifetime, never a dead request's private inventory.
|
|
15
|
+
if (Buffer.byteLength(value) > 64 * 1024)
|
|
16
|
+
suppressProcessDiagnosticValues();
|
|
17
|
+
else
|
|
18
|
+
registerProcessDiagnosticValues([
|
|
19
|
+
...resolvedStringVariants(value),
|
|
20
|
+
...urlCredentialComponents(value, {
|
|
21
|
+
includePathAndQuery: name === "APIFUSE__CDP_POOL__URL",
|
|
22
|
+
}),
|
|
23
|
+
...(name === "OTEL_EXPORTER_OTLP_HEADERS" || name === "OTEL_EXPORTER_OTLP_TRACES_HEADERS"
|
|
24
|
+
? otlpHeaderCredentialValues(value)
|
|
25
|
+
: []),
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
export function withDiagnosticEnv(observer, fn) {
|
|
32
|
+
const scope = typeof observer === "function" ? { observe: observer, finished: false } : observer;
|
|
33
|
+
const run = () => observers.run(scope, fn);
|
|
34
|
+
return scope.staticValues ? withAppDiagnosticFallback(scope.staticValues, run) : run();
|
|
35
|
+
}
|