@apifuse/provider-sdk 2.2.0-beta.62 → 2.2.0-beta.63

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 (243) hide show
  1. package/AUTHORING.md +268 -9
  2. package/CHANGELOG.md +4 -0
  3. package/README.md +1 -0
  4. package/bin/apifuse-check.ts +84 -2
  5. package/bin/apifuse-dev.ts +11 -31
  6. package/bin/apifuse-migrate-deployment.ts +200 -0
  7. package/bin/apifuse-pack-check.ts +11 -4
  8. package/bin/apifuse-pack-types.ts +187 -4
  9. package/bin/apifuse-record.ts +44 -32
  10. package/bin/apifuse-test.ts +3 -1
  11. package/dist/cli/commands.d.ts +1 -1
  12. package/dist/cli/commands.js +11 -0
  13. package/dist/cli/deployment-intent.d.ts +178 -0
  14. package/dist/cli/deployment-intent.js +277 -0
  15. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  16. package/dist/cli/migrate-deployment-intent.js +1552 -0
  17. package/dist/cli/migrate-provider-shape.d.ts +5 -1
  18. package/dist/cli/migrate-provider-shape.js +4 -2
  19. package/dist/cli/resolver-runtime.d.ts +21 -0
  20. package/dist/cli/resolver-runtime.js +31 -0
  21. package/dist/define.d.ts +3 -0
  22. package/dist/define.js +5 -0
  23. package/dist/dev.d.ts +3 -1
  24. package/dist/dev.js +6 -1
  25. package/dist/engine.d.ts +35 -1
  26. package/dist/engine.js +21 -2
  27. package/dist/error-resolution.d.ts +1 -0
  28. package/dist/error-resolution.js +54 -0
  29. package/dist/errors.d.ts +39 -1
  30. package/dist/errors.js +50 -0
  31. package/dist/i18n/error-messages.d.ts +86 -0
  32. package/dist/i18n/error-messages.js +192 -0
  33. package/dist/i18n/index.d.ts +1 -0
  34. package/dist/i18n/index.js +1 -0
  35. package/dist/i18n/keys.d.ts +12 -0
  36. package/dist/i18n/keys.js +76 -5
  37. package/dist/index.d.ts +7 -1
  38. package/dist/index.js +6 -0
  39. package/dist/lint.d.ts +10 -0
  40. package/dist/lint.js +412 -49
  41. package/dist/provider.d.ts +5 -5
  42. package/dist/provider.js +2 -2
  43. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  44. package/dist/runtime/browser-telemetry-binding.js +83 -0
  45. package/dist/runtime/browser-telemetry.d.ts +76 -0
  46. package/dist/runtime/browser-telemetry.js +165 -0
  47. package/dist/runtime/browser.d.ts +3 -0
  48. package/dist/runtime/browser.js +208 -47
  49. package/dist/runtime/cache-telemetry.d.ts +71 -0
  50. package/dist/runtime/cache-telemetry.js +177 -0
  51. package/dist/runtime/cache.js +67 -7
  52. package/dist/runtime/capability-response.d.ts +3 -0
  53. package/dist/runtime/capability-response.js +56 -0
  54. package/dist/runtime/capability-telemetry.d.ts +46 -0
  55. package/dist/runtime/capability-telemetry.js +68 -0
  56. package/dist/runtime/diagnostic-env.d.ts +3 -0
  57. package/dist/runtime/diagnostic-env.js +10 -1
  58. package/dist/runtime/engine-mode.d.ts +74 -0
  59. package/dist/runtime/engine-mode.js +152 -0
  60. package/dist/runtime/http-telemetry-guard.d.ts +10 -0
  61. package/dist/runtime/http-telemetry-guard.js +62 -10
  62. package/dist/runtime/http.js +141 -35
  63. package/dist/runtime/instrumentation.js +92 -13
  64. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  65. package/dist/runtime/ocr-telemetry.js +192 -0
  66. package/dist/runtime/ocr.js +30 -8
  67. package/dist/runtime/request-telemetry.d.ts +2 -0
  68. package/dist/runtime/request-telemetry.js +2 -1
  69. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  70. package/dist/runtime/resolver-runtime-options.js +33 -0
  71. package/dist/runtime/resolver-shared.d.ts +3 -2
  72. package/dist/runtime/resolver-shared.js +4 -4
  73. package/dist/runtime/resolver-telemetry.d.ts +1 -0
  74. package/dist/runtime/resolver-telemetry.js +1 -1
  75. package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
  76. package/dist/runtime/resolver-vendors/browser.js +46 -0
  77. package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
  78. package/dist/runtime/resolver-vendors/hosts.js +35 -0
  79. package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
  80. package/dist/runtime/resolver-vendors/types.d.ts +5 -4
  81. package/dist/runtime/resolver.d.ts +4 -1
  82. package/dist/runtime/resolver.js +46 -13
  83. package/dist/runtime/state-telemetry.d.ts +79 -0
  84. package/dist/runtime/state-telemetry.js +194 -0
  85. package/dist/runtime/state.d.ts +3 -0
  86. package/dist/runtime/state.js +26 -7
  87. package/dist/runtime/stealth-cookies.d.ts +5 -1
  88. package/dist/runtime/stealth-cookies.js +21 -1
  89. package/dist/runtime/stealth-owned-headers.d.ts +26 -0
  90. package/dist/runtime/stealth-owned-headers.js +37 -0
  91. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  92. package/dist/runtime/stealth-telemetry.js +179 -0
  93. package/dist/runtime/stealth.d.ts +4 -1
  94. package/dist/runtime/stealth.js +228 -85
  95. package/dist/runtime/stt-telemetry.d.ts +77 -0
  96. package/dist/runtime/stt-telemetry.js +176 -0
  97. package/dist/runtime/stt.js +15 -6
  98. package/dist/server/error-stack-frames.d.ts +35 -0
  99. package/dist/server/error-stack-frames.js +219 -0
  100. package/dist/server/index.d.ts +7 -0
  101. package/dist/server/index.js +4 -0
  102. package/dist/server/sdk-version.d.ts +3 -0
  103. package/dist/server/sdk-version.js +19 -0
  104. package/dist/server/self-test.js +1 -18
  105. package/dist/server/sensitive-values.d.ts +1 -1
  106. package/dist/server/sensitive-values.js +9 -0
  107. package/dist/server/serve-implementation.d.ts +51 -2
  108. package/dist/server/serve-implementation.js +337 -90
  109. package/dist/server/types.d.ts +1 -0
  110. package/dist/server/types.js +7 -0
  111. package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
  112. package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
  113. package/dist/stateful/stateful-provider-runtime-context.js +1 -0
  114. package/dist/types.d.ts +94 -1
  115. package/package.json +6 -1
  116. package/src/cli/commands.ts +14 -0
  117. package/src/cli/deployment-intent.ts +364 -0
  118. package/src/cli/migrate-deployment-intent.ts +1908 -0
  119. package/src/cli/migrate-provider-shape.ts +10 -4
  120. package/src/cli/resolver-runtime.ts +72 -0
  121. package/src/define.ts +13 -0
  122. package/src/dev.ts +9 -2
  123. package/src/engine.ts +38 -2
  124. package/src/error-resolution.ts +58 -0
  125. package/src/errors.ts +77 -1
  126. package/src/i18n/error-messages.ts +255 -0
  127. package/src/i18n/index.ts +1 -0
  128. package/src/i18n/keys.ts +80 -6
  129. package/src/index.ts +72 -0
  130. package/src/lint.ts +522 -50
  131. package/src/provider.ts +10 -0
  132. package/src/runtime/browser-telemetry-binding.ts +92 -0
  133. package/src/runtime/browser-telemetry.ts +289 -0
  134. package/src/runtime/browser.ts +249 -65
  135. package/src/runtime/cache-telemetry.ts +247 -0
  136. package/src/runtime/cache.ts +68 -17
  137. package/src/runtime/capability-response.ts +53 -0
  138. package/src/runtime/capability-telemetry.ts +101 -0
  139. package/src/runtime/diagnostic-env.ts +11 -1
  140. package/src/runtime/engine-mode.ts +233 -0
  141. package/src/runtime/http-telemetry-guard.ts +66 -13
  142. package/src/runtime/http.ts +168 -37
  143. package/src/runtime/instrumentation.ts +105 -16
  144. package/src/runtime/ocr-telemetry.ts +308 -0
  145. package/src/runtime/ocr.ts +109 -74
  146. package/src/runtime/request-telemetry.ts +2 -1
  147. package/src/runtime/resolver-runtime-options.ts +50 -0
  148. package/src/runtime/resolver-shared.ts +9 -4
  149. package/src/runtime/resolver-telemetry.ts +1 -1
  150. package/src/runtime/resolver-vendors/browser.ts +65 -7
  151. package/src/runtime/resolver-vendors/hosts.ts +43 -0
  152. package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
  153. package/src/runtime/resolver-vendors/types.ts +5 -4
  154. package/src/runtime/resolver.ts +64 -21
  155. package/src/runtime/state-telemetry.ts +298 -0
  156. package/src/runtime/state.ts +46 -45
  157. package/src/runtime/stealth-cookies.ts +24 -1
  158. package/src/runtime/stealth-owned-headers.ts +41 -0
  159. package/src/runtime/stealth-telemetry.ts +304 -0
  160. package/src/runtime/stealth.ts +355 -150
  161. package/src/runtime/stt-telemetry.ts +282 -0
  162. package/src/runtime/stt.ts +93 -71
  163. package/src/server/error-stack-frames.ts +214 -0
  164. package/src/server/index.ts +53 -0
  165. package/src/server/sdk-version.ts +22 -0
  166. package/src/server/self-test.ts +1 -21
  167. package/src/server/sensitive-values.ts +14 -0
  168. package/src/server/serve-implementation.ts +569 -108
  169. package/src/server/types.ts +7 -0
  170. package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
  171. package/src/stateful/stateful-provider-runtime-context.ts +4 -0
  172. package/src/types.ts +99 -1
  173. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
  174. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
  175. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
  176. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
  177. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
  178. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
  179. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
  180. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
  181. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
  182. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
  183. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
  184. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
  185. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
  186. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
  187. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
  188. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
  189. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
  190. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
  191. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
  192. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
  193. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
  194. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
  195. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
  196. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
  197. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
  198. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
  199. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
  200. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
  201. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
  202. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
  203. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
  204. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
  205. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
  206. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
  207. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
  208. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
  209. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
  210. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
  211. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
  212. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
  213. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
  214. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
  215. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
  216. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
  217. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
  218. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
  219. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
  220. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
  221. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
  222. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
