@apifuse/provider-sdk 2.2.0-beta.59 → 2.2.0-beta.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/AUTHORING.md +33 -16
  2. package/CHANGELOG.md +8 -0
  3. package/bin/apifuse-dev.ts +7 -8
  4. package/bin/apifuse-pack-types.ts +22 -0
  5. package/bin/apifuse-perf.ts +45 -10
  6. package/bin/apifuse-record.ts +6 -8
  7. package/bin/apifuse-submit-check.ts +2 -2
  8. package/dist/config/loader.js +13 -12
  9. package/dist/define.d.ts +3 -2
  10. package/dist/define.js +1 -1
  11. package/dist/dev.js +3 -1
  12. package/dist/engine.d.ts +7 -6
  13. package/dist/engine.js +6 -6
  14. package/dist/error-resolution.js +21 -4
  15. package/dist/errors.d.ts +3 -0
  16. package/dist/errors.js +9 -0
  17. package/dist/handle-meta.d.ts +39 -0
  18. package/dist/handle-meta.js +29 -0
  19. package/dist/handle.d.ts +187 -0
  20. package/dist/handle.js +254 -0
  21. package/dist/i18n/catalog.js +21 -1
  22. package/dist/index.d.ts +6 -4
  23. package/dist/index.js +4 -3
  24. package/dist/lint.d.ts +3 -0
  25. package/dist/lint.js +388 -62
  26. package/dist/provider.d.ts +4 -4
  27. package/dist/provider.js +3 -3
  28. package/dist/runtime/browser.js +2 -1
  29. package/dist/runtime/cache.js +3 -2
  30. package/dist/runtime/diagnostic-env-values.d.ts +5 -0
  31. package/dist/runtime/diagnostic-env-values.js +57 -0
  32. package/dist/runtime/diagnostic-env.d.ts +11 -0
  33. package/dist/runtime/diagnostic-env.js +35 -0
  34. package/dist/runtime/diagnostic-redactor.d.ts +49 -0
  35. package/dist/runtime/diagnostic-redactor.js +569 -0
  36. package/dist/runtime/egress-lease.d.ts +2 -0
  37. package/dist/runtime/egress-lease.js +4 -1
  38. package/dist/runtime/env.js +2 -1
  39. package/dist/runtime/handle-wordlist.d.ts +43 -0
  40. package/dist/runtime/{choice-wordlist.js → handle-wordlist.js} +127 -9
  41. package/dist/runtime/handle.d.ts +71 -0
  42. package/dist/runtime/handle.js +895 -0
  43. package/dist/runtime/instrumentation.js +3 -0
  44. package/dist/runtime/native-network.d.ts +10 -1
  45. package/dist/runtime/native-network.js +230 -29
  46. package/dist/runtime/native-telemetry.d.ts +142 -0
  47. package/dist/runtime/native-telemetry.js +231 -0
  48. package/dist/runtime/ocr.js +2 -1
  49. package/dist/runtime/otlp.js +5 -4
  50. package/dist/runtime/proxy-nodemaven.js +3 -2
  51. package/dist/runtime/request-options.d.ts +7 -0
  52. package/dist/runtime/request-options.js +62 -22
  53. package/dist/runtime/resolver-vendors/browser.js +0 -1
  54. package/dist/runtime/resolver.js +3 -2
  55. package/dist/runtime/state.d.ts +4 -1
  56. package/dist/runtime/state.js +32 -17
  57. package/dist/runtime/stt.js +3 -2
  58. package/dist/runtime/trace.d.ts +5 -0
  59. package/dist/runtime/trace.js +115 -20
  60. package/dist/schema.d.ts +11 -0
  61. package/dist/schema.js +56 -2
  62. package/dist/server/index.d.ts +1 -0
  63. package/dist/server/index.js +1 -0
  64. package/dist/server/self-test-redaction.js +8 -33
  65. package/dist/server/sensitive-values.d.ts +26 -0
  66. package/dist/server/sensitive-values.js +128 -0
  67. package/dist/server/serve-implementation.d.ts +4 -11
  68. package/dist/server/serve-implementation.js +305 -96
  69. package/dist/server/trace-output.d.ts +2 -1
  70. package/dist/server/trace-output.js +46 -14
  71. package/dist/testing/run.js +10 -7
  72. package/dist/trace-sanitization.d.ts +4 -3
  73. package/dist/trace-sanitization.js +45 -22
  74. package/dist/types.d.ts +4 -107
  75. package/package.json +2 -1
  76. package/src/config/loader.ts +13 -12
  77. package/src/define.ts +4 -3
  78. package/src/dev.ts +3 -1
  79. package/src/engine.ts +8 -8
  80. package/src/error-resolution.ts +21 -4
  81. package/src/errors.ts +13 -0
  82. package/src/handle-meta.ts +58 -0
  83. package/src/handle.ts +529 -0
  84. package/src/i18n/catalog.ts +23 -1
  85. package/src/index.ts +28 -13
  86. package/src/lint.ts +456 -71
  87. package/src/provider.ts +10 -20
  88. package/src/runtime/browser.ts +2 -1
  89. package/src/runtime/cache.ts +3 -2
  90. package/src/runtime/diagnostic-env-values.ts +56 -0
  91. package/src/runtime/diagnostic-env.ts +55 -0
  92. package/src/runtime/diagnostic-redactor.ts +662 -0
  93. package/src/runtime/egress-lease.ts +6 -1
  94. package/src/runtime/env.ts +2 -1
  95. package/src/runtime/{choice-wordlist.ts → handle-wordlist.ts} +130 -9
  96. package/src/runtime/handle.ts +1162 -0
  97. package/src/runtime/instrumentation.ts +3 -0
  98. package/src/runtime/native-network.ts +281 -33
  99. package/src/runtime/native-telemetry.ts +366 -0
  100. package/src/runtime/ocr.ts +2 -1
  101. package/src/runtime/otlp.ts +5 -4
  102. package/src/runtime/proxy-nodemaven.ts +3 -2
  103. package/src/runtime/request-options.ts +76 -28
  104. package/src/runtime/resolver-vendors/browser.ts +0 -1
  105. package/src/runtime/resolver.ts +3 -2
  106. package/src/runtime/state.ts +44 -16
  107. package/src/runtime/stt.ts +3 -2
  108. package/src/runtime/trace.ts +168 -26
  109. package/src/schema.ts +63 -2
  110. package/src/server/index.ts +17 -0
  111. package/src/server/self-test-redaction.ts +10 -40
  112. package/src/server/sensitive-values.ts +197 -0
  113. package/src/server/serve-implementation.ts +388 -128
  114. package/src/server/trace-output.ts +77 -17
  115. package/src/testing/run.ts +11 -7
  116. package/src/trace-sanitization.ts +70 -23
  117. package/src/types.ts +4 -137
  118. package/dist/choice-token.d.ts +0 -24
  119. package/dist/choice-token.js +0 -74
  120. package/dist/runtime/choice-wordlist.d.ts +0 -9
  121. package/dist/runtime/choice.d.ts +0 -27
  122. package/dist/runtime/choice.js +0 -801
  123. package/src/choice-token.ts +0 -165
  124. package/src/runtime/choice.ts +0 -1197
