@apifuse/provider-sdk 2.2.0-beta.61 → 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 (258) hide show
  1. package/AUTHORING.md +268 -9
  2. package/CHANGELOG.md +8 -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 +191 -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/handle-meta.d.ts +18 -2
  32. package/dist/handle-meta.js +30 -2
  33. package/dist/handle.d.ts +33 -12
  34. package/dist/handle.js +69 -24
  35. package/dist/i18n/error-messages.d.ts +86 -0
  36. package/dist/i18n/error-messages.js +192 -0
  37. package/dist/i18n/index.d.ts +1 -0
  38. package/dist/i18n/index.js +1 -0
  39. package/dist/i18n/keys.d.ts +12 -0
  40. package/dist/i18n/keys.js +76 -5
  41. package/dist/index.d.ts +10 -2
  42. package/dist/index.js +9 -1
  43. package/dist/lint.d.ts +10 -0
  44. package/dist/lint.js +440 -57
  45. package/dist/provider.d.ts +7 -5
  46. package/dist/provider.js +4 -2
  47. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  48. package/dist/runtime/browser-telemetry-binding.js +83 -0
  49. package/dist/runtime/browser-telemetry.d.ts +76 -0
  50. package/dist/runtime/browser-telemetry.js +165 -0
  51. package/dist/runtime/browser.d.ts +3 -0
  52. package/dist/runtime/browser.js +208 -47
  53. package/dist/runtime/cache-telemetry.d.ts +71 -0
  54. package/dist/runtime/cache-telemetry.js +177 -0
  55. package/dist/runtime/cache.js +67 -7
  56. package/dist/runtime/capability-response.d.ts +3 -0
  57. package/dist/runtime/capability-response.js +56 -0
  58. package/dist/runtime/capability-telemetry.d.ts +46 -0
  59. package/dist/runtime/capability-telemetry.js +68 -0
  60. package/dist/runtime/diagnostic-env.d.ts +3 -0
  61. package/dist/runtime/diagnostic-env.js +10 -1
  62. package/dist/runtime/engine-mode.d.ts +74 -0
  63. package/dist/runtime/engine-mode.js +152 -0
  64. package/dist/runtime/handle.js +15 -10
  65. package/dist/runtime/http-telemetry-binding.d.ts +10 -0
  66. package/dist/runtime/http-telemetry-binding.js +152 -0
  67. package/dist/runtime/http-telemetry-guard.d.ts +16 -0
  68. package/dist/runtime/http-telemetry-guard.js +202 -0
  69. package/dist/runtime/http-telemetry.d.ts +104 -0
  70. package/dist/runtime/http-telemetry.js +190 -0
  71. package/dist/runtime/http.d.ts +31 -0
  72. package/dist/runtime/http.js +356 -174
  73. package/dist/runtime/instrumentation.js +92 -13
  74. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  75. package/dist/runtime/ocr-telemetry.js +192 -0
  76. package/dist/runtime/ocr.js +30 -8
  77. package/dist/runtime/request-telemetry.d.ts +2 -0
  78. package/dist/runtime/request-telemetry.js +2 -1
  79. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  80. package/dist/runtime/resolver-runtime-options.js +33 -0
  81. package/dist/runtime/resolver-shared.d.ts +3 -2
  82. package/dist/runtime/resolver-shared.js +4 -4
  83. package/dist/runtime/resolver-telemetry.d.ts +1 -0
  84. package/dist/runtime/resolver-telemetry.js +1 -1
  85. package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
  86. package/dist/runtime/resolver-vendors/browser.js +46 -0
  87. package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
  88. package/dist/runtime/resolver-vendors/hosts.js +35 -0
  89. package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
  90. package/dist/runtime/resolver-vendors/types.d.ts +5 -4
  91. package/dist/runtime/resolver.d.ts +4 -1
  92. package/dist/runtime/resolver.js +46 -13
  93. package/dist/runtime/state-telemetry.d.ts +79 -0
  94. package/dist/runtime/state-telemetry.js +194 -0
  95. package/dist/runtime/state.d.ts +3 -0
  96. package/dist/runtime/state.js +26 -7
  97. package/dist/runtime/stealth-cookies.d.ts +5 -1
  98. package/dist/runtime/stealth-cookies.js +21 -1
  99. package/dist/runtime/stealth-owned-headers.d.ts +26 -0
  100. package/dist/runtime/stealth-owned-headers.js +37 -0
  101. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  102. package/dist/runtime/stealth-telemetry.js +179 -0
  103. package/dist/runtime/stealth.d.ts +4 -1
  104. package/dist/runtime/stealth.js +228 -85
  105. package/dist/runtime/stt-telemetry.d.ts +77 -0
  106. package/dist/runtime/stt-telemetry.js +176 -0
  107. package/dist/runtime/stt.js +15 -6
  108. package/dist/server/error-stack-frames.d.ts +35 -0
  109. package/dist/server/error-stack-frames.js +219 -0
  110. package/dist/server/index.d.ts +9 -0
  111. package/dist/server/index.js +5 -0
  112. package/dist/server/sdk-version.d.ts +3 -0
  113. package/dist/server/sdk-version.js +19 -0
  114. package/dist/server/self-test.js +1 -18
  115. package/dist/server/sensitive-values.d.ts +1 -1
  116. package/dist/server/sensitive-values.js +9 -0
  117. package/dist/server/serve-implementation.d.ts +53 -2
  118. package/dist/server/serve-implementation.js +369 -123
  119. package/dist/server/types.d.ts +1 -0
  120. package/dist/server/types.js +7 -0
  121. package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
  122. package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
  123. package/dist/stateful/stateful-provider-runtime-context.js +1 -0
  124. package/dist/types.d.ts +94 -1
  125. package/package.json +6 -1
  126. package/src/cli/commands.ts +14 -0
  127. package/src/cli/deployment-intent.ts +364 -0
  128. package/src/cli/migrate-deployment-intent.ts +1908 -0
  129. package/src/cli/migrate-provider-shape.ts +10 -4
  130. package/src/cli/resolver-runtime.ts +72 -0
  131. package/src/define.ts +13 -0
  132. package/src/dev.ts +9 -2
  133. package/src/engine.ts +38 -2
  134. package/src/error-resolution.ts +58 -0
  135. package/src/errors.ts +77 -1
  136. package/src/handle-meta.ts +39 -4
  137. package/src/handle.ts +121 -38
  138. package/src/i18n/error-messages.ts +255 -0
  139. package/src/i18n/index.ts +1 -0
  140. package/src/i18n/keys.ts +80 -6
  141. package/src/index.ts +91 -0
  142. package/src/lint.ts +552 -57
  143. package/src/provider.ts +20 -0
  144. package/src/runtime/browser-telemetry-binding.ts +92 -0
  145. package/src/runtime/browser-telemetry.ts +289 -0
  146. package/src/runtime/browser.ts +249 -65
  147. package/src/runtime/cache-telemetry.ts +247 -0
  148. package/src/runtime/cache.ts +68 -17
  149. package/src/runtime/capability-response.ts +53 -0
  150. package/src/runtime/capability-telemetry.ts +101 -0
  151. package/src/runtime/diagnostic-env.ts +11 -1
  152. package/src/runtime/engine-mode.ts +233 -0
  153. package/src/runtime/handle.ts +20 -10
  154. package/src/runtime/http-telemetry-binding.ts +162 -0
  155. package/src/runtime/http-telemetry-guard.ts +208 -0
  156. package/src/runtime/http-telemetry.ts +292 -0
  157. package/src/runtime/http.ts +457 -204
  158. package/src/runtime/instrumentation.ts +105 -16
  159. package/src/runtime/ocr-telemetry.ts +308 -0
  160. package/src/runtime/ocr.ts +109 -74
  161. package/src/runtime/request-telemetry.ts +2 -1
  162. package/src/runtime/resolver-runtime-options.ts +50 -0
  163. package/src/runtime/resolver-shared.ts +9 -4
  164. package/src/runtime/resolver-telemetry.ts +1 -1
  165. package/src/runtime/resolver-vendors/browser.ts +65 -7
  166. package/src/runtime/resolver-vendors/hosts.ts +43 -0
  167. package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
  168. package/src/runtime/resolver-vendors/types.ts +5 -4
  169. package/src/runtime/resolver.ts +64 -21
  170. package/src/runtime/state-telemetry.ts +298 -0
  171. package/src/runtime/state.ts +46 -45
  172. package/src/runtime/stealth-cookies.ts +24 -1
  173. package/src/runtime/stealth-owned-headers.ts +41 -0
  174. package/src/runtime/stealth-telemetry.ts +304 -0
  175. package/src/runtime/stealth.ts +355 -150
  176. package/src/runtime/stt-telemetry.ts +282 -0
  177. package/src/runtime/stt.ts +93 -71
  178. package/src/server/error-stack-frames.ts +214 -0
  179. package/src/server/index.ts +66 -0
  180. package/src/server/sdk-version.ts +22 -0
  181. package/src/server/self-test.ts +1 -21
  182. package/src/server/sensitive-values.ts +14 -0
  183. package/src/server/serve-implementation.ts +601 -157
  184. package/src/server/types.ts +7 -0
  185. package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
  186. package/src/stateful/stateful-provider-runtime-context.ts +4 -0
  187. package/src/types.ts +99 -1
  188. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
  189. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
  190. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
  191. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
  192. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
  193. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
  194. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
  195. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
  196. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
  197. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
  198. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
  199. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
  200. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
  201. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
  202. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
  203. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
  204. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
  205. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
  206. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
  207. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
  208. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
  209. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
  210. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
  211. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
  212. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
  213. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
  214. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
  215. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
  216. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
  217. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
  218. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
  219. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
  220. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
  221. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
  222. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
  244. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
  245. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
  246. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
  247. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
  248. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
  249. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
  250. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
  251. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
  252. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
  253. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
  254. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
  255. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
  256. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
  257. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
  258. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