@@ -0,0 +1,308 @@
1
+ import type { OcrContext } from "../types.js";
2
+ import {
3
+ add,
4
+ capabilityErrorText,
5
+ capabilityFacts,
6
+ capabilityMetadata,
7
+ capabilityText,
8
+ inputBytes,
9
+ integer,
10
+ observeCapability,
11
+ registerCapabilityInput,
12
+ } from "./capability-telemetry.js";
13
+ import {
14
+ type ClosedEnum,
15
+ closedEnum,
16
+ type SpanIndex,
17
+ type TelemetryContributor,
18
+ } from "./request-telemetry.js";
19
+ export type OcrTelemetryBackend =
20
+ | "cloudflare-workers-ai"
21
+ | "openai-compatible"
22
+ | "custom"
23
+ | "unavailable";
24
+ export type OcrTelemetryEngine = "workers-ai" | "openai-compatible" | "custom";
25
+ export type OcrTelemetryErrorCode =
26
+ | "OCR_UNAVAILABLE"
27
+ | "UNSUPPORTED_OCR_BACKEND"
28
+ | "OCR_UPSTREAM_FAILED"
29
+ | "OCR_INCOMPLETE_RESPONSE"
30
+ | "transport_network_error"
31
+ | "transport_timeout"
32
+ | "other";
33
+ export type OcrTelemetryModel =
34
+ | "gemma-4-26b-a4b-it"
35
+ | "glm-ocr"
36
+ | "moondream3.1-9B-A2B"
37
+ | "kimi-k2.7-code";
38
+ export type OcrTelemetryFinishReason =
39
+ | "stop"
40
+ | "length"
41
+ | "content_filter"
42
+ | "tool_calls"
43
+ | "function_call"
44
+ | "error"
45
+ | "unknown";
46
+ const ERROR_CODES: ReadonlySet<string> = new Set([
47
+ "OCR_UNAVAILABLE",
48
+ "UNSUPPORTED_OCR_BACKEND",
49
+ "OCR_UPSTREAM_FAILED",
50
+ "OCR_INCOMPLETE_RESPONSE",
51
+ "transport_network_error",
52
+ "transport_timeout",
53
+ "other",
54
+ ]);
55
+ const MODELS = new Map<string, OcrTelemetryModel>([
56
+ ["@cf/google/gemma-4-26b-a4b-it", "gemma-4-26b-a4b-it"],
57
+ ["zai-org/GLM-OCR", "glm-ocr"],
58
+ ["@cf/moondream/moondream3.1-9B-A2B", "moondream3.1-9B-A2B"],
59
+ ["@cf/moonshotai/kimi-k2.7-code", "kimi-k2.7-code"],
60
+ ]);
61
+ function errorCode(error: unknown): OcrTelemetryErrorCode {
62
+ const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
63
+ return typeof code === "string" && ERROR_CODES.has(code)
64
+ ? (code as OcrTelemetryErrorCode)
65
+ : "other";
66
+ }
67
+ function finishReason(value: string | undefined, failed: boolean): OcrTelemetryFinishReason {
68
+ switch (value) {
69
+ case "stop":
70
+ case "length":
71
+ case "content_filter":
72
+ case "tool_calls":
73
+ case "function_call":
74
+ return value;
75
+ default:
76
+ return value === undefined ? (failed ? "error" : "stop") : "unknown";
77
+ }
78
+ }
79
+ export type OcrTelemetryEvent = {
80
+ backend: OcrTelemetryBackend;
81
+ engine: OcrTelemetryEngine;
82
+ model?: string;
83
+ ms: number;
84
+ status?: number;
85
+ bytesIn?: number;
86
+ bytesOut?: number;
87
+ candidates?: number;
88
+ warnings?: number;
89
+ errorCode?: OcrTelemetryErrorCode;
90
+ diagnostics?: string;
91
+ finishReason?: OcrTelemetryFinishReason;
92
+ };
93
+ export interface OcrTelemetrySink {
94
+ record(event: OcrTelemetryEvent): void;
95
+ markTelemetryFailed?(): void;
96
+ }
97
+ export type OcrTelemetryLogPayload = {
98
+ telemetryFailed?: true;
99
+ diagnostics?: string[];
100
+ backend: OcrTelemetryBackend;
101
+ engine: OcrTelemetryEngine;
102
+ model?: string;
103
+ ms: number;
104
+ status?: number;
105
+ bytesIn: number;
106
+ bytesOut: number;
107
+ candidates: number;
108
+ warnings: number;
109
+ lastErrorCode?: OcrTelemetryErrorCode;
110
+ finishReason?: OcrTelemetryFinishReason;
111
+ samples?: Array<Omit<OcrTelemetryEvent, "backend" | "engine" | "model" | "diagnostics">>;
112
+ samplesDropped?: number;
113
+ };
114
+ export type OcrTelemetryHeaderPayload = {
115
+ backend: ClosedEnum<OcrTelemetryBackend>;
116
+ engine: ClosedEnum<OcrTelemetryEngine>;
117
+ model?: ClosedEnum<OcrTelemetryModel>;
118
+ ms: number;
119
+ status?: number;
120
+ bytesIn: number;
121
+ bytesOut: number;
122
+ candidates: number;
123
+ warnings: number;
124
+ lastErrorCode?: ClosedEnum<OcrTelemetryErrorCode>;
125
+ finishReason?: ClosedEnum<OcrTelemetryFinishReason>;
126
+ samples?: Array<{
127
+ ms: number;
128
+ status?: number;
129
+ bytesIn?: number;
130
+ bytesOut?: number;
131
+ candidates?: number;
132
+ warnings?: number;
133
+ errorCode?: ClosedEnum<OcrTelemetryErrorCode>;
134
+ finishReason?: ClosedEnum<OcrTelemetryFinishReason>;
135
+ }>;
136
+ samplesDropped?: number;
137
+ };
138
+ export class OcrTelemetryCollector
139
+ implements
140
+ OcrTelemetrySink,
141
+ TelemetryContributor<OcrTelemetryLogPayload, OcrTelemetryHeaderPayload>
142
+ {
143
+ readonly key = "ocr" as const;
144
+ readonly #redact?: (text: string) => string;
145
+ #samples: NonNullable<OcrTelemetryLogPayload["samples"]> = [];
146
+ #summary: Omit<OcrTelemetryLogPayload, "samples" | "samplesDropped"> | undefined;
147
+ #diagnostics: string[] = [];
148
+ #dropped = 0;
149
+ #failed = false;
150
+ constructor(options: { redact?: (text: string) => string } = {}) {
151
+ this.#redact = options.redact;
152
+ }
153
+ markTelemetryFailed(): void {
154
+ this.#failed = true;
155
+ this.#summary ??= {
156
+ backend: "custom",
157
+ engine: "custom",
158
+ ms: 0,
159
+ bytesIn: 0,
160
+ bytesOut: 0,
161
+ candidates: 0,
162
+ warnings: 0,
163
+ };
164
+ }
165
+ record(event: OcrTelemetryEvent): void {
166
+ const sample = {
167
+ ms: integer(event.ms),
168
+ ...(event.status === undefined ? {} : { status: integer(event.status) }),
169
+ ...(event.bytesIn === undefined ? {} : { bytesIn: integer(event.bytesIn) }),
170
+ ...(event.bytesOut === undefined ? {} : { bytesOut: integer(event.bytesOut) }),
171
+ ...(event.candidates === undefined ? {} : { candidates: integer(event.candidates) }),
172
+ ...(event.warnings === undefined ? {} : { warnings: integer(event.warnings) }),
173
+ ...(event.errorCode ? { errorCode: event.errorCode } : {}),
174
+ ...(event.finishReason ? { finishReason: event.finishReason } : {}),
175
+ ...(event.diagnostics === undefined
176
+ ? {}
177
+ : { diagnostics: capabilityText(event.diagnostics, this.#redact, true) }),
178
+ };
179
+ const prior = this.#summary;
180
+ this.#summary = {
181
+ backend: event.backend,
182
+ engine: event.engine,
183
+ ...(event.model === undefined ? {} : { model: capabilityText(event.model, this.#redact) }),
184
+ ms: add(prior?.ms ?? 0, sample.ms),
185
+ ...(sample.status === undefined ? {} : { status: sample.status }),
186
+ bytesIn: add(prior?.bytesIn ?? 0, sample.bytesIn ?? 0),
187
+ bytesOut: add(prior?.bytesOut ?? 0, sample.bytesOut ?? 0),
188
+ candidates: add(prior?.candidates ?? 0, sample.candidates ?? 0),
189
+ warnings: add(prior?.warnings ?? 0, sample.warnings ?? 0),
190
+ ...(event.errorCode ? { lastErrorCode: event.errorCode } : {}),
191
+ ...(event.finishReason ? { finishReason: event.finishReason } : {}),
192
+ };
193
+ if (this.#samples.length < 24) {
194
+ const { diagnostics, ...closedSample } = sample;
195
+ this.#samples.push(closedSample);
196
+ if (diagnostics !== undefined) this.#diagnostics.push(diagnostics);
197
+ } else this.#dropped = add(this.#dropped, 1);
198
+ }
199
+ toLogPayload(_spans: SpanIndex): OcrTelemetryLogPayload | undefined {
200
+ if (!this.#summary) return undefined;
201
+ return {
202
+ ...this.#summary,
203
+ ...(this.#diagnostics.length ? { diagnostics: [...this.#diagnostics] } : {}),
204
+ ...(this.#failed ? { telemetryFailed: true as const } : {}),
205
+ samples: this.#samples.map((s) => ({ ...s })),
206
+ ...(this.#dropped ? { samplesDropped: this.#dropped } : {}),
207
+ };
208
+ }
209
+ toHeaderPayload(log: OcrTelemetryLogPayload): OcrTelemetryHeaderPayload {
210
+ return {
211
+ backend: closedEnum(log.backend),
212
+ engine: closedEnum(log.engine),
213
+ ...(log.model && MODELS.has(log.model) ? { model: closedEnum(MODELS.get(log.model)!) } : {}),
214
+ ms: log.ms,
215
+ ...(log.status === undefined ? {} : { status: log.status }),
216
+ bytesIn: log.bytesIn,
217
+ bytesOut: log.bytesOut,
218
+ candidates: log.candidates,
219
+ warnings: log.warnings,
220
+ ...(log.lastErrorCode ? { lastErrorCode: closedEnum(log.lastErrorCode) } : {}),
221
+ ...(log.finishReason ? { finishReason: closedEnum(log.finishReason) } : {}),
222
+ ...(log.samples
223
+ ? {
224
+ samples: log.samples.map((s) => ({
225
+ ms: s.ms,
226
+ ...(s.status === undefined ? {} : { status: s.status }),
227
+ ...(s.bytesIn === undefined ? {} : { bytesIn: s.bytesIn }),
228
+ ...(s.bytesOut === undefined ? {} : { bytesOut: s.bytesOut }),
229
+ ...(s.candidates === undefined ? {} : { candidates: s.candidates }),
230
+ ...(s.warnings === undefined ? {} : { warnings: s.warnings }),
231
+ ...(s.errorCode ? { errorCode: closedEnum(s.errorCode) } : {}),
232
+ ...(s.finishReason ? { finishReason: closedEnum(s.finishReason) } : {}),
233
+ })),
234
+ }
235
+ : {}),
236
+ ...(log.samplesDropped ? { samplesDropped: log.samplesDropped } : {}),
237
+ };
238
+ }
239
+ }
240
+ export function bindOcrTelemetry(
241
+ context: OcrContext,
242
+ sink: OcrTelemetrySink,
243
+ options: { backend?: OcrTelemetryBackend; engine?: OcrTelemetryEngine; model?: string } = {},
244
+ ): OcrContext {
245
+ const metadata = capabilityMetadata(context);
246
+ const backend =
247
+ options.backend ?? (metadata?.backend as OcrTelemetryBackend | undefined) ?? "custom";
248
+ const engine = options.engine ?? (metadata?.engine as OcrTelemetryEngine | undefined) ?? "custom";
249
+ const model = options.model ?? metadata?.model;
250
+ async function run<
251
+ T extends {
252
+ text: string;
253
+ model: string;
254
+ candidates?: readonly unknown[];
255
+ warnings?: readonly unknown[];
256
+ },
257
+ >(input: { kind: string; data?: string; url?: string }, operation: () => Promise<T>): Promise<T> {
258
+ const started = performance.now();
259
+ const facts: { status?: number; finishReason?: string; diagnostics?: string } = {};
260
+ observeCapability(sink, () => registerCapabilityInput(input));
261
+ let result: T;
262
+ try {
263
+ result = await capabilityFacts.run(facts, operation);
264
+ } catch (error) {
265
+ observeCapability(sink, () => {
266
+ const status =
267
+ error &&
268
+ typeof error === "object" &&
269
+ "status" in error &&
270
+ typeof error.status === "number"
271
+ ? error.status
272
+ : undefined;
273
+ return sink.record({
274
+ backend,
275
+ engine,
276
+ model,
277
+ ms: performance.now() - started,
278
+ status: facts.status ?? status,
279
+ bytesIn: inputBytes(input),
280
+ errorCode: errorCode(error),
281
+ finishReason: finishReason(facts.finishReason, true),
282
+ diagnostics: `${capabilityErrorText(error)} ${facts.diagnostics ?? ""}`,
283
+ });
284
+ });
285
+ throw error;
286
+ }
287
+ observeCapability(sink, () =>
288
+ sink.record({
289
+ backend,
290
+ engine,
291
+ model: result.model,
292
+ ms: performance.now() - started,
293
+ status: facts.status,
294
+ bytesIn: inputBytes(input),
295
+ bytesOut: Buffer.byteLength(result.text),
296
+ candidates: result.candidates?.length ?? 0,
297
+ finishReason: finishReason(facts.finishReason, false),
298
+ warnings: result.warnings?.length ?? 0,
299
+ }),
300
+ );
301
+ return result;
302
+ }
303
+ return {
304
+ ...context,
305
+ recognize: (request) => run(request.image, () => context.recognize(request)),
306
+ extractCaptchaText: (image, opts) => run(image, () => context.extractCaptchaText(image, opts)),
307
+ };
308
+ }
@@ -1,4 +1,3 @@
1
- import { readDiagnosticEnv } from "./diagnostic-env.js";
2
1
  import { ProviderError, TransportError } from "../errors.js";
3
2
  import type {
4
3
  OcrCaptchaCandidate,
@@ -10,6 +9,13 @@ import type {
10
9
  OcrResult,
11
10
  ProviderOcrConfig,
12
11
  } from "../types.js";
12
+ import { readCapabilityErrorBody } from "./capability-response.js";
13
+ import {
14
+ captureCapability,
15
+ registerCapabilityInput,
16
+ tagCapability,
17
+ } from "./capability-telemetry.js";
18
+ import { readDiagnosticEnv, registerDiagnosticValue } from "./diagnostic-env.js";
13
19
  import { CLOUDFLARE_ACCOUNT_ID_ENV } from "./stt.js";
14
20
  import { createTimeoutController, isTimeoutLikeError } from "./timeout.js";
15
21
 
@@ -78,14 +84,17 @@ function createErrorOcrClient(options: ErrorOcrClientOptions): OcrContext {
78
84
  fix: options.fix,
79
85
  });
80
86
  };
81
- return {
82
- async recognize() {
83
- return unavailable();
84
- },
85
- async extractCaptchaText() {
86
- return unavailable();
87
+ return tagCapability(
88
+ {
89
+ async recognize() {
90
+ return unavailable();
91
+ },
92
+ async extractCaptchaText() {
93
+ return unavailable();
94
+ },
87
95
  },
88
- };
96
+ { backend: "unavailable", engine: "custom" },
97
+ );
89
98
  }
90
99
 
91
100
  export function createUnsupportedOcrClient(reason?: string): OcrContext {
@@ -249,6 +258,8 @@ function responseContent(payload: unknown, cloudflare: boolean, model: string):
249
258
  const choices = root?.choices;
250
259
  if (!Array.isArray(choices)) return undefined;
251
260
  const choice = unknownRecord(choices[0]);
261
+ if (typeof choice?.finish_reason === "string")
262
+ captureCapability({ finishReason: choice.finish_reason });
252
263
  if (typeof choice?.finish_reason === "string" && choice.finish_reason !== "stop") {
253
264
  throw incompleteResponseError(model, choice.finish_reason);
254
265
  }
@@ -305,7 +316,11 @@ function moondreamSseContent(body: string, model: string): string | undefined {
305
316
  terminalFinishReason = chunk.finish_reason;
306
317
  }
307
318
  }
308
- if (finalAnswer) return finalAnswer;
319
+ if (finalAnswer) {
320
+ captureCapability({ finishReason: "stop" });
321
+ return finalAnswer;
322
+ }
323
+ if (terminalFinishReason) captureCapability({ finishReason: terminalFinishReason });
309
324
  if (terminalFinishReason) throw incompleteResponseError(model, terminalFinishReason);
310
325
  if (firstDecodingFailure) throw malformedResponseError(model, firstDecodingFailure);
311
326
  return finalAnswer;
@@ -361,48 +376,57 @@ export function createCloudflareWorkersAiOcrClient(
361
376
  ): OcrContext {
362
377
  const model = options.model ?? DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL;
363
378
  const runFetch = options.fetch ?? fetch;
364
- return createOcrClient(model, async (request) => {
365
- const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
366
- try {
367
- let response: Response;
379
+ return tagCapability(
380
+ createOcrClient(model, async (request) => {
381
+ registerCapabilityInput(request.image);
382
+ registerDiagnosticValue(options.apiToken);
383
+ registerDiagnosticValue(`Bearer ${options.apiToken}`);
384
+ const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
368
385
  try {
369
- response = await runFetch(
370
- `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(options.accountId)}/ai/run/${model}`,
371
- {
372
- method: "POST",
373
- headers: {
374
- Authorization: `Bearer ${options.apiToken}`,
375
- "Content-Type": "application/json",
386
+ let response: Response;
387
+ try {
388
+ response = await runFetch(
389
+ `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(options.accountId)}/ai/run/${model}`,
390
+ {
391
+ method: "POST",
392
+ headers: {
393
+ Authorization: `Bearer ${options.apiToken}`,
394
+ "Content-Type": "application/json",
395
+ },
396
+ body: JSON.stringify(
397
+ isMoondreamModel(model)
398
+ ? moondreamPayload(request)
399
+ : cloudflareMessagesPayload(request, model),
400
+ ),
401
+ signal: timeout.controller.signal,
376
402
  },
377
- body: JSON.stringify(
378
- isMoondreamModel(model)
379
- ? moondreamPayload(request)
380
- : cloudflareMessagesPayload(request, model),
381
- ),
382
- signal: timeout.controller.signal,
383
- },
384
- );
403
+ );
404
+ } catch (error) {
405
+ throw toOcrTransportError(error);
406
+ }
407
+ captureCapability({ status: response.status });
408
+ if (!response.ok) {
409
+ const echoed = await readCapabilityErrorBody(response, timeout.controller.signal);
410
+ captureCapability({ diagnostics: echoed });
411
+ throw new TransportError("OCR upstream request failed", {
412
+ code: "OCR_UPSTREAM_FAILED",
413
+ status: response.status,
414
+ upstreamStatus: response.status,
415
+ });
416
+ }
417
+ const text = isMoondreamModel(model)
418
+ ? moondreamSseContent(await response.text(), model)
419
+ : responseContent(await responseJson(response, model), true, model);
420
+ if (!text) throw emptyResponseError(model);
421
+ return { text, model };
385
422
  } catch (error) {
386
423
  throw toOcrTransportError(error);
424
+ } finally {
425
+ timeout.clear();
387
426
  }
388
- if (!response.ok) {
389
- throw new TransportError("OCR upstream request failed", {
390
- code: "OCR_UPSTREAM_FAILED",
391
- status: response.status,
392
- upstreamStatus: response.status,
393
- });
394
- }
395
- const text = isMoondreamModel(model)
396
- ? moondreamSseContent(await response.text(), model)
397
- : responseContent(await responseJson(response, model), true, model);
398
- if (!text) throw emptyResponseError(model);
399
- return { text, model };
400
- } catch (error) {
401
- throw toOcrTransportError(error);
402
- } finally {
403
- timeout.clear();
404
- }
405
- });
427
+ }),
428
+ { backend: "cloudflare-workers-ai", engine: "workers-ai", model },
429
+ );
406
430
  }
407
431
 
408
432
  export function createOpenAiCompatibleOcrClient(
@@ -410,38 +434,49 @@ export function createOpenAiCompatibleOcrClient(
410
434
  ): OcrContext {
411
435
  const model = options.model;
412
436
  const runFetch = options.fetch ?? fetch;
413
- return createOcrClient(model, async (request) => {
414
- const headers: Record<string, string> = { "Content-Type": "application/json" };
415
- if (options.apiKey) headers.Authorization = `Bearer ${options.apiKey}`;
416
- const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
417
- try {
418
- let response: Response;
437
+ return tagCapability(
438
+ createOcrClient(model, async (request) => {
439
+ registerCapabilityInput(request.image);
440
+ if (options.apiKey) {
441
+ registerDiagnosticValue(options.apiKey);
442
+ registerDiagnosticValue(`Bearer ${options.apiKey}`);
443
+ }
444
+ const headers: Record<string, string> = { "Content-Type": "application/json" };
445
+ if (options.apiKey) headers.Authorization = `Bearer ${options.apiKey}`;
446
+ const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
419
447
  try {
420
- response = await runFetch(`${options.baseUrl.replace(/\/+$/u, "")}/chat/completions`, {
421
- method: "POST",
422
- headers,
423
- body: JSON.stringify(messagesPayload(request, model)),
424
- signal: timeout.controller.signal,
425
- });
448
+ let response: Response;
449
+ try {
450
+ response = await runFetch(`${options.baseUrl.replace(/\/+$/u, "")}/chat/completions`, {
451
+ method: "POST",
452
+ headers,
453
+ body: JSON.stringify(messagesPayload(request, model)),
454
+ signal: timeout.controller.signal,
455
+ });
456
+ } catch (error) {
457
+ throw toOcrTransportError(error);
458
+ }
459
+ captureCapability({ status: response.status });
460
+ if (!response.ok) {
461
+ const echoed = await readCapabilityErrorBody(response, timeout.controller.signal);
462
+ captureCapability({ diagnostics: echoed });
463
+ throw new TransportError("OCR upstream request failed", {
464
+ code: "OCR_UPSTREAM_FAILED",
465
+ status: response.status,
466
+ upstreamStatus: response.status,
467
+ });
468
+ }
469
+ const text = responseContent(await responseJson(response, model), false, model);
470
+ if (!text) throw emptyResponseError(model);
471
+ return { text, model };
426
472
  } catch (error) {
427
473
  throw toOcrTransportError(error);
474
+ } finally {
475
+ timeout.clear();
428
476
  }
429
- if (!response.ok) {
430
- throw new TransportError("OCR upstream request failed", {
431
- code: "OCR_UPSTREAM_FAILED",
432
- status: response.status,
433
- upstreamStatus: response.status,
434
- });
435
- }
436
- const text = responseContent(await responseJson(response, model), false, model);
437
- if (!text) throw emptyResponseError(model);
438
- return { text, model };
439
- } catch (error) {
440
- throw toOcrTransportError(error);
441
- } finally {
442
- timeout.clear();
443
- }
444
- });
477
+ }),
478
+ { backend: "openai-compatible", engine: "openai-compatible", model },
479
+ );
445
480
  }
446
481
 
447
482
  function cleanCaptchaText(text: string): string {
@@ -140,7 +140,8 @@ const MAX_INGESTIBLE_ARRAY_LENGTH = 64;
140
140
  const MAX_INGESTIBLE_OBJECT_KEYS = 32;
141
141
  const MAX_INGESTIBLE_DEPTH = 4;
142
142
  const INGESTIBLE_TOKEN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$/;
143
- const HEADER_PRIORITY = [
143
+ /** @internal */
144
+ export const HEADER_PRIORITY = [
144
145
  "proxy",
145
146
  "resolver",
146
147
  "native",
@@ -0,0 +1,50 @@
1
+ import type { ProviderCache, ProviderDefinition, ProviderProxyPolicy } from "../types.js";
2
+ import type { ResolverRuntimeOptions } from "./resolver.js";
3
+ import type { ResolverTelemetrySink } from "./resolver-telemetry.js";
4
+ import type { BrowserTelemetrySink } from "./browser-telemetry.js";
5
+
6
+ /** Normalize the `proxy` declaration shorthand (`true`/`false`) into the policy object the resolver chain consumes. */
7
+ export function resolveNativeProxyPolicy(
8
+ provider: ProviderDefinition,
9
+ ): ProviderProxyPolicy | undefined {
10
+ if (typeof provider.proxy === "object") return provider.proxy;
11
+ if (provider.proxy === true) return { mode: "optional" };
12
+ if (provider.proxy === false) return { mode: "disabled" };
13
+ return undefined;
14
+ }
15
+
16
+ /**
17
+ * One option set for every SDK-built resolver chain — the server's ctx.resolver and automatic
18
+ * SBSD solve, and the CLI helper contexts — so they share allowed hosts, cache, identity scope,
19
+ * proxy intent, and the telemetry sink. `identityScope` is server-owned; CLI contexts pass none.
20
+ */
21
+ export function createResolverRuntimeOptions(
22
+ provider: ProviderDefinition,
23
+ cache: ProviderCache,
24
+ identityScope: string | undefined,
25
+ proxyPolicy: ProviderProxyPolicy | undefined,
26
+ proxyClientOptions: Omit<
27
+ NonNullable<ResolverRuntimeOptions["proxyIntent"]>,
28
+ "mode" | "userAgent"
29
+ >,
30
+ stealthProfile: { readonly userAgent: string } | undefined,
31
+ telemetry: ResolverTelemetrySink,
32
+ browserTelemetry?: BrowserTelemetrySink,
33
+ ): ResolverRuntimeOptions {
34
+ return {
35
+ allowedHosts: provider.allowedHosts,
36
+ cache,
37
+ telemetry,
38
+ browserTelemetry,
39
+ ...(identityScope === undefined ? {} : { identityScope }),
40
+ ...(proxyPolicy
41
+ ? {
42
+ proxyIntent: {
43
+ mode: proxyPolicy.mode,
44
+ ...proxyClientOptions,
45
+ ...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
46
+ },
47
+ }
48
+ : {}),
49
+ };
50
+ }
@@ -2,8 +2,12 @@ import { ProviderError } from "../errors.js";
2
2
  import type { ChallengeSolution, ProviderChallenge, ResolverContext } from "../types.js";
3
3
  import type { TraceRecorder } from "./trace.js";
4
4
  import type { ResolverTelemetryOutcome, ResolverTelemetrySink } from "./resolver-telemetry.js";
5
+ import type { BrowserTelemetrySink } from "./browser-telemetry.js";
5
6
 
6
- type ResolverTelemetryBinding = (sink: ResolverTelemetrySink) => ResolverContext;
7
+ type ResolverTelemetryBinding = (
8
+ sink: ResolverTelemetrySink,
9
+ browserSink?: BrowserTelemetrySink,
10
+ ) => ResolverContext;
7
11
  const telemetryBindings = new WeakMap<ResolverContext, ResolverTelemetryBinding>();
8
12
 
9
13
  /** Internal contract: reconstruct a chain with a new request sink, without mutating the host chain. */
@@ -27,6 +31,7 @@ export function inheritResolverTelemetryBinding(
27
31
  export function bindResolverTelemetry(
28
32
  resolver: ResolverContext,
29
33
  sink: ResolverTelemetrySink | undefined,
34
+ browserSink?: BrowserTelemetrySink,
30
35
  ): ResolverContext {
31
36
  if (!sink) return resolver;
32
37
  const metadata = (
@@ -34,9 +39,9 @@ export function bindResolverTelemetry(
34
39
  readonly [RESOLVER_INSTRUMENTATION_METADATA]?: { readonly target: ResolverContext };
35
40
  }
36
41
  )[RESOLVER_INSTRUMENTATION_METADATA];
37
- if (metadata) return bindResolverTelemetry(metadata.target, sink);
42
+ if (metadata) return bindResolverTelemetry(metadata.target, sink, browserSink);
38
43
  const bind = telemetryBindings.get(resolver);
39
- if (bind) return bind(sink);
44
+ if (bind) return bind(sink, browserSink);
40
45
  const wrapper: ResolverSolveWithRecorder = {
41
46
  async solve(challenge, signal, recorder) {
42
47
  const startedAt = Date.now();
@@ -74,7 +79,7 @@ export function bindResolverTelemetry(
74
79
  }
75
80
 
76
81
  function createOpaqueResolverTelemetryBinding(resolver: ResolverContext): ResolverTelemetryBinding {
77
- return (sink) => bindResolverTelemetry(resolver, sink);
82
+ return (sink, browserSink) => bindResolverTelemetry(resolver, sink, browserSink);
78
83
  }
79
84
 
80
85
  export const RESOLVER_INSTRUMENTATION_METADATA = Symbol.for(
@@ -147,7 +147,7 @@ function boundedInteger(value: number): number {
147
147
  return Math.max(0, Math.floor(Number.isFinite(value) ? value : 0));
148
148
  }
149
149
 
150
- function boundedText(value: string, redact?: (text: string) => string): string {
150
+ export function boundedText(value: string, redact?: (text: string) => string): string {
151
151
  let result = value;
152
152
  try {
153
153
  result = redact?.(value) ?? value;