@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.
Files changed (150) hide show
  1. package/AUTHORING.md +25 -0
  2. package/CHANGELOG.md +8 -0
  3. package/README.md +18 -2
  4. package/bin/apifuse-dev.ts +2 -1
  5. package/bin/apifuse-pack-types.ts +49 -0
  6. package/bin/apifuse-perf.ts +41 -4
  7. package/bin/apifuse-record.ts +9 -2
  8. package/dist/cli/templates/provider/README.md.tpl +15 -3
  9. package/dist/config/loader.d.ts +7 -0
  10. package/dist/config/loader.js +43 -18
  11. package/dist/declaration-validation.d.ts +2 -1
  12. package/dist/declaration-validation.js +39 -0
  13. package/dist/define.d.ts +4 -4
  14. package/dist/define.js +25 -1
  15. package/dist/engine.d.ts +16 -0
  16. package/dist/engine.js +59 -3
  17. package/dist/error-resolution.js +13 -0
  18. package/dist/index.d.ts +7 -4
  19. package/dist/index.js +4 -2
  20. package/dist/lint.js +38 -17
  21. package/dist/provider.d.ts +3 -3
  22. package/dist/provider.js +2 -2
  23. package/dist/runtime/bounded-expiring-map.d.ts +21 -0
  24. package/dist/runtime/bounded-expiring-map.js +64 -0
  25. package/dist/runtime/browser.js +2 -1
  26. package/dist/runtime/cache.d.ts +2 -0
  27. package/dist/runtime/cache.js +11 -3
  28. package/dist/runtime/diagnostic-env-values.d.ts +5 -0
  29. package/dist/runtime/diagnostic-env-values.js +57 -0
  30. package/dist/runtime/diagnostic-env.d.ts +11 -0
  31. package/dist/runtime/diagnostic-env.js +35 -0
  32. package/dist/runtime/diagnostic-redactor.d.ts +49 -0
  33. package/dist/runtime/diagnostic-redactor.js +569 -0
  34. package/dist/runtime/egress-lease.d.ts +65 -0
  35. package/dist/runtime/egress-lease.js +236 -0
  36. package/dist/runtime/env.js +2 -1
  37. package/dist/runtime/http.js +1 -0
  38. package/dist/runtime/instrumentation.js +3 -0
  39. package/dist/runtime/ocr.js +2 -1
  40. package/dist/runtime/otlp.js +5 -4
  41. package/dist/runtime/proxy-nodemaven.js +3 -2
  42. package/dist/runtime/proxy-retry-policy.d.ts +4 -1
  43. package/dist/runtime/proxy-retry-policy.js +11 -2
  44. package/dist/runtime/request-options.d.ts +7 -0
  45. package/dist/runtime/request-options.js +62 -22
  46. package/dist/runtime/request-telemetry.d.ts +7 -9
  47. package/dist/runtime/resolver-config.d.ts +7 -0
  48. package/dist/runtime/resolver-config.js +8 -0
  49. package/dist/runtime/resolver-public.d.ts +3 -1
  50. package/dist/runtime/resolver-public.js +1 -1
  51. package/dist/runtime/resolver-shared.d.ts +9 -0
  52. package/dist/runtime/resolver-shared.js +57 -0
  53. package/dist/runtime/resolver-telemetry.d.ts +134 -0
  54. package/dist/runtime/resolver-telemetry.js +204 -0
  55. package/dist/runtime/resolver-usage.d.ts +24 -0
  56. package/dist/runtime/resolver-usage.js +60 -0
  57. package/dist/runtime/resolver-vendors/bindings.d.ts +5 -0
  58. package/dist/runtime/resolver-vendors/bindings.js +5 -0
  59. package/dist/runtime/resolver-vendors/browser.js +0 -1
  60. package/dist/runtime/resolver-vendors/capsolver.d.ts +2 -2
  61. package/dist/runtime/resolver-vendors/capsolver.js +21 -9
  62. package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
  63. package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
  64. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -2
  65. package/dist/runtime/resolver-vendors/twocaptcha.js +26 -10
  66. package/dist/runtime/resolver-vendors/types.d.ts +35 -5
  67. package/dist/runtime/resolver-vendors/types.js +20 -10
  68. package/dist/runtime/resolver.d.ts +5 -1
  69. package/dist/runtime/resolver.js +400 -111
  70. package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
  71. package/dist/runtime/stealth-akamai-sbsd.js +142 -0
  72. package/dist/runtime/stealth.js +547 -53
  73. package/dist/runtime/stt.js +3 -2
  74. package/dist/runtime/trace.d.ts +5 -0
  75. package/dist/runtime/trace.js +115 -20
  76. package/dist/schema.d.ts +20 -0
  77. package/dist/schema.js +72 -2
  78. package/dist/server/index.d.ts +2 -0
  79. package/dist/server/index.js +1 -0
  80. package/dist/server/self-test-redaction.js +8 -33
  81. package/dist/server/self-test.d.ts +4 -0
  82. package/dist/server/self-test.js +10 -1
  83. package/dist/server/sensitive-values.d.ts +26 -0
  84. package/dist/server/sensitive-values.js +131 -0
  85. package/dist/server/serve-implementation.d.ts +7 -1
  86. package/dist/server/serve-implementation.js +394 -125
  87. package/dist/server/trace-output.d.ts +2 -1
  88. package/dist/server/trace-output.js +46 -14
  89. package/dist/server/types.d.ts +6 -0
  90. package/dist/server/types.js +14 -0
  91. package/dist/stealth/profiles.d.ts +7 -1
  92. package/dist/stealth/profiles.js +9 -0
  93. package/dist/testing/run.js +6 -0
  94. package/dist/trace-sanitization.d.ts +4 -3
  95. package/dist/trace-sanitization.js +45 -22
  96. package/dist/types.d.ts +106 -10
  97. package/package.json +2 -1
  98. package/src/cli/templates/provider/README.md.tpl +15 -3
  99. package/src/config/loader.ts +47 -18
  100. package/src/declaration-validation.ts +47 -1
  101. package/src/define.ts +45 -3
  102. package/src/engine.ts +78 -3
  103. package/src/error-resolution.ts +13 -0
  104. package/src/index.ts +34 -1
  105. package/src/lint.ts +44 -18
  106. package/src/provider.ts +10 -0
  107. package/src/runtime/bounded-expiring-map.ts +67 -0
  108. package/src/runtime/browser.ts +2 -1
  109. package/src/runtime/cache.ts +13 -3
  110. package/src/runtime/diagnostic-env-values.ts +56 -0
  111. package/src/runtime/diagnostic-env.ts +55 -0
  112. package/src/runtime/diagnostic-redactor.ts +662 -0
  113. package/src/runtime/egress-lease.ts +341 -0
  114. package/src/runtime/env.ts +2 -1
  115. package/src/runtime/http.ts +1 -0
  116. package/src/runtime/instrumentation.ts +3 -0
  117. package/src/runtime/ocr.ts +2 -1
  118. package/src/runtime/otlp.ts +5 -4
  119. package/src/runtime/proxy-nodemaven.ts +3 -2
  120. package/src/runtime/proxy-retry-policy.ts +12 -1
  121. package/src/runtime/request-options.ts +76 -28
  122. package/src/runtime/request-telemetry.ts +5 -7
  123. package/src/runtime/resolver-config.ts +12 -0
  124. package/src/runtime/resolver-public.ts +21 -0
  125. package/src/runtime/resolver-shared.ts +75 -0
  126. package/src/runtime/resolver-telemetry.ts +362 -0
  127. package/src/runtime/resolver-usage.ts +96 -0
  128. package/src/runtime/resolver-vendors/bindings.ts +5 -0
  129. package/src/runtime/resolver-vendors/browser.ts +0 -1
  130. package/src/runtime/resolver-vendors/capsolver.ts +22 -3
  131. package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
  132. package/src/runtime/resolver-vendors/twocaptcha.ts +26 -12
  133. package/src/runtime/resolver-vendors/types.ts +60 -12
  134. package/src/runtime/resolver.ts +468 -126
  135. package/src/runtime/stealth-akamai-sbsd.ts +207 -0
  136. package/src/runtime/stealth.ts +727 -95
  137. package/src/runtime/stt.ts +3 -2
  138. package/src/runtime/trace.ts +168 -26
  139. package/src/schema.ts +80 -2
  140. package/src/server/index.ts +21 -0
  141. package/src/server/self-test-redaction.ts +10 -40
  142. package/src/server/self-test.ts +13 -0
  143. package/src/server/sensitive-values.ts +200 -0
  144. package/src/server/serve-implementation.ts +561 -136
  145. package/src/server/trace-output.ts +77 -17
  146. package/src/server/types.ts +14 -0
  147. package/src/stealth/profiles.ts +10 -0
  148. package/src/testing/run.ts +6 -0
  149. package/src/trace-sanitization.ts +70 -23
  150. package/src/types.ts +124 -19