@@ -1,3 +1,4 @@
1
+ import { runCapabilitySpan } from "./capability-telemetry.js";
1
2
  import { registerDiagnosticSensitiveValues } from "./diagnostic-redactor.js";
2
3
  import type {
3
4
  HttpStreamResponse,
@@ -35,9 +36,26 @@ export type InstrumentedProviderContext<T extends Pick<ProviderContext, "trace">
35
36
  trace: TraceContext;
36
37
  };
37
38
 
38
- type InstrumentedNamespace = "http" | "stealth" | "browser" | "session" | "state" | "resolver";
39
-
40
- const BROWSER_PAGE_METHODS = new Set(["goto", "fill", "click", "type", "waitForSelector"]);
39
+ type InstrumentedNamespace =
40
+ | "http"
41
+ | "stealth"
42
+ | "browser"
43
+ | "session"
44
+ | "state"
45
+ | "resolver"
46
+ | "ocr"
47
+ | "stt";
48
+
49
+ const BROWSER_PAGE_METHODS = new Set([
50
+ "goto",
51
+ "fill",
52
+ "click",
53
+ "type",
54
+ "waitForSelector",
55
+ "evaluate",
56
+ "content",
57
+ "screenshot",
58
+ ]);
41
59
  const DIAGNOSTIC_BASE_URL = "http://apifuse-instrumentation.invalid";
