@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,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;
@@ -8,6 +8,7 @@ import type {
8
8
  } from "../../types.js";
9
9
  import { type BrowserClientOptions, createBrowserClient } from "../browser.js";
10
10
  import type { TraceRecorder } from "../trace.js";
11
+ import type { BrowserTelemetrySink } from "../browser-telemetry.js";
11
12
  import { resolverChallengeIssuingIdentity } from "./bindings.js";
12
13
  import { assertResolverHostAllowed, normalizedResolverHostname } from "./hosts.js";
13
14
  import {
@@ -31,6 +32,59 @@ type SupportedBrowserChallengeKind = keyof typeof SUCCESS_COOKIE_NAMES;
31
32
 
32
33
  type BrowserClientFactory = (options: BrowserClientOptions) => BrowserClient;
33
34
 
35
+ const RESOLVER_PAGE_METHODS = new Set([
36
+ "goto",
37
+ "evaluate",
38
+ "fill",
39
+ "click",
40
+ "type",
41
+ "waitForSelector",
42
+ "content",
43
+ "screenshot",
44
+ "cookies",
45
+ "url",
46
+ "title",
47
+ "userAgent",
48
+ ]);
49
+
50
+ function instrumentResolverBrowser(client: BrowserClient, recorder: TraceRecorder): BrowserClient {
51
+ const wrapPage = (page: BrowserPage): BrowserPage =>
52
+ new Proxy(page, {
53
+ get(target, property, receiver) {
54
+ const value = Reflect.get(target, property, receiver);
55
+ if (
56
+ typeof property !== "string" ||
57
+ !RESOLVER_PAGE_METHODS.has(property) ||
58
+ typeof value !== "function"
59
+ )
60
+ return value;
61
+ return (...args: unknown[]) =>
62
+ recorder.runSpan(`browser.page.${property}`, () => Reflect.apply(value, target, args));
63
+ },
64
+ });
65
+ return new Proxy(client, {
66
+ get(target, property, receiver) {
67
+ const value = Reflect.get(target, property, receiver);
68
+ if (property === "newPage" && typeof value === "function")
69
+ return () =>
70
+ recorder.runSpan("browser.newPage", async () =>
71
+ wrapPage(await Reflect.apply(value, target, [])),
72
+ );
73
+ if (property === "rawPage" && typeof value === "function")
74
+ return () =>
75
+ recorder.runSpan("browser.rawPage", async () =>
76
+ wrapPage(await Reflect.apply(value, target, [])),
77
+ );
78
+ if (property === "withIsolatedContext" && typeof value === "function")
79
+ return (handler: (page: BrowserPage) => Promise<unknown>) =>
80
+ recorder.runSpan("browser.withIsolatedContext", () =>
81
+ Reflect.apply(value, target, [(page: BrowserPage) => handler(wrapPage(page))]),
82
+ );
83
+ return value;
84
+ },
85
+ });
86
+ }
87
+
34
88
  let createResolverBrowserClient: BrowserClientFactory = createBrowserClient;
35
89
 
36
90
  /** Internal test seam; deliberately not re-exported from the package root. */
@@ -53,6 +107,7 @@ export interface BrowserResolverVendorOptions {
53
107
  readonly pollIntervalMs?: number;
54
108
  readonly allowedHosts: readonly string[];
55
109
  readonly createClient?: BrowserClientFactory;
110
+ readonly telemetry?: BrowserTelemetrySink;
56
111
  }
57
112
 
58
113
  export interface BrowserResolverVendorAdapter extends ResolverVendorAdapter {
@@ -67,9 +122,7 @@ export interface BrowserResolverVendorAdapter extends ResolverVendorAdapter {
67
122
 
68
123
  class BrowserSolveTimeoutError extends Error {
69
124
  constructor(blockedRequests: readonly string[]) {
70
- super(
71
- `Browser resolver solve budget elapsed${formatBlockedRequests(blockedRequests)}`,
72
- );
125
+ super(`Browser resolver solve budget elapsed${formatBlockedRequests(blockedRequests)}`);
73
126
  this.name = "BrowserSolveTimeoutError";
74
127
  }
75
128
  }
@@ -274,10 +327,7 @@ async function solveInPage(
274
327
  ],
275
328
  },
276
329
  async () => {
277
- const userAgent = await raceWithAbort(
278
- () => page.userAgent(),
279
- signal,
280
- );
330
+ const userAgent = await raceWithAbort(() => page.userAgent(), signal);
281
331
  try {
282
332
  await raceWithAbort(
283
333
  () =>
@@ -467,7 +517,15 @@ export function createBrowserResolverVendorAdapter(
467
517
  ...(proxyUrl === undefined ? {} : { proxy: proxyUrl }),
468
518
  requireCdpPool: cdpUrl !== undefined,
469
519
  serviceWorkers: "block",
520
+ telemetry: options.telemetry,
470
521
  });
522
+ /**
523
+ * Direct vendor callers without a telemetry sink keep the historical trace shape.
524
+ * Bound server requests record browser page spans under resolver.vendor.attempt,
525
+ * with resolver.vendor.cleanup as a sibling of the browser context span.
526
+ */
527
+ if (traceRecorder && options.telemetry)
528
+ client = instrumentResolverBrowser(client, traceRecorder);
471
529
  const contextOperation = client.withIsolatedContext(async (page) => {
472
530
  handlerEntered = true;
473
531
  return await solveInPage(
@@ -1,4 +1,25 @@
1
1
  import { ProviderError } from "../../errors.js";
2
+ import type { ProviderResolverVendor } from "../../types.js";
3
+
4
+ /**
5
+ * Exact SDK-owned service hosts each vendor's adapter may reach through its bound
6
+ * transport, in addition to the provider's declared `allowedHosts`. This table is
7
+ * the trust boundary for `ResolverVendorAdapter.transportAllowedHosts`: a
8
+ * declaration outside its vendor's entry is rejected, whoever supplied the adapter.
9
+ * Only Hyper's observed-IP reflector rides the identity-bound transport (ADR-0008
10
+ * v1.1 amend, PR #251); every other vendor talks to its own service directly.
11
+ * Frozen at runtime, not just in the type: the Hyper adapter hands its entry out by
12
+ * reference as `transportAllowedHosts`, so a mutable table would let any holder of a
13
+ * registry adapter widen the boundary for every later adapter in the process.
14
+ */
15
+ export const RESOLVER_VENDOR_TRANSPORT_HOSTS = Object.freeze({
16
+ "2captcha": Object.freeze([] as const),
17
+ browser: Object.freeze([] as const),
18
+ capmonster: Object.freeze([] as const),
19
+ capsolver: Object.freeze([] as const),
20
+ custom: Object.freeze([] as const),
21
+ hypersolutions: Object.freeze(["ip.hypersolutions.co"] as const),
22
+ }) satisfies Readonly<Record<ProviderResolverVendor, readonly string[]>>;
2
23
 
3
24
  export function normalizedResolverHostname(hostname: string): string {
4
25
  return hostname.trim().toLowerCase().replace(/\.$/, "");
@@ -36,3 +57,25 @@ export function assertResolverHostAllowed(
36
57
  fix: "Add the exact target hostname to the provider's allowedHosts declaration.",
37
58
  });
38
59
  }
60
+
61
+ export function assertResolverVendorTransportHosts(
62
+ vendor: ProviderResolverVendor,
63
+ declaredHosts: readonly string[],
64
+ ): void {
65
+ // A vendor id outside the table (only reachable from untyped callers) owns no hosts and
66
+ // is rejected below like any other overreach; `hasOwn` keeps prototype keys out too.
67
+ const ownedHosts: readonly string[] = Object.hasOwn(RESOLVER_VENDOR_TRANSPORT_HOSTS, vendor)
68
+ ? RESOLVER_VENDOR_TRANSPORT_HOSTS[vendor]
69
+ : [];
70
+ for (const declaredHost of declaredHosts) {
71
+ const normalizedHost = normalizedResolverHostname(declaredHost);
72
+ if (ownedHosts.some((host) => normalizedResolverHostname(host) === normalizedHost)) continue;
73
+ throw new ProviderError(
74
+ `Resolver vendor "${vendor}" may not declare transport host "${normalizedHost}"`,
75
+ {
76
+ code: "RESOLVER_VENDOR_HOST_NOT_ALLOWED",
77
+ fix: "Remove the host from transportAllowedHosts: an adapter reaches only the provider's allowedHosts plus the SDK-owned service hosts of its vendor.",
78
+ },
79
+ );
80
+ }
81
+ }
@@ -3,7 +3,7 @@ import { isIP } from "node:net";
3
3
  import type { ChallengeSolution, ProviderChallenge } from "../../types.js";
4
4
  import { recordPaidResolverCreate } from "../resolver-usage.js";
5
5
  import type { TraceRecorder } from "../trace.js";
6
- import { assertResolverHostAllowed } from "./hosts.js";
6
+ import { assertResolverHostAllowed, RESOLVER_VENDOR_TRANSPORT_HOSTS } from "./hosts.js";
7
7
  import {
8
8
  ResolverChallengeVerdictError,
9
9
  type ResolverIdentity,
@@ -21,7 +21,7 @@ const HYPER_IP_URL = "https://ip.hypersolutions.co/ip";
21
21
  * egress address the upstream will see. The payload-generation POST carries no
22
22
  * identity and goes direct, as in the measured zozotown source.
23
23
  */
24
- const HYPER_TRANSPORT_HOSTS = ["ip.hypersolutions.co"] as const;
24
+ const HYPER_TRANSPORT_HOSTS = RESOLVER_VENDOR_TRANSPORT_HOSTS.hypersolutions;
25
25
  const IP_RESPONSE_MAX_BYTES = 4_096;
26
26
  /** Measured bound shared by the script, the Hyper envelope, and the payload submission. */
27
27
  const BODY_MAX_BYTES = 1_000_000;
@@ -157,10 +157,11 @@ export interface ResolverVendorAdapter {
157
157
  readonly id: ProviderResolverVendor;
158
158
  readonly requiresTransport?: boolean | ((kind: ProviderChallengeKind) => boolean);
159
159
  /**
160
- * Exact SDK-owned service hosts this adapter may reach through its bound transport.
161
- * Honored for every adapter the chain runs, so whoever supplies `adapters` to
162
- * `createResolverClient` is the trust boundary; the engine path
163
- * (`createResolverClientFromEnv`) only constructs registry adapters.
160
+ * Exact SDK-owned service hosts this adapter may reach through its bound transport,
161
+ * in addition to the provider's `allowedHosts`. Every host must appear in the
162
+ * SDK-owned `RESOLVER_VENDOR_TRANSPORT_HOSTS` entry for `id`; the chain rejects any
163
+ * other declaration with `RESOLVER_VENDOR_HOST_NOT_ALLOWED`, whoever supplied the
164
+ * adapter. The transport handed to `solve` is revoked once `solve` settles.
164
165
  */
165
166
  readonly transportAllowedHosts?: readonly string[];
166
167
  supports(kind: ProviderChallengeKind): boolean;