package/dist/provider.js CHANGED
@@ -1,12 +1,12 @@
1
1
  export { AuthAbortError, credentialsAuthChallenge, createAuthFlowHelpers, defineCredentialsAuth, } from "./auth.js";
2
2
  export { createFormCeremony } from "./ceremonies/index.js";
3
- export { assertFreshProviderChoiceIssuedAt, createProviderChoiceToken, ProviderChoiceTokenError, parseProviderChoiceToken, } from "./choice-token.js";
4
3
  export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define.js";
5
4
  export { AssertionExpressionSchema, AssertionPredicateSchema, AssertStepSchema, BoundedJsonPathSchema, CandidateBlockSchema, CandidatePolicySchema, CredentialRefDeclarationSchema, defineHealthScenario, HealthScenarioSchema, HealthStepSchema, ExtractStepSchema, FindFirstSchema, GuardStepSchema, JournalPolicySchema, JsonTemplateSchema, ManualTriggerPolicySchema, OperandSchema, OperationStepSchema, QuantifierSchema, ReferenceSchema, RetryPolicySchema, SafeRegexSchema, ScopedAssertionExpressionSchema, ScopedAssertionPredicateSchema, ScopedItemReferenceSchema, ScopedOperandSchema, StepReferenceSchema, RelativeDateNodeSchema, ValueTypeSchema, } from "./health-scenario.js";
6
5
  export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
7
6
  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
7
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
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";
8
+ export * from "./handle.js";
9
+ export { createHandleContext, createTestHandleContext, normalizeHandle, } from "./runtime/handle.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";
@@ -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.APIFUSE__CDP_POOL__URL;
293
+ return readDiagnosticEnv("APIFUSE__CDP_POOL__URL", env);
293
294
  }