42
60
 
43
61
  type RequestDiagnostics = {
@@ -398,9 +416,19 @@ function buildSpanAttributes(
398
416
  attributes.method = method;
399
417
  }
400
418
 
401
- if (status !== undefined && (namespace === "http" || namespace === "stealth")) {
419
+ if (
420
+ status !== undefined &&
421
+ (namespace === "http" || namespace === "stealth" || namespace === "ocr" || namespace === "stt")
422
+ ) {
402
423
  attributes.status = status;
403
424
  }
425
+ if ((namespace === "ocr" || namespace === "stt") && result && typeof result === "object") {
426
+ if ("model" in result && typeof result.model === "string") attributes.model = result.model;
427
+ if ("durationMs" in result && typeof result.durationMs === "number")
428
+ attributes.duration_ms = result.durationMs;
429
+ if ("warnings" in result && Array.isArray(result.warnings))
430
+ attributes.warnings = result.warnings.length;
431
+ }
404
432
 
405
433
  if (duration !== undefined) {
406
434
  attributes.duration_ms = duration;
@@ -538,18 +566,33 @@ function wrapPage<T extends object>(page: T, trace: TraceContext): T {
538
566
  const methodName = String(property);
539
567
  const wrapped = (...args: unknown[]) => {
540
568
  let elapsedMs = 0;
569
+ const diagnostics = snapshotRequestDiagnostics("browser", methodName, args);
570
+ registerDiagnosticSensitiveValues(trace, diagnostics.sensitiveValues);
541
571
 
542
572
  return recorder.runSpan(
543
- `browser.page.${methodName}`,
573
+ ["evaluate", "content", "screenshot"].includes(methodName)
574
+ ? `browser.${methodName}`
575
+ : `browser.page.${methodName}`,
544
576
  async () => {
545
577
  const startedAt = Date.now();
546
- const result = await Reflect.apply(value, pageTarget, args);
578
+ let result: unknown;
579
+ try {
580
+ result = await Reflect.apply(value, pageTarget, args);
581
+ } catch (error) {
582
+ throw sanitizeRequestError(error, diagnostics);
583
+ }
547
584
  elapsedMs = Date.now() - startedAt;
548
585
  return result;
549
586
  },
550
587
  {
551
- onSuccess: () => getBrowserPageAttributes(methodName, args, elapsedMs),
552
- onError: (error) => getBrowserPageAttributes(methodName, args, undefined, error),
588
+ onSuccess: () => ({
589
+ ...getBrowserPageAttributes(methodName, args, elapsedMs),
590
+ ...(diagnostics.traceUrl ? { url: diagnostics.traceUrl } : {}),
591
+ }),
592
+ onError: (error) => ({
593
+ ...getBrowserPageAttributes(methodName, args, undefined, error),
594
+ ...(diagnostics.traceUrl ? { url: diagnostics.traceUrl } : {}),
595
+ }),
553
596
  },
554
597
  );
555
598
  };
@@ -621,10 +664,15 @@ function wrapNamespace<T extends object>(
621
664
  trace: TraceContext,
622
665
  shouldInstrument?: (methodName: string, args: unknown[]) => boolean,
623
666
  ): T {
624
- const recorder = getTraceRecorder(trace);
625
- if (!recorder) {
626
- return target;
627
- }
667
+ const baseRecorder = getTraceRecorder(trace);
668
+ if (!baseRecorder) return target;
669
+ const recorder: NonNullable<ReturnType<typeof getTraceRecorder>> =
670
+ namespace === "ocr" || namespace === "stt"
671
+ ? {
672
+ runSpan: (name, fn, options) =>
673
+ runCapabilitySpan(target, () => baseRecorder.runSpan(name, fn, options)),
674
+ }
675
+ : baseRecorder;
628
676
 
629
677
  const wrappedMethods = new Map<PropertyKey, unknown>();
630
678
  const resolverMetadata =
@@ -719,6 +767,32 @@ function wrapNamespace<T extends object>(
719
767
  return wrapped;
720
768
  }
721
769
 
770
+ if (namespace === "browser" && property === "rawPage") {
771
+ if (wrappedMethods.has(property)) return wrappedMethods.get(property);
772
+ const wrapped = (...args: unknown[]) =>
773
+ recorder.runSpan("browser.rawPage", async () => {
774
+ const page = await Reflect.apply(value, namespaceTarget, args);
775
+ return wrapPage(page, trace);
776
+ });
777
+ wrappedMethods.set(property, wrapped);
778
+ return wrapped;
779
+ }
780
+
781
+ if (namespace === "browser" && property === "withIsolatedContext") {
782
+ if (wrappedMethods.has(property)) return wrappedMethods.get(property);
783
+ const wrapped = (handler: unknown, ...args: unknown[]) =>
784
+ recorder.runSpan("browser.withIsolatedContext", async () => {
785
+ if (typeof handler !== "function")
786
+ return Reflect.apply(value, namespaceTarget, [handler, ...args]);
787
+ return Reflect.apply(value, namespaceTarget, [
788
+ (page: object) => Reflect.apply(handler, undefined, [wrapPage(page, trace)]),
789
+ ...args,
790
+ ]);
791
+ });
792
+ wrappedMethods.set(property, wrapped);
793
+ return wrapped;
794
+ }
795
+
722
796
  if (wrappedMethods.has(property)) {
723
797
  return wrappedMethods.get(property);
724
798
  }
@@ -727,18 +801,31 @@ function wrapNamespace<T extends object>(
727
801
  if (namespace === "browser") {
728
802
  const wrapped = (...args: unknown[]) => {
729
803
  let elapsedMs = 0;
804
+ const diagnostics = snapshotRequestDiagnostics("browser", methodName, args);
805
+ registerDiagnosticSensitiveValues(trace, diagnostics.sensitiveValues);
730
806
 
731
807
  return recorder.runSpan(
732
808
  `browser.${methodName}`,
733
809
  async () => {
734
810
  const startedAt = Date.now();
735
- const result = await Reflect.apply(value, namespaceTarget, args);
811
+ let result: unknown;
812
+ try {
813
+ result = await Reflect.apply(value, namespaceTarget, args);
814
+ } catch (error) {
815
+ throw sanitizeRequestError(error, diagnostics);
816
+ }
736
817
  elapsedMs = Date.now() - startedAt;
737
818
  return result;
738
819
  },
739
820
  {
740
- onSuccess: () => getBrowserPageAttributes(methodName, args, elapsedMs),
741
- onError: (error) => getBrowserPageAttributes(methodName, args, undefined, error),
821
+ onSuccess: () => ({
822
+ ...getBrowserPageAttributes(methodName, args, elapsedMs),
823
+ ...(diagnostics.traceUrl ? { url: diagnostics.traceUrl } : {}),
824
+ }),
825
+ onError: (error) => ({
826
+ ...getBrowserPageAttributes(methodName, args, undefined, error),
827
+ ...(diagnostics.traceUrl ? { url: diagnostics.traceUrl } : {}),
828
+ }),
742
829
  },
743
830
  );
744
831
  };
@@ -878,7 +965,9 @@ export function wrapWithInstrumentation<T extends Pick<ProviderContext, "trace">
878
965
  property === "browser" ||
879
966
  property === "session" ||
880
967
  property === "state" ||
881
- property === "resolver"
968
+ property === "resolver" ||
969
+ property === "ocr" ||
970
+ property === "stt"
882
971
  ) {
883
972
  const namespace = property;
884
973
  if (wrappedTargets.has(namespace)) {
@@ -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
+ }