@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
@@ -117,6 +117,7 @@ export type ResolverTelemetryHeaderPayload = {
117
117
  c?: ClosedEnum<string>;
118
118
  }[];
119
119
  };
120
+ export declare function boundedText(value: string, redact?: (text: string) => string): string;
120
121
  export declare class ResolverTelemetryCollector implements ResolverTelemetrySink, TelemetryContributor<ResolverTelemetryLogPayload, ResolverTelemetryHeaderPayload> {
121
122
  #private;
122
123
  readonly key: "resolver";
@@ -8,7 +8,7 @@ const HEADER_TOKEN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$/;
8
8
  function boundedInteger(value) {
9
9
  return Math.max(0, Math.floor(Number.isFinite(value) ? value : 0));
10
10
  }
11
- function boundedText(value, redact) {
11
+ export function boundedText(value, redact) {
12
12
  let result = value;
13
13
  try {
14
14
  result = redact?.(value) ?? value;
@@ -1,6 +1,7 @@
1
1
  import type { BrowserClient, ChallengeSolution, ProviderChallenge } from "../../types.js";
2
2
  import { type BrowserClientOptions } from "../browser.js";
3
3
  import type { TraceRecorder } from "../trace.js";
4
+ import type { BrowserTelemetrySink } from "../browser-telemetry.js";
4
5
  import { type ResolverIdentity, type ResolverVendorAdapter } from "./types.js";
5
6
  type BrowserClientFactory = (options: BrowserClientOptions) => BrowserClient;
6
7
  /** Internal test seam; deliberately not re-exported from the package root. */
@@ -11,6 +12,7 @@ export interface BrowserResolverVendorOptions {
11
12
  readonly pollIntervalMs?: number;
12
13
  readonly allowedHosts: readonly string[];
13
14
  readonly createClient?: BrowserClientFactory;
15
+ readonly telemetry?: BrowserTelemetrySink;
14
16
  }
15
17
  export interface BrowserResolverVendorAdapter extends ResolverVendorAdapter {
16
18
  readonly id: "browser";
@@ -12,6 +12,44 @@ const SUCCESS_COOKIE_NAMES = {
12
12
  aws_waf: "aws-waf-token",
13
13
  cloudflare_interstitial: "cf_clearance",
14
14
  };
15
+ const RESOLVER_PAGE_METHODS = new Set([
16
+ "goto",
17
+ "evaluate",
18
+ "fill",
19
+ "click",
20
+ "type",
21
+ "waitForSelector",
22
+ "content",
23
+ "screenshot",
24
+ "cookies",
25
+ "url",
26
+ "title",
27
+ "userAgent",
28
+ ]);
29
+ function instrumentResolverBrowser(client, recorder) {
30
+ const wrapPage = (page) => new Proxy(page, {
31
+ get(target, property, receiver) {
32
+ const value = Reflect.get(target, property, receiver);
33
+ if (typeof property !== "string" ||
34
+ !RESOLVER_PAGE_METHODS.has(property) ||
35
+ typeof value !== "function")
36
+ return value;
37
+ return (...args) => recorder.runSpan(`browser.page.${property}`, () => Reflect.apply(value, target, args));
38
+ },
39
+ });
40
+ return new Proxy(client, {
41
+ get(target, property, receiver) {
42
+ const value = Reflect.get(target, property, receiver);
43
+ if (property === "newPage" && typeof value === "function")
44
+ return () => recorder.runSpan("browser.newPage", async () => wrapPage(await Reflect.apply(value, target, [])));
45
+ if (property === "rawPage" && typeof value === "function")
46
+ return () => recorder.runSpan("browser.rawPage", async () => wrapPage(await Reflect.apply(value, target, [])));
47
+ if (property === "withIsolatedContext" && typeof value === "function")
48
+ return (handler) => recorder.runSpan("browser.withIsolatedContext", () => Reflect.apply(value, target, [(page) => handler(wrapPage(page))]));
49
+ return value;
50
+ },
51
+ });
52
+ }
15
53
  let createResolverBrowserClient = createBrowserClient;
16
54
  /** Internal test seam; deliberately not re-exported from the package root. */
17
55
  export function swapBrowserResolverClientFactoryForTests(factory) {
@@ -324,7 +362,15 @@ export function createBrowserResolverVendorAdapter(options) {
324
362
  ...(proxyUrl === undefined ? {} : { proxy: proxyUrl }),
325
363
  requireCdpPool: cdpUrl !== undefined,
326
364
  serviceWorkers: "block",
365
+ telemetry: options.telemetry,
327
366
  });
367
+ /**
368
+ * Direct vendor callers without a telemetry sink keep the historical trace shape.
369
+ * Bound server requests record browser page spans under resolver.vendor.attempt,
370
+ * with resolver.vendor.cleanup as a sibling of the browser context span.
371
+ */
372
+ if (traceRecorder && options.telemetry)
373
+ client = instrumentResolverBrowser(client, traceRecorder);
328
374
  const contextOperation = client.withIsolatedContext(async (page) => {
329
375
  handlerEntered = true;
330
376
  return await solveInPage(page, challengeKind, challenge.pageUrl, options.allowedHosts, SUCCESS_COOKIE_NAMES[challengeKind], pollIntervalMs, options.timeoutMs, blockedRequests, solveController.signal);
@@ -1,2 +1,23 @@
1
+ import type { ProviderResolverVendor } from "../../types.js";
2
+ /**
3
+ * Exact SDK-owned service hosts each vendor's adapter may reach through its bound
4
+ * transport, in addition to the provider's declared `allowedHosts`. This table is
5
+ * the trust boundary for `ResolverVendorAdapter.transportAllowedHosts`: a
6
+ * declaration outside its vendor's entry is rejected, whoever supplied the adapter.
7
+ * Only Hyper's observed-IP reflector rides the identity-bound transport (ADR-0008
8
+ * v1.1 amend, PR #251); every other vendor talks to its own service directly.
9
+ * Frozen at runtime, not just in the type: the Hyper adapter hands its entry out by
10
+ * reference as `transportAllowedHosts`, so a mutable table would let any holder of a
11
+ * registry adapter widen the boundary for every later adapter in the process.
12
+ */
13
+ export declare const RESOLVER_VENDOR_TRANSPORT_HOSTS: Readonly<{
14
+ "2captcha": readonly [];
15
+ browser: readonly [];
16
+ capmonster: readonly [];
17
+ capsolver: readonly [];
18
+ custom: readonly [];
19
+ hypersolutions: readonly ["ip.hypersolutions.co"];
20
+ }>;
1
21
  export declare function normalizedResolverHostname(hostname: string): string;
2
22
  export declare function assertResolverHostAllowed(targetUrl: string, allowedHosts: readonly string[]): void;
23
+ export declare function assertResolverVendorTransportHosts(vendor: ProviderResolverVendor, declaredHosts: readonly string[]): void;
@@ -1,4 +1,23 @@
1
1
  import { ProviderError } from "../../errors.js";
2
+ /**
3
+ * Exact SDK-owned service hosts each vendor's adapter may reach through its bound
4
+ * transport, in addition to the provider's declared `allowedHosts`. This table is
5
+ * the trust boundary for `ResolverVendorAdapter.transportAllowedHosts`: a
6
+ * declaration outside its vendor's entry is rejected, whoever supplied the adapter.
7
+ * Only Hyper's observed-IP reflector rides the identity-bound transport (ADR-0008
8
+ * v1.1 amend, PR #251); every other vendor talks to its own service directly.
9
+ * Frozen at runtime, not just in the type: the Hyper adapter hands its entry out by
10
+ * reference as `transportAllowedHosts`, so a mutable table would let any holder of a
11
+ * registry adapter widen the boundary for every later adapter in the process.
12
+ */
13
+ export const RESOLVER_VENDOR_TRANSPORT_HOSTS = Object.freeze({
14
+ "2captcha": Object.freeze([]),
15
+ browser: Object.freeze([]),
16
+ capmonster: Object.freeze([]),
17
+ capsolver: Object.freeze([]),
18
+ custom: Object.freeze([]),
19
+ hypersolutions: Object.freeze(["ip.hypersolutions.co"]),
20
+ });
2
21
  export function normalizedResolverHostname(hostname) {
3
22
  return hostname.trim().toLowerCase().replace(/\.$/, "");
4
23
  }
@@ -31,3 +50,19 @@ export function assertResolverHostAllowed(targetUrl, allowedHosts) {
31
50
  fix: "Add the exact target hostname to the provider's allowedHosts declaration.",
32
51
  });
33
52
  }
53
+ export function assertResolverVendorTransportHosts(vendor, declaredHosts) {
54
+ // A vendor id outside the table (only reachable from untyped callers) owns no hosts and
55
+ // is rejected below like any other overreach; `hasOwn` keeps prototype keys out too.
56
+ const ownedHosts = Object.hasOwn(RESOLVER_VENDOR_TRANSPORT_HOSTS, vendor)
57
+ ? RESOLVER_VENDOR_TRANSPORT_HOSTS[vendor]
58
+ : [];
59
+ for (const declaredHost of declaredHosts) {
60
+ const normalizedHost = normalizedResolverHostname(declaredHost);
61
+ if (ownedHosts.some((host) => normalizedResolverHostname(host) === normalizedHost))
62
+ continue;
63
+ throw new ProviderError(`Resolver vendor "${vendor}" may not declare transport host "${normalizedHost}"`, {
64
+ code: "RESOLVER_VENDOR_HOST_NOT_ALLOWED",
65
+ fix: "Remove the host from transportAllowedHosts: an adapter reaches only the provider's allowedHosts plus the SDK-owned service hosts of its vendor.",
66
+ });
67
+ }
68
+ }
@@ -1,6 +1,6 @@
1
1
  import { isIP } from "node:net";
2
2
  import { recordPaidResolverCreate } from "../resolver-usage.js";
3
- import { assertResolverHostAllowed } from "./hosts.js";
3
+ import { assertResolverHostAllowed, RESOLVER_VENDOR_TRANSPORT_HOSTS } from "./hosts.js";
4
4
  import { ResolverChallengeVerdictError, ResolverVendorUnavailableError, } from "./types.js";
5
5
  const HYPERSOLUTIONS_VENDOR_ID = "hypersolutions";
6
6
  const HYPER_SBSD_URL = "https://akm.hypersolutions.co/sbsd";
@@ -10,7 +10,7 @@ const HYPER_IP_URL = "https://ip.hypersolutions.co/ip";
10
10
  * egress address the upstream will see. The payload-generation POST carries no
11
11
  * identity and goes direct, as in the measured zozotown source.
12
12
  */
13
- const HYPER_TRANSPORT_HOSTS = ["ip.hypersolutions.co"];
13
+ const HYPER_TRANSPORT_HOSTS = RESOLVER_VENDOR_TRANSPORT_HOSTS.hypersolutions;
14
14
  const IP_RESPONSE_MAX_BYTES = 4_096;
15
15
  /** Measured bound shared by the script, the Hyper envelope, and the payload submission. */
16
16
  const BODY_MAX_BYTES = 1_000_000;
@@ -82,10 +82,11 @@ export interface ResolverVendorAdapter {
82
82
  readonly id: ProviderResolverVendor;
83
83
  readonly requiresTransport?: boolean | ((kind: ProviderChallengeKind) => boolean);
84
84
  /**
85
- * Exact SDK-owned service hosts this adapter may reach through its bound transport.
86
- * Honored for every adapter the chain runs, so whoever supplies `adapters` to
87
- * `createResolverClient` is the trust boundary; the engine path
88
- * (`createResolverClientFromEnv`) only constructs registry adapters.
85
+ * Exact SDK-owned service hosts this adapter may reach through its bound transport,
86
+ * in addition to the provider's `allowedHosts`. Every host must appear in the
87
+ * SDK-owned `RESOLVER_VENDOR_TRANSPORT_HOSTS` entry for `id`; the chain rejects any
88
+ * other declaration with `RESOLVER_VENDOR_HOST_NOT_ALLOWED`, whoever supplied the
89
+ * adapter. The transport handed to `solve` is revoked once `solve` settles.
89
90
  */
90
91
  readonly transportAllowedHosts?: readonly string[];
91
92
  supports(kind: ProviderChallengeKind): boolean;
@@ -2,6 +2,7 @@ import { type ProxyResolutionOptions } from "../config/loader.js";
2
2
  import type { ChallengeSolution, ProviderCache, ProviderChallenge, ProviderChallengeKind, ProviderProxyMode, ProviderResolverConfig, ProviderResolverVendor, ResolverContext } from "../types.js";
3
3
  import { type ResolverIdentity, type ResolverVendorAdapter, type ResolverVendorTransport } from "./resolver-vendors/types.js";
4
4
  import type { TraceRecorder } from "./trace.js";
5
+ import type { BrowserTelemetrySink } from "./browser-telemetry.js";
5
6
  import type { ResolverTelemetrySink } from "./resolver-telemetry.js";
6
7
  export { createUnsupportedResolverClient, RESOLVER_INSTRUMENTATION_METADATA, } from "./resolver-shared.js";
7
8
  export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, DEFAULT_RESOLVER_TIMEOUT_MS, } from "./resolver-config.js";
@@ -15,6 +16,8 @@ export interface ResolverRuntimeOptions {
15
16
  readonly cache?: ProviderCache;
16
17
  /** Optional request-scoped observability sink; never used as resolver identity. */
17
18
  readonly telemetry?: ResolverTelemetrySink;
19
+ /** Request-scoped browser sink used by the resolver-owned browser vendor. */
20
+ readonly browserTelemetry?: BrowserTelemetrySink;
18
21
  /** Inputs for SDK-owned lazy proxy resolution. The SDK never accepts a caller-built identity. */
19
22
  readonly proxyIntent?: {
20
23
  readonly mode: ProviderProxyMode;
@@ -39,7 +42,7 @@ export type ResolverInstrumentationMetadata = {
39
42
  readonly target: ResolverContext;
40
43
  readonly traceRecorder: TraceRecorder;
41
44
  };
42
- export type ResolverAdapterFactory = (configuration: string | undefined, timeoutMs: number, allowedHosts: readonly string[]) => ResolverVendorAdapter;
45
+ export type ResolverAdapterFactory = (configuration: string | undefined, timeoutMs: number, allowedHosts: readonly string[], telemetry?: BrowserTelemetrySink) => ResolverVendorAdapter;
43
46
  export declare const RESOLVER_ADAPTER_REGISTRY: Partial<Readonly<Record<ProviderResolverVendor, ResolverAdapterFactory>>>;
44
47
  export declare function swapResolverAdapterFactoryForTests(vendor: ProviderResolverVendor, factory: ResolverAdapterFactory | undefined): () => void;
45
48
  /** Internal test seam; deliberately not re-exported from the package root. */
@@ -8,7 +8,7 @@ import { RESOLVER_CHALLENGE_BINDINGS, resolverChallengeAllowsDirectCache, resolv
8
8
  import { createBrowserResolverVendorAdapter } from "./resolver-vendors/browser.js";
9
9
  import { createCapsolverResolverVendorAdapter } from "./resolver-vendors/capsolver.js";
10
10
  import { createHypersolutionsResolverVendorAdapter } from "./resolver-vendors/hypersolutions.js";
11
- import { assertResolverHostAllowed } from "./resolver-vendors/hosts.js";
11
+ import { assertResolverHostAllowed, assertResolverVendorTransportHosts, } from "./resolver-vendors/hosts.js";
12
12
  import { createTwoCaptchaResolverVendorAdapter } from "./resolver-vendors/twocaptcha.js";
13
13
  import { RESOLVER_VENDOR_CAPABILITIES, ResolverVendorUnavailableError, attachResolverVendorPollObserver, resolveProviderResolverVendors, resolverVendorSupports, } from "./resolver-vendors/types.js";
14
14
  import { createUnsupportedResolverClient, inheritResolverTelemetryBinding, registerResolverTelemetryBinding, RESOLVER_INSTRUMENTATION_METADATA, } from "./resolver-shared.js";
@@ -77,11 +77,12 @@ const resolverAdapterRegistry = {
77
77
  timeoutMs,
78
78
  });
79
79
  },
80
- browser(configuration, timeoutMs, allowedHosts) {
80
+ browser(configuration, timeoutMs, allowedHosts, telemetry) {
81
81
  return createBrowserResolverVendorAdapter({
82
82
  allowedHosts,
83
83
  cdpUrl: configuration,
84
84
  timeoutMs,
85
+ telemetry,
85
86
  });
86
87
  },
87
88
  hypersolutions(configuration, timeoutMs, allowedHosts) {
@@ -169,7 +170,7 @@ function createUnavailableAdapter(vendor, reason) {
169
170
  },
170
171
  };
171
172
  }
172
- function createAdapter(vendor, timeoutMs, allowedHosts, adapterFactories) {
173
+ function createAdapter(vendor, timeoutMs, allowedHosts, adapterFactories, browserTelemetry) {
173
174
  const factory = adapterFactories[vendor.vendor];
174
175
  if (!factory && !KNOWN_UNIMPLEMENTED_RESOLVER_VENDORS.has(vendor.vendor)) {
175
176
  throw new Error(`Resolver adapter factory is missing for implemented vendor "${vendor.vendor}"`);
@@ -178,7 +179,7 @@ function createAdapter(vendor, timeoutMs, allowedHosts, adapterFactories) {
178
179
  return createUnavailableAdapter(vendor.vendor, vendor.reason);
179
180
  }
180
181
  if (factory) {
181
- return factory(vendor.configuration, timeoutMs, allowedHosts);
182
+ return factory(vendor.configuration, timeoutMs, allowedHosts, browserTelemetry);
182
183
  }
183
184
  return createUnavailableAdapter(vendor.vendor, "not_implemented");
184
185
  }
@@ -260,12 +261,23 @@ function sanitizeCauseMessage(message) {
260
261
  .join(" ")
261
262
  .slice(0, 512);
262
263
  }
264
+ function assertResolverTransportLive(revoked) {
265
+ if (!revoked)
266
+ return;
267
+ throw new ProviderError("Resolver transport was revoked when the vendor solve settled", {
268
+ code: "RESOLVER_TRANSPORT_REVOKED",
269
+ fix: "Complete every bound-transport call before solve() settles; the transport is per-attempt and must not be retained.",
270
+ });
271
+ }
263
272
  function restrictResolverTransport(transport, allowedHosts) {
264
- return {
273
+ // A retained reference must fail closed once the adapter's solve has settled.
274
+ let revoked = false;
275
+ const restricted = {
265
276
  sessionHeaders: transport.sessionHeaders,
266
277
  ...(transport.getCookie
267
278
  ? {
268
279
  getCookie(name, url) {
280
+ assertResolverTransportLive(revoked);
269
281
  // Jar reads are gated like fetches: an adapter may only read state for declared hosts.
270
282
  assertResolverHostAllowed(url, allowedHosts);
271
283
  return transport.getCookie?.(name, url);
@@ -273,6 +285,7 @@ function restrictResolverTransport(transport, allowedHosts) {
273
285
  }
274
286
  : {}),
275
287
  async fetch(url, init) {
288
+ assertResolverTransportLive(revoked);
276
289
  // Empty declarations remain deny-by-default, matching the adapter-factory/browser path.
277
290
  assertResolverHostAllowed(url, allowedHosts);
278
291
  const response = await transport.fetch(url, { ...init, redirect: "manual" });
@@ -286,6 +299,12 @@ function restrictResolverTransport(transport, allowedHosts) {
286
299
  return response;
287
300
  },
288
301
  };
302
+ return {
303
+ transport: restricted,
304
+ revoke() {
305
+ revoked = true;
306
+ },
307
+ };
289
308
  }
290
309
  function safeCause(error) {
291
310
  if (error.cause === undefined)
@@ -699,7 +718,7 @@ async function resolveResolverIdentity(proxyIntent) {
699
718
  }
700
719
  }
701
720
  function createChainTelemetryBinding(options) {
702
- return (telemetry) => createResolverChainClient({ ...options, telemetry });
721
+ return (telemetry, browserTelemetry) => createResolverChainClient({ ...options, telemetry, browserTelemetry });
703
722
  }
704
723
  function createResolverChainClient(options) {
705
724
  assertClientProfileTransportContract(options.clientProfile, options.transport);
@@ -791,7 +810,7 @@ function createResolverChainClient(options) {
791
810
  }
792
811
  const attempts = [];
793
812
  for (const [entryIndex, entry] of supportingEntries.entries()) {
794
- const adapter = entry.createAdapter();
813
+ const adapter = entry.createAdapter(options.browserTelemetry);
795
814
  const attemptStartedAt = Date.now();
796
815
  const diagnostics = {};
797
816
  const telemetryTraceRecorder = createResolverTelemetryTraceRecorder({
@@ -803,7 +822,11 @@ function createResolverChainClient(options) {
803
822
  });
804
823
  let solution;
805
824
  try {
806
- const solveAttempt = () => {
825
+ const solveAttempt = async () => {
826
+ // Boundary first: an overreaching declaration is a caller fault even when no
827
+ // transport is configured, not a "missing_transport" vendor unavailability.
828
+ const adapterHosts = adapter.transportAllowedHosts ?? [];
829
+ assertResolverVendorTransportHosts(adapter.id, adapterHosts);
807
830
  const requiresTransport = adapterRequiresTransport(adapter, challenge.kind);
808
831
  const unrestrictedTransport = options.transport ??
809
832
  (requiresTransport
@@ -815,10 +838,10 @@ function createResolverChainClient(options) {
815
838
  if (requiresTransport && unrestrictedTransport === undefined) {
816
839
  throw new ResolverVendorUnavailableError(adapter.id, "missing_transport");
817
840
  }
818
- const transport = unrestrictedTransport
841
+ const boundTransport = unrestrictedTransport
819
842
  ? restrictResolverTransport(unrestrictedTransport, [
820
843
  ...(options.allowedHosts ?? []),
821
- ...(adapter.transportAllowedHosts ?? []),
844
+ ...adapterHosts,
822
845
  ])
823
846
  : undefined;
824
847
  const usage = {
@@ -832,7 +855,12 @@ function createResolverChainClient(options) {
832
855
  }
833
856
  : {}),
834
857
  };
835
- return adapter.solve(challenge, identity, signal, telemetryTraceRecorder, transport, usage);
858
+ try {
859
+ return await adapter.solve(challenge, identity, signal, telemetryTraceRecorder, boundTransport?.transport, usage);
860
+ }
861
+ finally {
862
+ boundTransport?.revoke();
863
+ }
836
864
  };
837
865
  solution = traceRecorder
838
866
  ? await traceRecorder.runSpan("resolver.vendor.attempt", solveAttempt, {
@@ -948,11 +976,15 @@ function createResolverChainClient(options) {
948
976
  },
949
977
  };
950
978
  resolverCaches.set(client, cache ?? null);
951
- const reusableOptions = { ...options, telemetry: undefined };
979
+ const reusableOptions = { ...options, telemetry: undefined, browserTelemetry: undefined };
952
980
  registerResolverTelemetryBinding(client, createChainTelemetryBinding(reusableOptions));
953
981
  return client;
954
982
  }
955
983
  export function createResolverClient(options) {
984
+ for (const adapter of options.adapters) {
985
+ // Fail at construction, not on the first solve, when a supplied adapter oversteps its vendor.
986
+ assertResolverVendorTransportHosts(adapter.id, adapter.transportAllowedHosts ?? []);
987
+ }
956
988
  return createResolverChainClient({
957
989
  kinds: options.kinds,
958
990
  entries: options.adapters.map((adapter) => ({
@@ -1037,7 +1069,7 @@ function createResolverClientFromEnvInternal(config, env, options, adapterFactor
1037
1069
  return {
1038
1070
  id: vendor,
1039
1071
  supports: (kind) => resolverVendorSupports(vendor, kind),
1040
- createAdapter: () => createAdapter(resolveVendorAvailability(vendor, env), timeoutMs, allowedHosts, adapterFactories),
1072
+ createAdapter: (browserTelemetry) => createAdapter(resolveVendorAvailability(vendor, env), timeoutMs, allowedHosts, adapterFactories, browserTelemetry),
1041
1073
  };
1042
1074
  }),
1043
1075
  usingDefaultVendors: config.vendors === undefined,
@@ -1049,6 +1081,7 @@ function createResolverClientFromEnvInternal(config, env, options, adapterFactor
1049
1081
  clientProfile: config.clientProfile,
1050
1082
  allowedHosts,
1051
1083
  telemetry: options.telemetry,
1084
+ browserTelemetry: options.browserTelemetry,
1052
1085
  });
1053
1086
  }
1054
1087
  export function createResolverClientFromEnv(config, env = process.env, options = {}) {
@@ -0,0 +1,79 @@
1
+ import type { ProviderRuntimeState } from "../types.js";
2
+ import { type ClosedEnum, type SpanIndex, type TelemetryContributor } from "./request-telemetry.js";
3
+ export type StateTelemetryOperation = "list" | "get" | "set" | "patch" | "delete" | "cas" | "increment";
4
+ export type StateTelemetryBackend = "redis" | "memory" | "unsupported";
5
+ export type StateTelemetryViolation = "quota" | "ttl" | "size" | "unsupported" | "error";
6
+ export type StateTelemetrySample = {
7
+ key: string;
8
+ op: StateTelemetryOperation;
9
+ ms: number;
10
+ backend: StateTelemetryBackend;
11
+ };
12
+ export type StateTelemetryLogPayload = {
13
+ telemetryFailed?: true;
14
+ ops: {
15
+ list: number;
16
+ get: number;
17
+ set: number;
18
+ patch: number;
19
+ delete: number;
20
+ cas: number;
21
+ increment: number;
22
+ };
23
+ casConflicts: number;
24
+ violations: {
25
+ quota: number;
26
+ ttl: number;
27
+ size: number;
28
+ unsupported: number;
29
+ error: number;
30
+ };
31
+ backend: ClosedEnum<StateTelemetryBackend>;
32
+ /** State fails closed on Redis errors, so this remains 0 until a fallback exists. */
33
+ redisFallbacks: number;
34
+ redisMode: ClosedEnum<"not_configured" | "configured" | "degraded">;
35
+ /** Successful state operations that touch Redis; each operation counts once, regardless of command count. */
36
+ redisRoundTrips: number;
37
+ ms: number;
38
+ samples: StateTelemetrySample[];
39
+ dropped: number;
40
+ };
41
+ export type StateTelemetryHeaderPayload = Omit<StateTelemetryLogPayload, "samples" | "telemetryFailed">;
42
+ export interface StateTelemetrySink {
43
+ markTelemetryFailed?(): void;
44
+ setRedisConfigured?(configured: boolean): void;
45
+ record(event: {
46
+ op: StateTelemetryOperation;
47
+ key?: string;
48
+ ms: number;
49
+ backend: StateTelemetryBackend;
50
+ ok: boolean;
51
+ conflict?: boolean;
52
+ violation?: StateTelemetryViolation;
53
+ /** False for successful Redis-backed operations that execute no Redis commands. */
54
+ redisTouched?: boolean;
55
+ }): void;
56
+ }
57
+ export declare class StateTelemetryCollector implements TelemetryContributor<StateTelemetryLogPayload, StateTelemetryHeaderPayload>, StateTelemetrySink {
58
+ #private;
59
+ readonly key: "state";
60
+ constructor(options?: {
61
+ redact?: (text: string) => string;
62
+ });
63
+ markTelemetryFailed(): void;
64
+ setRedisConfigured(configured: boolean): void;
65
+ record(event: {
66
+ op: StateTelemetryOperation;
67
+ key?: string;
68
+ ms: number;
69
+ backend: StateTelemetryBackend;
70
+ ok: boolean;
71
+ conflict?: boolean;
72
+ violation?: StateTelemetryViolation;
73
+ /** False for successful Redis-backed operations that execute no Redis commands. */
74
+ redisTouched?: boolean;
75
+ }): void;
76
+ toLogPayload(_spans: SpanIndex): StateTelemetryLogPayload | undefined;
77
+ toHeaderPayload(log: StateTelemetryLogPayload): StateTelemetryHeaderPayload;
78
+ }
79
+ export declare function instrumentProviderRuntimeState(state: ProviderRuntimeState, sink: StateTelemetrySink, redact?: (text: string) => string): ProviderRuntimeState;