294
295
  async function importOptionalModule(moduleName) {
295
296
  return (await import(moduleName));
@@ -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 = process.env[APIFUSE__CACHE__KEY_PEPPER_ENV];
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 = process.env[APIFUSE__CACHE__KEY_PEPPER_ENV];
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
+ }
@@ -0,0 +1,49 @@
1
+ export type DiagnosticRedactor = (text: string) => string;
2
+ export declare const REDACTION_FAILED = "[REDACTION_FAILED]";
3
+ /** Observer failures must never return the original diagnostic, including via ?? fallbacks. */
4
+ export declare function redactDiagnosticText(text: string, redact?: DiagnosticRedactor): string;
5
+ export interface DiagnosticSensitiveRegistry {
6
+ redact: DiagnosticRedactor;
7
+ readonly redactCritical: DiagnosticRedactor;
8
+ readonly redactStructured: DiagnosticRedactor;
9
+ readonly suppressed: boolean;
10
+ has(value: string): boolean;
11
+ add(values: readonly string[]): void;
12
+ suppress(): void;
13
+ }
14
+ /** Opaque handle: callers cannot modify either of the two independently compiled matchers. */
15
+ export interface CompiledDiagnosticSensitiveValues {
16
+ readonly kind: "compiled-diagnostic-sensitive-values";
17
+ }
18
+ export declare function compileDiagnosticSensitiveValues(values: readonly string[]): CompiledDiagnosticSensitiveValues;
19
+ /**
20
+ * Give an independent runtime/configuration evaluation its own fallback lifetime.
21
+ * Apps created inside the scope retain that inventory, including across awaits and
22
+ * after the callback returns. Ordinary startup/CLI reads keep the process lifetime.
23
+ * This also lets test harnesses isolate synthetic env reads without clearing live
24
+ * apps' credentials or weakening registration, matching, or exhaustion policies.
25
+ */
26
+ export declare function withDiagnosticFallbackScope<T>(fn: () => T): T;
27
+ /** Re-enter the app's existing lifetime, including for detached request callbacks. */
28
+ export declare function withAppDiagnosticFallback<T>(staticValues: CompiledDiagnosticSensitiveValues, fn: () => T): T;
29
+ export declare function suppressProcessDiagnosticValues(): void;
30
+ export declare function registerProcessDiagnosticValues(values: readonly string[]): void;
31
+ /** The app's static inventory and the shared outside-context fallback form one static part. */
32
+ export declare function compileProcessDiagnosticSensitiveValues(values: readonly string[]): CompiledDiagnosticSensitiveValues;
33
+ /** One small mutable registry per request, composed with precompiled process-static values. */
34
+ export declare function createDiagnosticRedactor(values?: readonly string[], staticValues?: CompiledDiagnosticSensitiveValues): DiagnosticSensitiveRegistry;
35
+ /** Internal binding; neither the registry nor its values enter provider-facing context types. */
36
+ export declare function bindDiagnosticSensitiveRegistry(trace: object, registry: DiagnosticSensitiveRegistry): void;
37
+ export declare function registerDiagnosticSensitiveValues(trace: object, values: readonly string[]): void;
38
+ export declare function bindCriticalDiagnosticRedactor(redact: DiagnosticRedactor, critical: DiagnosticRedactor, structured?: DiagnosticRedactor, isSuppressed?: () => boolean): void;
39
+ export declare function isDiagnosticRedactionSuppressed(redact?: DiagnosticRedactor): boolean;
40
+ /** Typed values and keys still match known credentials, but never blanket suppression. */
41
+ export declare function diagnosticStructuredRedactor(redact?: DiagnosticRedactor): DiagnosticRedactor | undefined;
42
+ export declare function redactDiagnosticAttributeKey(key: string, redact?: DiagnosticRedactor): string;
43
+ export declare function redactCriticalDiagnosticText(text: string, redact?: DiagnosticRedactor): string;
44
+ export declare function diagnosticAttributeRedactor(key: string, redact?: DiagnosticRedactor): DiagnosticRedactor | undefined;
45
+ export declare function isDiagnosticBigintAttribute(attributes: object, key: string): boolean;
46
+ export declare function copyDiagnosticAttributeTypes<T extends Record<string, unknown>>(source: Record<string, unknown>, target: T): T;
47
+ /** Reserve existing keys so independently redacted names never drop an attribute. */
48
+ export declare function redactedKeyAllocator(keys: Iterable<string>): () => string;
49
+ export declare function isRedactedKey(key: string): boolean;