@@ -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);
@@ -465,12 +466,17 @@ export function createProviderCache(options) {
465
466
  },
466
467
  };
467
468
  }
469
+ const bypassCaches = new WeakSet();
470
+ /** Internal cache capability, separate from hit/miss metadata. */
471
+ export function isProviderCacheBypassed(cache) {
472
+ return bypassCaches.has(cache);
473
+ }
468
474
  export function createBypassProviderCache(options) {
469
- const configuredPepper = process.env[APIFUSE__CACHE__KEY_PEPPER_ENV];
475
+ const configuredPepper = readDiagnosticEnv(APIFUSE__CACHE__KEY_PEPPER_ENV);
470
476
  const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
471
477
  const events = [];
472
478
  const secretScopedKeys = new Set();
473
- return {
479
+ const cache = {
474
480
  key(namespace, parts, keyOptions) {
475
481
  const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
476
482
  const normalized = normalizeKeyPart(parts, extra, pepper);
@@ -510,6 +516,8 @@ export function createBypassProviderCache(options) {
510
516
  };
511
517
  },
512
518
  };
519
+ bypassCaches.add(cache);
520
+ return cache;
513
521
  }
514
522
  export function resetProviderCacheForTests() {
515
523
  for (const backend of sharedBackends.values()) {
@@ -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;