@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,5 +1,7 @@
1
- import { createHash } from "node:crypto";
1
+ import { STATUS_CODES } from "node:http";
2
+ import { readDiagnosticEnv, withDiagnosticEnv } from "../runtime/diagnostic-env.js";
2
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
+ import { createHash } from "node:crypto";
3
5
  import { existsSync } from "node:fs";
4
6
  import { createRequire } from "node:module";
5
7
  import { join } from "node:path";
@@ -8,15 +10,15 @@ import { Hono } from "hono";
8
10
  import { z } from "zod";
9
11
  import { AuthAbortError, createAuthFlowHelpers } from "../auth.js";
10
12
  import { validateFailClosedDeclaration } from "../declaration-validation.js";
11
- import { safeProviderErrorObservability } from "../error-observability.js";
12
13
  import {
13
14
  createInProcessProviderEngine,
14
15
  ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES,
15
16
  isEngineOwnedEnvName,
16
- readEngineProxyCredentials,
17
17
  type ProviderEngine,
18
18
  type ProviderEngineBindingCandidates,
19
+ readEngineProxyCredentials,
19
20
  } from "../engine.js";
21
+ import { safeProviderErrorObservability } from "../error-observability.js";
20
22
  import {
21
23
  SDK_OWNED_PROVIDER_ERROR_CODES,
22
24
  SDK_RUNTIME_OWNED_ERROR_CODES,
@@ -29,6 +31,7 @@ import {
29
31
  isTransportError,
30
32
  isValidationError,
31
33
  ProviderError,
34
+ SDKError,
32
35
  type ProviderErrorObservability,
33
36
  type ProviderErrorOptions,
34
37
  } from "../errors.js";
@@ -41,11 +44,11 @@ import {
41
44
  import type { ProviderLocale } from "../i18n/keys.js";
42
45
  import {
43
46
  categoryForStatus,
44
- type ProviderErrorSource,
45
- sourceForCategory,
46
47
  isRetryableCategory,
47
48
  PROVIDER_OBSERVABILITY_TAXONOMY_VERSION,
48
49
  type ProviderErrorCategory,
50
+ type ProviderErrorSource,
51
+ sourceForCategory,
49
52
  } from "../observability.js";
50
53
  import { createScratchpad } from "../runtime/auth-flow.js";
51
54
  import type * as BrowserRuntimeModule from "../runtime/browser.js";
@@ -55,13 +58,30 @@ import {
55
58
  PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
56
59
  } from "../runtime/choice.js";
57
60
  import { createCredentialContext } from "../runtime/credential.js";
61
+ import {
62
+ bindDiagnosticSensitiveRegistry,
63
+ type CompiledDiagnosticSensitiveValues,
64
+ compileProcessDiagnosticSensitiveValues,
65
+ createDiagnosticRedactor,
66
+ type DiagnosticRedactor,
67
+ REDACTION_FAILED,
68
+ isDiagnosticRedactionSuppressed,
69
+ bindCriticalDiagnosticRedactor,
70
+ redactCriticalDiagnosticText,
71
+ redactDiagnosticText,
72
+ registerDiagnosticSensitiveValues,
73
+ } from "../runtime/diagnostic-redactor.js";
74
+ import {
75
+ createCeremonyEgressLeaseRuntime,
76
+ ENGINE_CEREMONY_EGRESS_LEASE,
77
+ } from "../runtime/egress-lease.js";
58
78
  import { createEnvContext } from "../runtime/env.js";
59
79
  import { executeOperation } from "../runtime/executor.js";
60
80
  import { createHttpClient } from "../runtime/http.js";
61
81
  import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
62
82
  import type * as NativeNetworkRuntimeModule from "../runtime/native-network.js";
63
- import { getProviderBaseUrl } from "../runtime/provider.js";
64
83
  import { createOcrClientFromEnv } from "../runtime/ocr.js";
84
+ import { getProviderBaseUrl } from "../runtime/provider.js";
65
85
  import {
66
86
  PROXY_AUTH_IP_DENIED_CODE,
67
87
  PROXY_EDGE_AUTH_REJECTED_CODE,
@@ -73,18 +93,24 @@ import {
73
93
  type ProxyTelemetryLogPayload,
74
94
  } from "../runtime/proxy-telemetry.js";
75
95
  import {
96
+ type ClosedEnum,
76
97
  closedEnum,
77
98
  RequestTelemetry,
78
- tenantOpaqueKeys,
79
- type ClosedEnum,
80
99
  type TenantNeutral,
81
100
  type TenantOpaqueKeys,
101
+ tenantOpaqueKeys,
82
102
  } from "../runtime/request-telemetry.js";
83
103
  import type * as ResolverRuntimeModule from "../runtime/resolver.js";
84
104
  import {
105
+ bindResolverTelemetry,
85
106
  createUnsupportedResolverClient,
107
+ inheritResolverTelemetryBinding,
86
108
  type ResolverSolveWithRecorder,
87
109
  } from "../runtime/resolver-shared.js";
110
+ import {
111
+ ResolverTelemetryCollector,
112
+ type ResolverTelemetryLogPayload,
113
+ } from "../runtime/resolver-telemetry.js";
88
114
  import {
89
115
  assertRequiredSecretsPresent,
90
116
  listMissingRequiredSecrets,
@@ -94,32 +120,34 @@ import {
94
120
  createProviderRuntimeStateFromEnv,
95
121
  createUnsupportedProviderRuntimeState,
96
122
  } from "../runtime/state.js";
97
- import { StealthCookieJar } from "../runtime/stealth-cookies.js";
98
123
  import type * as StealthRuntimeModule from "../runtime/stealth.js";
124
+ import type { StealthChallengeRuntime } from "../runtime/stealth-akamai-sbsd.js";
125
+ import { StealthCookieJar } from "../runtime/stealth-cookies.js";
99
126
  import { createSttClientFromEnv } from "../runtime/stt.js";
100
127
  import {
101
128
  createTraceContext,
129
+ getTraceRecorder,
102
130
  type TraceContext as RuntimeTraceContext,
103
131
  type TraceRecorder,
104
132
  updateTraceContextExportMetadata,
105
133
  } from "../runtime/trace.js";
106
134
  import { resolveTraceConfigFromEnv } from "../runtime/trace-config.js";
107
135
  import { parseSchema } from "../schema.js";
136
+ import { StatefulRoutingDeadlineError } from "../stateful/errors.js";
108
137
  import {
109
138
  STATEFUL_NONCE_HEADER as STATEFUL_FORWARDING_NONCE_HEADER,
110
139
  STATEFUL_SIGNATURE_HEADER as STATEFUL_FORWARDING_SIGNATURE_HEADER,
111
140
  STATEFUL_TIMESTAMP_HEADER as STATEFUL_FORWARDING_TIMESTAMP_HEADER,
112
141
  verifyStatefulRequestSignature,
113
142
  } from "../stateful-signing.js";
114
- import { StatefulRoutingDeadlineError } from "../stateful/errors.js";
115
143
  import { getStealthProfile } from "../stealth/profiles.js";
116
- import { sanitizeTraceAttributes } from "../trace-sanitization.js";
117
144
  import {
118
145
  APIFUSE_STREAM_DONE_EVENT,
119
146
  APIFUSE_STREAM_ERROR_EVENT,
120
147
  encodeSseEvent,
121
148
  error as streamError,
122
149
  } from "../stream.js";
150
+ import { sanitizeSpanNameForOutput, sanitizeTraceAttributes } from "../trace-sanitization.js";
123
151
  import type {
124
152
  AuthContext,
125
153
  AuthTurn,
@@ -127,15 +155,15 @@ import type {
127
155
  FlowContext,
128
156
  FlowContextStore,
129
157
  HttpRetrySummary,
158
+ OcrContext,
130
159
  OperationDefinition,
131
160
  OperationErrorCode,
132
161
  OperationHttpStreamTransport,
133
162
  OperationSseTransport,
134
- OcrContext,
135
- ProviderErrorStatus,
136
- ProviderContext,
137
163
  ProviderCacheResponseMeta,
164
+ ProviderContext,
138
165
  ProviderDefinition,
166
+ ProviderErrorStatus,
139
167
  ProviderFilesContext,
140
168
  ProviderProxyPolicy,
141
169
  ProviderRuntimeState,
@@ -149,6 +177,10 @@ import type {
149
177
  import { VALID_OPERATION_ERROR_STATUSES } from "../types.js";
150
178
  import type { SelfTestCancellationLogEvent } from "./self-test.js";
151
179
  import { resolveSelfTestMasterSecrets } from "./self-test-token.js";
180
+ import {
181
+ collectStaticDiagnosticSensitiveValues,
182
+ createDiagnosticEnvObserver,
183
+ } from "./sensitive-values.js";
152
184
  import { resolveServerTraceContextOptions } from "./trace-output.js";
153
185
  import {
154
186
  type AuthFlowRequest,
@@ -294,9 +326,7 @@ export type ProviderServerOperationExecutorInput<
294
326
 
295
327
  export type ProviderServerOperationExecutor<
296
328
  TContext extends Partial<ProviderContext> = ProviderContext,
297
- > = (
298
- input: ProviderServerOperationExecutorInput<TContext>,
299
- ) => Promise<unknown>;
329
+ > = (input: ProviderServerOperationExecutorInput<TContext>) => Promise<unknown>;
300
330
 
301
331
  type RequestTerminalOutcome =
302
332
  | { kind: "completed"; status: number }
@@ -304,6 +334,7 @@ type RequestTerminalOutcome =
304
334
  | { kind: "cancelled"; status?: number };
305
335
 
306
336
  type RequestStreamLifecycle = {
337
+ redact: DiagnosticRedactor;
307
338
  runStep<T>(fn: () => Promise<T>): Promise<T>;
308
339
  registerCleanup(cleanup: () => void | Promise<void>): void;
309
340
  terminalize(outcome: RequestTerminalOutcome): void;
@@ -513,6 +544,9 @@ function createLazyStealthClient(
513
544
  async fetch(...args) {
514
545
  return (await getSession()).fetch(...args);
515
546
  },
547
+ async replayChallenged(...args) {
548
+ return (await getSession()).replayChallenged(...args);
549
+ },
516
550
  redirects: {
517
551
  async run(...args) {
518
552
  return (await getSession()).redirects.run(...args);
@@ -553,7 +587,7 @@ function bindResolverSignalWithoutRuntime(
553
587
  defaultSignal: AbortSignal | undefined,
554
588
  ): ResolverContext {
555
589
  if (!defaultSignal) return resolver;
556
- return {
590
+ const boundResolver: ResolverContext = {
557
591
  solve(challenge, signal = defaultSignal, traceRecorder?: TraceRecorder) {
558
592
  // Forward the instrumentation trace recorder so resolver.vendor.* spans
559
593
  // survive this wrapper. See ResolverSolveWithRecorder in resolver-shared.ts.
@@ -564,6 +598,8 @@ function bindResolverSignalWithoutRuntime(
564
598
  );
565
599
  },
566
600
  };
601
+ inheritResolverTelemetryBinding(resolver, boundResolver);
602
+ return boundResolver;
567
603
  }
568
604
 
569
605
  function getProviderStealthBaseUrl(provider: ProviderDefinition): string | undefined {
@@ -579,6 +615,99 @@ function getProviderStealthProfile(provider: ProviderDefinition) {
579
615
  return provider.stealth ? getStealthProfile(provider.stealth) : undefined;
580
616
  }
581
617
 
618
+ type ResolverRuntimeOptions = ResolverRuntimeModule.ResolverRuntimeOptions;
619
+
620
+ /** One option set for ctx.resolver and the automatic SBSD solve, so both share identity scope, cache, proxy intent, and telemetry. */
621
+ function createResolverRuntimeOptions(
622
+ provider: ProviderDefinition,
623
+ cache: ReturnType<typeof createProviderCache>,
624
+ identityScope: string,
625
+ proxyPolicy: ProviderProxyPolicy | undefined,
626
+ proxyClientOptions: Omit<
627
+ NonNullable<ResolverRuntimeOptions["proxyIntent"]>,
628
+ "mode" | "userAgent"
629
+ >,
630
+ stealthProfile: { readonly userAgent: string } | undefined,
631
+ telemetry: ResolverTelemetryCollector,
632
+ ): ResolverRuntimeOptions {
633
+ return {
634
+ allowedHosts: provider.allowedHosts,
635
+ cache,
636
+ telemetry,
637
+ identityScope,
638
+ ...(proxyPolicy
639
+ ? {
640
+ proxyIntent: {
641
+ mode: proxyPolicy.mode,
642
+ ...proxyClientOptions,
643
+ ...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
644
+ },
645
+ }
646
+ : {}),
647
+ };
648
+ }
649
+
650
+ /** Shared predicate for the SBSD challenge runtime and the ceremony egress lease. */
651
+ function declaresAkamaiSbsdResolver(provider: ProviderDefinition): boolean {
652
+ return provider.resolver?.kinds.some((kind) => kind === "akamai_sbsd") === true;
653
+ }
654
+
655
+ function createStealthChallengeDetection(
656
+ provider: ProviderDefinition,
657
+ resolverRuntime: typeof ResolverRuntimeModule | undefined,
658
+ resolverOverride: ResolverContext | undefined,
659
+ resolverOptions: ResolverRuntimeOptions,
660
+ trace: RuntimeTraceContext,
661
+ signal: AbortSignal | undefined,
662
+ ): StealthChallengeRuntime | undefined {
663
+ const resolverDeclared = declaresAkamaiSbsdResolver(provider);
664
+ const detectOnly = provider.stealth?.challengeDetection?.akamaiSbsd === true;
665
+ if (!resolverDeclared && !detectOnly) {
666
+ return undefined;
667
+ }
668
+ return {
669
+ akamaiSbsd: {
670
+ allowedHosts: provider.allowedHosts ?? [],
671
+ // The profile belongs to the SBSD resolver; a resolver declared for other kinds
672
+ // may name a different browser without affecting detect-only classification.
673
+ ...(resolverDeclared && provider.resolver?.clientProfile
674
+ ? { clientProfile: provider.resolver.clientProfile }
675
+ : {}),
676
+ ...(resolverDeclared && resolverRuntime
677
+ ? {
678
+ async solve(challenge, transport, solveSignal) {
679
+ const resolver = resolverRuntime.bindResolverSignal(
680
+ (resolverOverride
681
+ ? bindResolverTelemetry(resolverOverride, resolverOptions.telemetry)
682
+ : undefined) ??
683
+ resolverRuntime.createResolverClientFromEnv(provider.resolver, undefined, {
684
+ allowedHosts: resolverOptions.allowedHosts,
685
+ cache: resolverOptions.cache,
686
+ telemetry: resolverOptions.telemetry,
687
+ identityScope: resolverOptions.identityScope,
688
+ // No proxyIntent: the transport is already bound to the initiating
689
+ // request's lease, and a second identity resolution would allocate
690
+ // again (and fail closed without allocator credentials) for nothing
691
+ // the SBSD adapters consume.
692
+ createTransport: () => transport,
693
+ }),
694
+ signal,
695
+ ) as ResolverContext & Partial<ResolverSolveWithRecorder>;
696
+ // Same span and recorder threading as the instrumented ctx.resolver.solve.
697
+ const recorder = getTraceRecorder(trace);
698
+ const solve = () => resolver.solve(challenge, solveSignal, recorder ?? undefined);
699
+ return recorder
700
+ ? recorder.runSpan("resolver.solve", solve, {
701
+ attributes: { challenge_kind: challenge.kind },
702
+ })
703
+ : solve();
704
+ },
705
+ }
706
+ : {}),
707
+ },
708
+ };
709
+ }
710
+
582
711
  function isProductionProviderBrowserMode(provider: ProviderDefinition, env = process.env): boolean {
583
712
  if (provider.runtime !== "browser") {
584
713
  return false;
@@ -712,8 +841,10 @@ function providerSecretNames(provider: ProviderDefinition): string[] {
712
841
  }
713
842
 
714
843
  type RequestScopeContext = {
844
+ redact: DiagnosticRedactor;
715
845
  trace: RuntimeTraceContext;
716
846
  telemetry: RequestTelemetry;
847
+ resolverTelemetry: ResolverTelemetryCollector;
717
848
  };
718
849
 
719
850
  function createProviderContext(
@@ -741,16 +872,43 @@ function createProviderContext(
741
872
  proxyClientOptions.affinityKey,
742
873
  request.requestId,
743
874
  );
875
+ const cache = createProviderCache({ providerId: provider.id });
744
876
  let wrappedContext: ProviderContext | undefined;
877
+ const { capabilityModules } = options;
878
+ const resolverOptions = createResolverRuntimeOptions(
879
+ provider,
880
+ cache,
881
+ resolverIdentityScope,
882
+ proxyPolicy,
883
+ proxyClientOptions,
884
+ stealthProfile,
885
+ scope.resolverTelemetry,
886
+ );
887
+ const challengeRuntime = createStealthChallengeDetection(
888
+ provider,
889
+ capabilityModules.resolver,
890
+ options.resolver,
891
+ resolverOptions,
892
+ scope.trace,
893
+ signal,
894
+ );
745
895
  const stealthClientOptions = {
746
896
  upstream: proxyClientOptions.upstream,
747
897
  affinityKey: proxyClientOptions.affinityKey,
748
898
  telemetry: scope.telemetry.proxy,
749
899
  engineCredentials: engineProxyCredentials,
750
900
  ...(signal ? { signal } : {}),
751
- ...(provider.stealth ? { stealth: provider.stealth } : {}),
901
+ // A declared resolver without a `stealth` block still gets the default Chrome client
902
+ // (auth FlowContext is not capability-gated), so the runtime must ride along.
903
+ ...(provider.stealth || challengeRuntime
904
+ ? {
905
+ stealth: {
906
+ ...(provider.stealth ?? {}),
907
+ ...(challengeRuntime ? { challengeRuntime } : {}),
908
+ },
909
+ }
910
+ : {}),
752
911
  };
753
- const { capabilityModules } = options;
754
912
  const logStealthCleanupError = (error: unknown) =>
755
913
  logProviderCleanupError(
756
914
  options.logger,
@@ -760,6 +918,7 @@ function createProviderContext(
760
918
  request.requestId,
761
919
  "stealth",
762
920
  error,
921
+ scope.redact,
763
922
  );
764
923
 
765
924
  const env = createEnvContext([
@@ -777,7 +936,6 @@ function createProviderContext(
777
936
  headers: request.headers ?? {},
778
937
  };
779
938
  const requestState = state.forConnection(requestContext.connectionId);
780
- const cache = createProviderCache({ providerId: provider.id });
781
939
  const bindings: ProviderEngineBindingCandidates = {
782
940
  env,
783
941
  credential,
@@ -802,7 +960,7 @@ function createProviderContext(
802
960
  provider.runtime === "browser"
803
961
  ? capabilityModules.browser!.createBrowserClient({
804
962
  allowedHosts: provider.allowedHosts,
805
- cdpUrl: process.env.APIFUSE__CDP_POOL__URL,
963
+ cdpUrl: readDiagnosticEnv("APIFUSE__CDP_POOL__URL"),
806
964
  headless: true,
807
965
  requireCdpPool: isProductionProviderBrowserMode(provider),
808
966
  stealth: true,
@@ -829,25 +987,20 @@ function createProviderContext(
829
987
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
830
988
  resolver: capabilityModules.resolver
831
989
  ? capabilityModules.resolver.bindResolverSignal(
832
- options.resolver ??
833
- capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, {
834
- allowedHosts: provider.allowedHosts,
835
- cache,
836
- identityScope: resolverIdentityScope,
837
- ...(proxyPolicy
838
- ? {
839
- proxyIntent: {
840
- mode: proxyPolicy.mode,
841
- ...proxyClientOptions,
842
- ...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
843
- },
844
- }
845
- : {}),
846
- }),
990
+ (options.resolver
991
+ ? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
992
+ : undefined) ??
993
+ capabilityModules.resolver.createResolverClientFromEnv(
994
+ provider.resolver,
995
+ undefined,
996
+ resolverOptions,
997
+ ),
847
998
  signal,
848
999
  )
849
1000
  : bindResolverSignalWithoutRuntime(
850
- options.resolver ??
1001
+ (options.resolver
1002
+ ? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
1003
+ : undefined) ??
851
1004
  createUnsupportedResolverClient("Provider does not declare resolver capability"),
852
1005
  signal,
853
1006
  ),
@@ -927,6 +1080,7 @@ export function resolveAuthFlowProxyAffinityKey(
927
1080
  function createAuthFlowContext(
928
1081
  provider: ProviderDefinition,
929
1082
  request: AuthFlowRequest,
1083
+ route: AuthRoute,
930
1084
  options: ProviderServerRuntimeOptions,
931
1085
  state: ProviderRuntimeState,
932
1086
  scope: RequestScopeContext,
@@ -934,6 +1088,7 @@ function createAuthFlowContext(
934
1088
  ): {
935
1089
  context: FlowContext;
936
1090
  getPatch: () => Record<string, unknown | null> | undefined;
1091
+ getEngineState: () => AuthFlowSuccessResponse["engine"];
937
1092
  } {
938
1093
  const baseUrl = getProviderBaseUrl(provider);
939
1094
  const stealthBaseUrl = getProviderStealthBaseUrl(provider);
@@ -951,20 +1106,73 @@ function createAuthFlowContext(
951
1106
  telemetry: scope.telemetry.proxy,
952
1107
  engineCredentials: engineProxyCredentials,
953
1108
  };
1109
+ // The lease pins the proxy egress a challenged ceremony solved on, so only providers
1110
+ // that declare the akamai_sbsd resolver kind carry one (same predicate as the challenge
1111
+ // runtime). `abort` never evaluates the key or tenant: a user must be able to cancel a
1112
+ // stranded flow even when engine provisioning is broken, and an abort is not a
1113
+ // continuation of the ceremony the lease pins.
1114
+ const ceremonyEgressLease =
1115
+ route !== "abort" &&
1116
+ declaresAkamaiSbsdResolver(provider) &&
1117
+ proxyPolicy &&
1118
+ proxyPolicy.mode !== "disabled"
1119
+ ? createCeremonyEgressLeaseRuntime({
1120
+ tenantId: request.tenantId,
1121
+ providerId: provider.id,
1122
+ flowId: request.flowId,
1123
+ affinityKey: proxyClientOptions.affinityKey,
1124
+ onHandle: (handle) => registerDiagnosticSensitiveValues(scope.trace, [handle]),
1125
+ ...(request.engine?.egressLease ? { handle: request.engine.egressLease } : {}),
1126
+ })
1127
+ : undefined;
1128
+ if (route !== "abort" && request.engine?.egressLease && !ceremonyEgressLease) {
1129
+ throw new SDKError(
1130
+ "An egress lease was supplied for an auth flow that does not use a ceremony lease",
1131
+ { code: "EGRESS_LEASE_INVALID" },
1132
+ );
1133
+ }
954
1134
  const resolverIdentityScope = resolveProviderResolverIdentityScope(
955
1135
  provider,
956
1136
  proxyClientOptions.affinityKey,
957
1137
  request.requestId,
958
1138
  );
1139
+ const cache = createProviderCache({ providerId: provider.id });
1140
+ const { capabilityModules } = options;
1141
+ const resolverOptions = createResolverRuntimeOptions(
1142
+ provider,
1143
+ cache,
1144
+ resolverIdentityScope,
1145
+ proxyPolicy,
1146
+ proxyClientOptions,
1147
+ stealthProfile,
1148
+ scope.resolverTelemetry,
1149
+ );
1150
+ const challengeRuntime = createStealthChallengeDetection(
1151
+ provider,
1152
+ capabilityModules.resolver,
1153
+ options.resolver,
1154
+ resolverOptions,
1155
+ scope.trace,
1156
+ signal,
1157
+ );
959
1158
  const stealthClientOptions = {
960
1159
  upstream: proxyClientOptions.upstream,
961
1160
  affinityKey: proxyClientOptions.affinityKey,
962
1161
  telemetry: scope.telemetry.proxy,
963
1162
  engineCredentials: engineProxyCredentials,
1163
+ ...(ceremonyEgressLease ? { [ENGINE_CEREMONY_EGRESS_LEASE]: ceremonyEgressLease } : {}),
964
1164
  ...(signal ? { signal } : {}),
965
- ...(provider.stealth ? { stealth: provider.stealth } : {}),
1165
+ // A declared resolver without a `stealth` block still gets the default Chrome client
1166
+ // (auth FlowContext is not capability-gated), so the runtime must ride along.
1167
+ ...(provider.stealth || challengeRuntime
1168
+ ? {
1169
+ stealth: {
1170
+ ...(provider.stealth ?? {}),
1171
+ ...(challengeRuntime ? { challengeRuntime } : {}),
1172
+ },
1173
+ }
1174
+ : {}),
966
1175
  };
967
- const { capabilityModules } = options;
968
1176
  const logStealthCleanupError = (error: unknown) =>
969
1177
  logProviderCleanupError(
970
1178
  options.logger,
@@ -974,6 +1182,7 @@ function createAuthFlowContext(
974
1182
  request.requestId,
975
1183
  "stealth",
976
1184
  error,
1185
+ scope.redact,
977
1186
  );
978
1187
  const credential = request.connection
979
1188
  ? createCredentialContext({
@@ -983,8 +1192,6 @@ function createAuthFlowContext(
983
1192
  values: request.connection.secrets,
984
1193
  })
985
1194
  : undefined;
986
- const cache = createProviderCache({ providerId: provider.id });
987
-
988
1195
  const context: FlowContext = wrapWithInstrumentation({
989
1196
  flowId: request.flowId,
990
1197
  connectionId: resolveOperationConnectionId(request),
@@ -1026,25 +1233,20 @@ function createAuthFlowContext(
1026
1233
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
1027
1234
  resolver: capabilityModules.resolver
1028
1235
  ? capabilityModules.resolver.bindResolverSignal(
1029
- options.resolver ??
1030
- capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, {
1031
- allowedHosts: provider.allowedHosts,
1032
- cache,
1033
- identityScope: resolverIdentityScope,
1034
- ...(proxyPolicy
1035
- ? {
1036
- proxyIntent: {
1037
- mode: proxyPolicy.mode,
1038
- ...proxyClientOptions,
1039
- ...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
1040
- },
1041
- }
1042
- : {}),
1043
- }),
1236
+ (options.resolver
1237
+ ? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
1238
+ : undefined) ??
1239
+ capabilityModules.resolver.createResolverClientFromEnv(
1240
+ provider.resolver,
1241
+ undefined,
1242
+ resolverOptions,
1243
+ ),
1044
1244
  signal,
1045
1245
  )
1046
1246
  : bindResolverSignalWithoutRuntime(
1047
- options.resolver ??
1247
+ (options.resolver
1248
+ ? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
1249
+ : undefined) ??
1048
1250
  createUnsupportedResolverClient("Provider does not declare resolver capability"),
1049
1251
  signal,
1050
1252
  ),
@@ -1054,6 +1256,10 @@ function createAuthFlowContext(
1054
1256
  return {
1055
1257
  context,
1056
1258
  getPatch: flowContextStore.getPatch,
1259
+ getEngineState() {
1260
+ const egressLease = ceremonyEgressLease?.handle();
1261
+ return egressLease ? { egressLease } : undefined;
1262
+ },
1057
1263
  };
1058
1264
  }
1059
1265
 
@@ -1082,6 +1288,7 @@ type ProviderServerLogEventBase = ProviderRequestCost & {
1082
1288
  requestedProviderId?: string;
1083
1289
  status: number;
1084
1290
  proxy?: ProxyTelemetryLogPayload;
1291
+ resolver?: ResolverTelemetryLogPayload;
1085
1292
  };
1086
1293
 
1087
1294
  export type ProviderServerLogEvent =
@@ -1167,7 +1374,11 @@ export type ProviderServerOptions<TContext extends Partial<ProviderContext> = Pr
1167
1374
  stt?: SttContext;
1168
1375
  /** Optional OCR override for tests or custom hosts; local/prod normally resolves from env. */
1169
1376
  ocr?: OcrContext;
1170
- /** Optional resolver override for tests or custom hosts; local/prod normally resolves from env. */
1377
+ /**
1378
+ * Optional resolver override for tests or custom hosts; local/prod normally resolves from env.
1379
+ * SDK chains are reconstructed with each request's telemetry sink. An opaque host
1380
+ * resolver is reported as one custom invocation; its internal vendor work is not exposed.
1381
+ */
1171
1382
  resolver?: ResolverContext;
1172
1383
  /** Optional runtime state override for tests or custom hosts. Production resolves Redis from env and fails closed when unavailable. */
1173
1384
  state?: ProviderRuntimeState;
@@ -1229,15 +1440,18 @@ function finishRequestCost(input: {
1229
1440
  };
1230
1441
  }
1231
1442
 
1232
- function zodDetails(error: z.ZodError): Array<{
1443
+ function zodDetails(
1444
+ error: z.ZodError,
1445
+ redact?: DiagnosticRedactor,
1446
+ ): Array<{
1233
1447
  path: string;
1234
1448
  code: string;
1235
1449
  message: string;
1236
1450
  }> {
1237
1451
  return error.issues.map((issue) => ({
1238
- path: issue.path.join("."),
1239
- code: issue.code,
1240
- message: issue.message,
1452
+ path: sanitizeSpanNameForOutput(issue.path.join("."), redact),
1453
+ code: sanitizeSpanNameForOutput(issue.code, redact),
1454
+ message: sanitizeSpanNameForOutput(issue.message, redact),
1241
1455
  }));
1242
1456
  }
1243
1457
 
@@ -1264,6 +1478,7 @@ function toErrorResponse(
1264
1478
  error: unknown,
1265
1479
  requestId: string | undefined,
1266
1480
  observabilityDetails: ErrorObservabilityDetails,
1481
+ redact?: DiagnosticRedactor,
1267
1482
  ): OperationErrorResponse {
1268
1483
  const observability = observabilityDetails;
1269
1484
  const source = publicErrorSource(error, observability.category);
@@ -1302,7 +1517,7 @@ function toErrorResponse(
1302
1517
  ...(requestId ? { requestId } : {}),
1303
1518
  retryable: observability.retryable,
1304
1519
  source,
1305
- details: zodDetails(error),
1520
+ details: zodDetails(error, redact),
1306
1521
  },
1307
1522
  };
1308
1523
  }
@@ -1598,14 +1813,17 @@ export type ProviderErrorCauseFrame = {
1598
1813
  const MAX_PROVIDER_ERROR_CAUSE_FRAMES = 5;
1599
1814
  const MAX_PROVIDER_ERROR_CAUSE_MESSAGE_LENGTH = 300;
1600
1815
 
1601
- function providerErrorCauseMessage(message: string): string {
1602
- const sanitized = sanitizeDiagnosticText(message);
1816
+ function providerErrorCauseMessage(message: string, redact?: DiagnosticRedactor): string {
1817
+ const sanitized = sanitizeDiagnosticText(redactDiagnosticText(message, redact));
1603
1818
  return sanitized.length > MAX_PROVIDER_ERROR_CAUSE_MESSAGE_LENGTH
1604
1819
  ? `${sanitized.slice(0, MAX_PROVIDER_ERROR_CAUSE_MESSAGE_LENGTH)}… [truncated]`
1605
1820
  : sanitized;
1606
1821
  }
1607
1822
 
1608
- function providerErrorCauseChain(error: unknown): ProviderErrorCauseFrame[] | undefined {
1823
+ function providerErrorCauseChain(
1824
+ error: unknown,
1825
+ redact?: DiagnosticRedactor,
1826
+ ): ProviderErrorCauseFrame[] | undefined {
1609
1827
  if (!(error instanceof Error) && !isProviderError(error)) return undefined;
1610
1828
 
1611
1829
  const seen = new Set<object>([error]);
@@ -1622,9 +1840,9 @@ function providerErrorCauseChain(error: unknown): ProviderErrorCauseFrame[] | un
1622
1840
  const providerObservability = safeProviderErrorObservability(cause);
1623
1841
  const causeCode = providerErrorCode(cause);
1624
1842
  frames.push({
1625
- errorClass: cause.name,
1626
- ...(causeCode !== undefined ? { code: causeCode } : {}),
1627
- message: providerErrorCauseMessage(message),
1843
+ errorClass: redactDiagnosticText(cause.name, redact),
1844
+ ...(causeCode !== undefined ? { code: redactDiagnosticText(causeCode, redact) } : {}),
1845
+ message: providerErrorCauseMessage(message, redact),
1628
1846
  messageLength: message.length,
1629
1847
  messageFingerprint: createHash("sha256").update(message).digest("hex").slice(0, 12),
1630
1848
  ...(providerObservability ? { providerObservability } : {}),
@@ -1648,6 +1866,7 @@ function logProviderError(
1648
1866
  telemetry: RequestTelemetry | undefined,
1649
1867
  observabilityDetails: ErrorObservabilityDetails,
1650
1868
  correlation: RequestCorrelationIds = {},
1869
+ redact?: DiagnosticRedactor,
1651
1870
  ): void {
1652
1871
  const providerCode = isProviderError(error) ? providerErrorCode(error) : undefined;
1653
1872
  const code = isProviderError(error)
@@ -1659,7 +1878,7 @@ function logProviderError(
1659
1878
  : "internal_error";
1660
1879
  const errorClass = error instanceof Error ? error.name : typeof error;
1661
1880
  const message = error instanceof Error ? error.message : String(error);
1662
- const causeChain = providerErrorCauseChain(error);
1881
+ const causeChain = providerErrorCauseChain(error, redact);
1663
1882
  const details = observabilityDetails;
1664
1883
  const isUnregisteredProviderErrorCode =
1665
1884
  status === 500 &&
@@ -1679,24 +1898,28 @@ function logProviderError(
1679
1898
  emit({
1680
1899
  level: status >= 500 ? "error" : "warn",
1681
1900
  event: "provider_request_failed",
1682
- providerId: provider.id,
1901
+ providerId: redactDiagnosticText(provider.id, redact),
1683
1902
  kind,
1684
- route,
1685
- ...(requestId ? { requestId } : {}),
1903
+ route: redactCriticalDiagnosticText(route, redact),
1904
+ ...(requestId ? { requestId: redactCriticalDiagnosticText(requestId, redact) } : {}),
1686
1905
  ...(correlation.connectionId !== undefined
1687
- ? { connectionId: correlation.connectionId }
1906
+ ? { connectionId: redactDiagnosticText(correlation.connectionId, redact) }
1907
+ : {}),
1908
+ ...(correlation.flowId !== undefined
1909
+ ? { flowId: redactDiagnosticText(correlation.flowId, redact) }
1910
+ : {}),
1911
+ ...(correlation.tenantId !== undefined
1912
+ ? { tenantId: redactDiagnosticText(correlation.tenantId, redact) }
1688
1913
  : {}),
1689
- ...(correlation.flowId !== undefined ? { flowId: correlation.flowId } : {}),
1690
- ...(correlation.tenantId !== undefined ? { tenantId: correlation.tenantId } : {}),
1691
1914
  ...(correlation.requestedProviderId !== undefined
1692
- ? { requestedProviderId: correlation.requestedProviderId }
1915
+ ? { requestedProviderId: redactDiagnosticText(correlation.requestedProviderId, redact) }
1693
1916
  : {}),
1694
1917
  status,
1695
1918
  ...cost,
1696
1919
  ...(telemetryPayload ?? {}),
1697
- code,
1698
- errorClass,
1699
- message,
1920
+ code: sanitizeSpanNameForOutput(redactCriticalDiagnosticText(code, redact)),
1921
+ errorClass: redactDiagnosticText(errorClass, redact),
1922
+ message: sanitizeDiagnosticText(redactDiagnosticText(message, redact)),
1700
1923
  ...(causeChain ? { causeChain } : {}),
1701
1924
  ...(providerObservability ? { providerObservability } : {}),
1702
1925
  ...(details.upstreamStatus ? { upstreamStatus: details.upstreamStatus } : {}),
@@ -1710,7 +1933,7 @@ function logProviderError(
1710
1933
  "Declare this code (with status and retryable) in the operation's errorCodes so it serves its intended status instead of 500.",
1711
1934
  }
1712
1935
  : {}),
1713
- ...(error instanceof z.ZodError ? { issues: zodDetails(error) } : {}),
1936
+ ...(error instanceof z.ZodError ? { issues: zodDetails(error, redact) } : {}),
1714
1937
  });
1715
1938
  }
1716
1939
 
@@ -1722,6 +1945,7 @@ function logProviderCleanupError(
1722
1945
  requestId: string | undefined,
1723
1946
  resource: "browser" | "stealth",
1724
1947
  error: unknown,
1948
+ redact?: DiagnosticRedactor,
1725
1949
  ): void {
1726
1950
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1727
1951
  const errorClass = error instanceof Error ? error.name : typeof error;
@@ -1729,13 +1953,13 @@ function logProviderCleanupError(
1729
1953
  emit({
1730
1954
  level: "warn",
1731
1955
  event: "provider_cleanup_failed",
1732
- providerId: provider.id,
1956
+ providerId: redactDiagnosticText(provider.id, redact),
1733
1957
  kind,
1734
- route: operationId,
1735
- ...(requestId ? { requestId } : {}),
1958
+ route: redactCriticalDiagnosticText(operationId, redact),
1959
+ ...(requestId ? { requestId: redactCriticalDiagnosticText(requestId, redact) } : {}),
1736
1960
  resource,
1737
- errorClass,
1738
- message,
1961
+ errorClass: redactDiagnosticText(errorClass, redact),
1962
+ message: sanitizeDiagnosticText(redactDiagnosticText(message, redact)),
1739
1963
  });
1740
1964
  }
1741
1965
 
@@ -1749,23 +1973,28 @@ function logProviderSuccess(
1749
1973
  cost: ProviderRequestCost,
1750
1974
  telemetry?: RequestTelemetry,
1751
1975
  correlation: RequestCorrelationIds = {},
1976
+ redact?: DiagnosticRedactor,
1752
1977
  ): void {
1753
1978
  const telemetryPayload = telemetry?.toLogPayload();
1754
1979
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1755
1980
  emit({
1756
1981
  level: "info",
1757
1982
  event: "provider_request_completed",
1758
- providerId: provider.id,
1983
+ providerId: redactDiagnosticText(provider.id, redact),
1759
1984
  kind,
1760
- route,
1761
- ...(requestId ? { requestId } : {}),
1985
+ route: redactCriticalDiagnosticText(route, redact),
1986
+ ...(requestId ? { requestId: redactCriticalDiagnosticText(requestId, redact) } : {}),
1762
1987
  ...(correlation.connectionId !== undefined
1763
- ? { connectionId: correlation.connectionId }
1988
+ ? { connectionId: redactDiagnosticText(correlation.connectionId, redact) }
1989
+ : {}),
1990
+ ...(correlation.flowId !== undefined
1991
+ ? { flowId: redactDiagnosticText(correlation.flowId, redact) }
1992
+ : {}),
1993
+ ...(correlation.tenantId !== undefined
1994
+ ? { tenantId: redactDiagnosticText(correlation.tenantId, redact) }
1764
1995
  : {}),
1765
- ...(correlation.flowId !== undefined ? { flowId: correlation.flowId } : {}),
1766
- ...(correlation.tenantId !== undefined ? { tenantId: correlation.tenantId } : {}),
1767
1996
  ...(correlation.requestedProviderId !== undefined
1768
- ? { requestedProviderId: correlation.requestedProviderId }
1997
+ ? { requestedProviderId: redactDiagnosticText(correlation.requestedProviderId, redact) }
1769
1998
  : {}),
1770
1999
  status,
1771
2000
  ...cost,
@@ -1779,6 +2008,7 @@ type RequestScopeFinishResult = {
1779
2008
  };
1780
2009
 
1781
2010
  type RequestScope = RequestScopeContext & {
2011
+ seedCredentials(rawBody: unknown, kind: "operation" | "auth" | "stateful"): void;
1782
2012
  enrich(input: {
1783
2013
  route?: string;
1784
2014
  requestId?: string;
@@ -1850,8 +2080,91 @@ function requestTraceId(
1850
2080
  );
1851
2081
  }
1852
2082
 
2083
+ /** Harvest only credential subtrees, iteratively and before schema diagnostics. */
2084
+ function rawRequestCredentials(
2085
+ rawBody: unknown,
2086
+ kind: "operation" | "auth" | "stateful",
2087
+ ): { values: string[]; exhausted: boolean } {
2088
+ const record = (value: unknown): Record<string, unknown> | undefined =>
2089
+ value !== null && typeof value === "object" ? (value as Record<string, unknown>) : undefined;
2090
+ const own = (value: unknown, key: string): unknown => {
2091
+ const object = record(value);
2092
+ return object && Object.hasOwn(object, key) ? object[key] : undefined;
2093
+ };
2094
+ const body = kind === "stateful" ? own(rawBody, "operationRequest") : rawBody;
2095
+ const values: string[] = [];
2096
+ let remainingBytes = 64 * 1024;
2097
+ let exhausted = false;
2098
+ const add = (value: unknown): void => {
2099
+ if (typeof value !== "string") return;
2100
+ const bytes = Buffer.byteLength(value, "utf8");
2101
+ if (bytes > remainingBytes) {
2102
+ exhausted = true;
2103
+ return;
2104
+ }
2105
+ remainingBytes -= bytes;
2106
+ if (value) values.push(value);
2107
+ const trimmed = value.trim();
2108
+ if (trimmed && trimmed !== value) values.push(trimmed);
2109
+ };
2110
+ function* entries(object: Record<string, unknown>) {
2111
+ for (const key in object) {
2112
+ if (Object.hasOwn(object, key)) yield [key, object[key]] as const;
2113
+ }
2114
+ }
2115
+ const visit = (root: unknown): void => {
2116
+ const object = record(root);
2117
+ if (!object) {
2118
+ add(root);
2119
+ return;
2120
+ }
2121
+ // Connection inventories are usually flat. Walk the root directly and only
2122
+ // allocate iterator frames when a nested credential container is encountered.
2123
+ for (const key in object) {
2124
+ if (!Object.hasOwn(object, key)) continue;
2125
+ const value = object[key];
2126
+ add(key);
2127
+ if (exhausted) break;
2128
+ const child = record(value);
2129
+ if (!child) {
2130
+ add(value);
2131
+ if (exhausted) break;
2132
+ continue;
2133
+ }
2134
+ const stack = [{ iterator: entries(child), depth: 1 }];
2135
+ while (stack.length && !exhausted) {
2136
+ const frame = stack[stack.length - 1];
2137
+ const entry = frame.iterator.next();
2138
+ if (entry.done) {
2139
+ stack.pop();
2140
+ continue;
2141
+ }
2142
+ const [key, value] = entry.value;
2143
+ add(key);
2144
+ if (exhausted) break;
2145
+ const child = record(value);
2146
+ if (child) {
2147
+ if (frame.depth >= 8) {
2148
+ exhausted = true;
2149
+ break;
2150
+ }
2151
+ stack.push({ iterator: entries(child), depth: frame.depth + 1 });
2152
+ } else add(value);
2153
+ }
2154
+ if (exhausted) break;
2155
+ }
2156
+ };
2157
+ visit(own(own(body, "connection"), "secrets"));
2158
+ if (kind === "auth" && !exhausted) {
2159
+ add(own(own(body, "engine"), "egressLease"));
2160
+ if (!exhausted) visit(own(body, "input"));
2161
+ }
2162
+ return { values, exhausted };
2163
+ }
2164
+
1853
2165
  function createRequestScope(input: {
1854
2166
  provider: ProviderDefinition;
2167
+ staticSensitiveValues: CompiledDiagnosticSensitiveValues;
1855
2168
  kind: "operation" | "auth";
1856
2169
  route: string;
1857
2170
  requestId?: string;
@@ -1863,8 +2176,25 @@ function createRequestScope(input: {
1863
2176
  setHeader?: (name: string, value: string) => void;
1864
2177
  declaredErrorCode?: (error: unknown) => OperationErrorCode | undefined;
1865
2178
  }): RequestScope {
2179
+ const sensitiveRegistry = createDiagnosticRedactor([], input.staticSensitiveValues);
2180
+ const redact = (text: string) => redactDiagnosticText(text, sensitiveRegistry.redact);
2181
+ bindCriticalDiagnosticRedactor(
2182
+ redact,
2183
+ sensitiveRegistry.redactCritical,
2184
+ sensitiveRegistry.redactStructured,
2185
+ () => sensitiveRegistry.suppressed,
2186
+ );
1866
2187
  const requestCost = startRequestCost();
1867
- const traceConfig = resolveTraceConfigFromEnv();
2188
+ const observeEnv = {
2189
+ observe: createDiagnosticEnvObserver(
2190
+ input.provider,
2191
+ sensitiveRegistry.add,
2192
+ sensitiveRegistry.has,
2193
+ ),
2194
+ finished: false,
2195
+ staticValues: input.staticSensitiveValues,
2196
+ };
2197
+ const traceConfig = withDiagnosticEnv(observeEnv, () => resolveTraceConfigFromEnv());
1868
2198
  const details = {
1869
2199
  route: input.route,
1870
2200
  requestId: input.requestId,
@@ -1883,13 +2213,19 @@ function createRequestScope(input: {
1883
2213
  const initialTraceId = requestTraceId(input.headers, input.requestId);
1884
2214
  const trace: RuntimeTraceContext = traceConfig
1885
2215
  ? createTraceContext({
1886
- ...resolveServerTraceContextOptions(traceConfig, traceAttributes),
2216
+ ...withDiagnosticEnv(observeEnv, () =>
2217
+ resolveServerTraceContextOptions(traceConfig, traceAttributes, undefined, redact),
2218
+ ),
2219
+ redact,
1887
2220
  ...(initialTraceId ? { traceId: initialTraceId } : {}),
1888
2221
  })
1889
- : createTraceContext();
2222
+ : createTraceContext({ redact });
2223
+ bindDiagnosticSensitiveRegistry(trace, sensitiveRegistry);
1890
2224
  const proxyCollector = new ProxyTelemetryCollector();
2225
+ const resolverCollector = new ResolverTelemetryCollector({ redact });
1891
2226
  const telemetry = new RequestTelemetry(trace);
1892
2227
  telemetry.register(proxyCollector);
2228
+ telemetry.register(resolverCollector);
1893
2229
  let rootRunner: <T>(fn: () => Promise<T>) => Promise<T> = (fn) => fn();
1894
2230
  let resolveRoot!: (outcome: RequestTerminalOutcome) => void;
1895
2231
  const rootTerminal = new Promise<RequestTerminalOutcome>((resolve) => {
@@ -1913,12 +2249,14 @@ function createRequestScope(input: {
1913
2249
  if (outcome.kind === "cancelled") return clientCancelledError();
1914
2250
  return undefined;
1915
2251
  };
1916
- const root = trace.span(`request:${input.kind}:${input.route}`, async () => {
1917
- rootRunner = AsyncLocalStorage.snapshot();
1918
- const outcome = await rootTerminal;
1919
- const error = terminalError(outcome);
1920
- if (error !== undefined) throw error;
1921
- });
2252
+ const root = withDiagnosticEnv(observeEnv, () =>
2253
+ trace.span(`request:${input.kind}:${input.route}`, async () => {
2254
+ rootRunner = AsyncLocalStorage.snapshot();
2255
+ const outcome = await rootTerminal;
2256
+ const error = terminalError(outcome);
2257
+ if (error !== undefined) throw error;
2258
+ }),
2259
+ );
1922
2260
  void root.catch(() => undefined);
1923
2261
 
1924
2262
  const settleRoot = (): void => {
@@ -1953,7 +2291,7 @@ function createRequestScope(input: {
1953
2291
  traceAttributes.route = details.route;
1954
2292
  const traceId = requestTraceId(details.headers, details.requestId);
1955
2293
  const sanitizedAttributes = Object.fromEntries(
1956
- Object.entries(sanitizeTraceAttributes(traceAttributes)).map(([key, value]) => [
2294
+ Object.entries(sanitizeTraceAttributes(traceAttributes, redact)).map(([key, value]) => [
1957
2295
  key,
1958
2296
  String(value),
1959
2297
  ]),
@@ -1965,8 +2303,16 @@ function createRequestScope(input: {
1965
2303
  };
1966
2304
 
1967
2305
  const scope: RequestScope = {
2306
+ redact,
1968
2307
  trace,
1969
2308
  telemetry,
2309
+ resolverTelemetry: resolverCollector,
2310
+ seedCredentials(rawBody, kind): void {
2311
+ const harvested = rawRequestCredentials(rawBody, kind);
2312
+ sensitiveRegistry.add(harvested.values);
2313
+ // An incomplete inventory cannot certify free text: emit less.
2314
+ if (harvested.exhausted) sensitiveRegistry.suppress();
2315
+ },
1970
2316
  enrich(enrichment): void {
1971
2317
  if (terminalOutcome) return;
1972
2318
  if (enrichment.route !== undefined) details.route = enrichment.route;
@@ -2016,6 +2362,7 @@ function createRequestScope(input: {
2016
2362
  },
2017
2363
  terminalize(outcome): RequestScopeFinishResult {
2018
2364
  if (finishedResult) return finishedResult;
2365
+ observeEnv.finished = true;
2019
2366
  terminalOutcome = outcome;
2020
2367
  const error = terminalError(outcome);
2021
2368
  finishedResult = {};
@@ -2023,8 +2370,7 @@ function createRequestScope(input: {
2023
2370
  const declaredErrorCode =
2024
2371
  error === undefined ? undefined : input.declaredErrorCode?.(error);
2025
2372
  const status =
2026
- outcome.status ??
2027
- (error === undefined ? 200 : toStatusCode(error, declaredErrorCode));
2373
+ outcome.status ?? (error === undefined ? 200 : toStatusCode(error, declaredErrorCode));
2028
2374
  finishedResult = headerSnapshot(error);
2029
2375
  const cost = finishRequestCost(requestCost);
2030
2376
  try {
@@ -2039,6 +2385,7 @@ function createRequestScope(input: {
2039
2385
  cost,
2040
2386
  telemetry,
2041
2387
  details.correlation,
2388
+ redact,
2042
2389
  );
2043
2390
  } else {
2044
2391
  logProviderError(
@@ -2054,6 +2401,7 @@ function createRequestScope(input: {
2054
2401
  telemetry,
2055
2402
  finishedResult.errorObservability as ErrorObservabilityDetails,
2056
2403
  details.correlation,
2404
+ redact,
2057
2405
  );
2058
2406
  }
2059
2407
  } catch {
@@ -2089,35 +2437,73 @@ function createRequestScope(input: {
2089
2437
  return scope;
2090
2438
  }
2091
2439
 
2092
- function responseWithRequestScopeHeaders(
2440
+ // A raw `Response` result skips `toErrorResponse`. Its payload shape stays
2441
+ // provider-owned; known credentials in error payloads still need redaction.
2442
+ // The observability header is SDK-owned: derive it
2443
+ // from the status. Only timeouts, rate limits, and 5xx are retryable;
2444
+ // `isRetryableCategory` would otherwise mark every other 4xx (`upstream_http`)
2445
+ // as retryable.
2446
+ function rawResponseErrorObservability(status: number): ErrorObservabilityDetails {
2447
+ return {
2448
+ category: categoryForStatus(status),
2449
+ taxonomyVersion: PROVIDER_OBSERVABILITY_TAXONOMY_VERSION,
2450
+ retryable: status === 408 || status === 429 || status >= 500,
2451
+ };
2452
+ }
2453
+
2454
+ // `rawStatusFallback` is decided by the caller from the outcome, not from a
2455
+ // missing snapshot: a failed outcome whose thrown value is `undefined` also has
2456
+ // no `errorObservability`, and its 500 carries the SDK envelope, not a raw body.
2457
+ async function responseWithRequestScopeHeaders(
2093
2458
  response: Response,
2094
2459
  finished: RequestScopeFinishResult,
2095
- ): Response {
2460
+ rawStatusFallback: boolean,
2461
+ redact: DiagnosticRedactor,
2462
+ ): Promise<Response> {
2096
2463
  const headers = new Headers(response.headers);
2097
2464
  headers.delete(PROVIDER_TELEMETRY_HEADER);
2098
2465
  if (finished.providerTelemetryHeader) {
2099
2466
  headers.set(PROVIDER_TELEMETRY_HEADER, finished.providerTelemetryHeader);
2100
2467
  }
2101
- if (finished.errorObservability) {
2102
- headers.set(ERROR_OBSERVABILITY_HEADER, JSON.stringify(finished.errorObservability));
2103
- }
2104
- return new Response(response.body, {
2468
+ headers.delete(ERROR_OBSERVABILITY_HEADER);
2469
+ const errorObservability =
2470
+ finished.errorObservability ??
2471
+ (rawStatusFallback && response.status >= 400
2472
+ ? rawResponseErrorObservability(response.status)
2473
+ : undefined);
2474
+ if (errorObservability) {
2475
+ headers.set(ERROR_OBSERVABILITY_HEADER, JSON.stringify(errorObservability));
2476
+ }
2477
+ // Raw Response bodies are provider-owned. Preserve their stream and representation.
2478
+ const body = response.body;
2479
+ const statusText =
2480
+ rawStatusFallback && response.status >= 400
2481
+ ? redactDiagnosticText(response.statusText, redact)
2482
+ : response.statusText;
2483
+ return new Response(body, {
2105
2484
  headers,
2106
2485
  status: response.status,
2107
- statusText: response.statusText,
2486
+ // When free text cannot be certified, use the SDK's standard HTTP reason
2487
+ // phrase. It preserves the status contract without trusting provider text.
2488
+ statusText:
2489
+ statusText === REDACTION_FAILED && isDiagnosticRedactionSuppressed(redact)
2490
+ ? (STATUS_CODES[response.status] ?? "")
2491
+ : statusText,
2108
2492
  });
2109
2493
  }
2110
2494
 
2111
- function finalizeRequestResponse(
2495
+ async function finalizeRequestResponse(
2112
2496
  scope: RequestScope,
2113
2497
  response: Response,
2114
2498
  outcome: RequestTerminalOutcome,
2115
- ): Response {
2499
+ ): Promise<Response> {
2116
2500
  try {
2117
2501
  const error = outcome.kind === "failed" ? outcome.error : undefined;
2118
- const finalResponse = responseWithRequestScopeHeaders(
2502
+ const finalResponse = await responseWithRequestScopeHeaders(
2119
2503
  response,
2120
2504
  scope.snapshotHeaders(error),
2505
+ outcome.kind === "completed",
2506
+ scope.redact,
2121
2507
  );
2122
2508
  scope.terminalize(outcome);
2123
2509
  return finalResponse;
@@ -2336,11 +2722,7 @@ function toSseResponse(
2336
2722
  const validated = await validateSseEvent(operation, next.value);
2337
2723
  const encodedEvent = encodeSseEvent(validated);
2338
2724
  const bytes = encoder.encode(encodedEvent);
2339
- assertStreamPayloadWithinLimit(
2340
- bytes.byteLength,
2341
- transport?.maxEventBytes,
2342
- "event",
2343
- );
2725
+ assertStreamPayloadWithinLimit(bytes.byteLength, transport?.maxEventBytes, "event");
2344
2726
  return bytes;
2345
2727
  });
2346
2728
  controller.enqueue(encodedBytes);
@@ -2349,9 +2731,13 @@ function toSseResponse(
2349
2731
  controller.enqueue(
2350
2732
  encoder.encode(
2351
2733
  encodeSseEvent(
2352
- streamError("stream_error", message, {
2353
- ...(requestId ? { requestId } : {}),
2354
- }),
2734
+ streamError(
2735
+ "stream_error",
2736
+ sanitizeDiagnosticText(redactDiagnosticText(message, lifecycle.redact)),
2737
+ {
2738
+ ...(requestId ? { requestId } : {}),
2739
+ },
2740
+ ),
2355
2741
  ),
2356
2742
  ),
2357
2743
  );
@@ -2484,6 +2870,7 @@ function getHttpStreamTransport(
2484
2870
  function toAuthFlowResponse(
2485
2871
  result: unknown,
2486
2872
  contextPatch: Record<string, unknown | null> | undefined,
2873
+ engine: AuthFlowSuccessResponse["engine"],
2487
2874
  ): Response | AuthFlowSuccessResponse {
2488
2875
  if (result instanceof Response) {
2489
2876
  return result;
@@ -2496,6 +2883,7 @@ function toAuthFlowResponse(
2496
2883
  return {
2497
2884
  data: result,
2498
2885
  ...(contextPatch ? { contextPatch } : {}),
2886
+ ...(engine ? { engine } : {}),
2499
2887
  };
2500
2888
  }
2501
2889
 
@@ -2592,6 +2980,7 @@ async function handleOperation(
2592
2980
  request.requestId,
2593
2981
  "stealth",
2594
2982
  error,
2983
+ scope.redact,
2595
2984
  );
2596
2985
  }
2597
2986
  }
@@ -2607,11 +2996,13 @@ async function handleOperation(
2607
2996
  request.requestId,
2608
2997
  "browser",
2609
2998
  error,
2999
+ scope.redact,
2610
3000
  );
2611
3001
  }
2612
3002
  }
2613
3003
  };
2614
3004
  const streamLifecycle: RequestStreamLifecycle = {
3005
+ redact: scope.redact,
2615
3006
  runStep<T>(fn: () => Promise<T>): Promise<T> {
2616
3007
  return scope.runStreamStep(fn);
2617
3008
  },
@@ -2672,10 +3063,12 @@ async function handleAuthFlow(
2672
3063
  // depend on declared secrets (client ids/secrets), so fail structured before
2673
3064
  // any flow code runs instead of at whatever point the ceremony first reads
2674
3065
  // the env. `abort` stays exempt: a user must always be able to cancel a
2675
- // stranded flow even when provisioning is broken.
2676
- const { context, getPatch } = createAuthFlowContext(
3066
+ // stranded flow even when provisioning is broken (createAuthFlowContext
3067
+ // applies the same exemption to the engine ceremony lease).
3068
+ const { context, getPatch, getEngineState } = createAuthFlowContext(
2677
3069
  provider,
2678
3070
  request,
3071
+ route,
2679
3072
  options,
2680
3073
  state,
2681
3074
  scope,
@@ -2715,10 +3108,10 @@ async function handleAuthFlow(
2715
3108
  isAuthTurn(result)
2716
3109
  ? materializeAuthFlowTurn(provider, request, result)
2717
3110
  : result;
2718
- return toAuthFlowResponse(materializedResult, getPatch());
3111
+ return toAuthFlowResponse(materializedResult, getPatch(), getEngineState());
2719
3112
  } catch (error) {
2720
3113
  if (error instanceof AuthAbortError) {
2721
- return toAuthFlowResponse(error.turn, getPatch());
3114
+ return toAuthFlowResponse(error.turn, getPatch(), getEngineState());
2722
3115
  }
2723
3116
  throw error;
2724
3117
  } finally {
@@ -2733,6 +3126,7 @@ async function handleAuthFlow(
2733
3126
  request.requestId,
2734
3127
  "stealth",
2735
3128
  error,
3129
+ scope.redact,
2736
3130
  );
2737
3131
  }
2738
3132
  }
@@ -2854,12 +3248,15 @@ function operationRequestFromForwardingEnvelope(
2854
3248
  };
2855
3249
  }
2856
3250
 
2857
- function parseStatefulForwardingEnvelope(rawBody: unknown): ProviderServerStatefulForwardEnvelope {
3251
+ function parseStatefulForwardingEnvelope(
3252
+ rawBody: unknown,
3253
+ redact: DiagnosticRedactor,
3254
+ ): ProviderServerStatefulForwardEnvelope {
2858
3255
  const parsed = ProviderServerStatefulForwardEnvelopeSchema.safeParse(rawBody);
2859
3256
  if (parsed.success) return parsed.data;
2860
3257
  throw new ProviderError("Stateful forwarding envelope is invalid.", {
2861
3258
  code: "STATEFUL_FORWARDING_ENVELOPE_INVALID",
2862
- details: zodDetails(parsed.error),
3259
+ details: zodDetails(parsed.error, redact),
2863
3260
  });
2864
3261
  }
2865
3262
 
@@ -2867,7 +3264,9 @@ function parseStatefulForwardingEnvelope(rawBody: unknown): ProviderServerStatef
2867
3264
  * Primary, cross-runtime app factory. Declared capability ESM is preloaded
2868
3265
  * asynchronously, so this path works on Bun and every supported Node release.
2869
3266
  */
2870
- export async function createServerAppAsync<TContext extends Partial<ProviderContext> = ProviderContext>(
3267
+ export async function createServerAppAsync<
3268
+ TContext extends Partial<ProviderContext> = ProviderContext,
3269
+ >(
2871
3270
  provider: ProviderDefinition<TContext>,
2872
3271
  options: ProviderServerOptions<TContext> = {},
2873
3272
  ): Promise<Hono> {
@@ -2914,6 +3313,12 @@ function createServerAppWithCapabilityModules(
2914
3313
  engine: serverOptions.engine ?? createInProcessProviderEngine(),
2915
3314
  };
2916
3315
  const app = new Hono();
3316
+ // Compile the startup inventory once, composed with the shared outside-context fallback.
3317
+ const staticSensitiveValues = compileProcessDiagnosticSensitiveValues(
3318
+ collectStaticDiagnosticSensitiveValues(provider, {
3319
+ statefulForwardingSecret: options.statefulForwarding?.secret,
3320
+ }),
3321
+ );
2917
3322
  const logger = options.logger ?? defaultProviderServerLogger;
2918
3323
  const operationErrorCodes = buildOperationErrorCodeLookup(provider);
2919
3324
  const statefulForwardingReplayCache = new StatefulForwardingReplayCache(
@@ -2969,6 +3374,7 @@ function createServerAppWithCapabilityModules(
2969
3374
  const operation = "stateful-internal";
2970
3375
  const requestScope = createRequestScope({
2971
3376
  provider,
3377
+ staticSensitiveValues,
2972
3378
  kind: "operation",
2973
3379
  route: operation,
2974
3380
  headers: Object.fromEntries(c.req.raw.headers.entries()),
@@ -2998,7 +3404,8 @@ function createServerAppWithCapabilityModules(
2998
3404
  code: "STATEFUL_FORWARDING_ENVELOPE_INVALID",
2999
3405
  });
3000
3406
  }
3001
- const envelope = parseStatefulForwardingEnvelope(rawBody);
3407
+ requestScope.seedCredentials(rawBody, "stateful");
3408
+ const envelope = parseStatefulForwardingEnvelope(rawBody, requestScope.redact);
3002
3409
  if (envelope.providerId !== provider.id) {
3003
3410
  throw new ProviderError(
3004
3411
  "Stateful forwarding envelope providerId does not match the served provider.",
@@ -3134,7 +3541,10 @@ function createServerAppWithCapabilityModules(
3134
3541
  ...(requestId ? { requestId } : {}),
3135
3542
  });
3136
3543
  const observabilityDetails = errorObservabilityDetails(error, declaredErrorCode);
3137
- const response = c.json(toErrorResponse(error, requestId, observabilityDetails), status);
3544
+ const response = c.json(
3545
+ toErrorResponse(error, requestId, observabilityDetails, requestScope.redact),
3546
+ status,
3547
+ );
3138
3548
  return finalizeRequestResponse(requestScope, response, {
3139
3549
  kind: "failed",
3140
3550
  status,
@@ -3148,6 +3558,7 @@ function createServerAppWithCapabilityModules(
3148
3558
  const operation = c.req.param("operation");
3149
3559
  const requestScope = createRequestScope({
3150
3560
  provider,
3561
+ staticSensitiveValues,
3151
3562
  kind: "operation",
3152
3563
  route: operation,
3153
3564
  operationId: operation,
@@ -3161,6 +3572,7 @@ function createServerAppWithCapabilityModules(
3161
3572
  .clone()
3162
3573
  .json()
3163
3574
  .catch(() => undefined);
3575
+ requestScope.seedCredentials(rawBody, "operation");
3164
3576
  const body = OperationRequestSchema.parse(rawBody);
3165
3577
  const requestHeaders = Object.fromEntries(c.req.raw.headers.entries());
3166
3578
  body.headers = { ...requestHeaders, ...body.headers };
@@ -3185,7 +3597,12 @@ function createServerAppWithCapabilityModules(
3185
3597
  );
3186
3598
  const response = handled instanceof Response ? handled : c.json(handled);
3187
3599
  return streaming
3188
- ? responseWithRequestScopeHeaders(response, requestScope.snapshotHeaders())
3600
+ ? responseWithRequestScopeHeaders(
3601
+ response,
3602
+ requestScope.snapshotHeaders(),
3603
+ true,
3604
+ requestScope.redact,
3605
+ )
3189
3606
  : response;
3190
3607
  };
3191
3608
  const response = streaming
@@ -3202,7 +3619,10 @@ function createServerAppWithCapabilityModules(
3202
3619
  const requestId = extractRequestId(rawBody);
3203
3620
  requestScope.enrich({ ...(requestId ? { requestId } : {}) });
3204
3621
  const observabilityDetails = errorObservabilityDetails(error, declaredErrorCode);
3205
- const response = c.json(toErrorResponse(error, requestId, observabilityDetails), status);
3622
+ const response = c.json(
3623
+ toErrorResponse(error, requestId, observabilityDetails, requestScope.redact),
3624
+ status,
3625
+ );
3206
3626
  return finalizeRequestResponse(requestScope, response, {
3207
3627
  kind: "failed",
3208
3628
  status,
@@ -3228,6 +3648,7 @@ function createServerAppWithCapabilityModules(
3228
3648
  let rawBody: unknown;
3229
3649
  const requestScope = createRequestScope({
3230
3650
  provider,
3651
+ staticSensitiveValues,
3231
3652
  kind: "auth",
3232
3653
  route: logRoute,
3233
3654
  headers: Object.fromEntries(c.req.raw.headers.entries()),
@@ -3239,6 +3660,7 @@ function createServerAppWithCapabilityModules(
3239
3660
  .clone()
3240
3661
  .json()
3241
3662
  .catch(() => undefined);
3663
+ requestScope.seedCredentials(rawBody, "auth");
3242
3664
  const body = withAuthRequestHeaders(
3243
3665
  AuthFlowRequestSchema.parse(rawBody),
3244
3666
  c.req.raw.headers,
@@ -3278,7 +3700,10 @@ function createServerAppWithCapabilityModules(
3278
3700
  const requestId = extractRequestId(rawBody);
3279
3701
  requestScope.enrich({ ...(requestId ? { requestId } : {}) });
3280
3702
  const observabilityDetails = errorObservabilityDetails(error);
3281
- const response = c.json(toErrorResponse(error, requestId, observabilityDetails), status);
3703
+ const response = c.json(
3704
+ toErrorResponse(error, requestId, observabilityDetails, requestScope.redact),
3705
+ status,
3706
+ );
3282
3707
  return finalizeRequestResponse(requestScope, response, {
3283
3708
  kind: "failed",
3284
3709
  status,