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

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 (261) hide show
  1. package/AUTHORING.md +367 -9
  2. package/CHANGELOG.md +8 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1 -0
  5. package/bin/apifuse-check.ts +84 -2
  6. package/bin/apifuse-dev.ts +11 -31
  7. package/bin/apifuse-migrate-deployment.ts +200 -0
  8. package/bin/apifuse-pack-check.ts +11 -4
  9. package/bin/apifuse-pack-types.ts +187 -4
  10. package/bin/apifuse-record.ts +44 -32
  11. package/bin/apifuse-submit-check.ts +9 -5
  12. package/bin/apifuse-test.ts +3 -1
  13. package/dist/cli/commands.d.ts +1 -1
  14. package/dist/cli/commands.js +11 -0
  15. package/dist/cli/deployment-intent.d.ts +178 -0
  16. package/dist/cli/deployment-intent.js +277 -0
  17. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  18. package/dist/cli/migrate-deployment-intent.js +1552 -0
  19. package/dist/cli/migrate-provider-shape.d.ts +5 -1
  20. package/dist/cli/migrate-provider-shape.js +4 -2
  21. package/dist/cli/resolver-runtime.d.ts +21 -0
  22. package/dist/cli/resolver-runtime.js +31 -0
  23. package/dist/define.d.ts +3 -0
  24. package/dist/define.js +5 -0
  25. package/dist/dev.d.ts +3 -1
  26. package/dist/dev.js +6 -1
  27. package/dist/engine.d.ts +35 -1
  28. package/dist/engine.js +21 -2
  29. package/dist/error-resolution.d.ts +1 -0
  30. package/dist/error-resolution.js +54 -0
  31. package/dist/errors.d.ts +39 -1
  32. package/dist/errors.js +50 -0
  33. package/dist/handle-meta.d.ts +36 -1
  34. package/dist/handle-meta.js +16 -0
  35. package/dist/handle.d.ts +23 -5
  36. package/dist/handle.js +54 -8
  37. package/dist/health-scenario.d.ts +38 -0
  38. package/dist/i18n/error-messages.d.ts +86 -0
  39. package/dist/i18n/error-messages.js +192 -0
  40. package/dist/i18n/index.d.ts +1 -0
  41. package/dist/i18n/index.js +1 -0
  42. package/dist/i18n/keys.d.ts +12 -0
  43. package/dist/i18n/keys.js +76 -5
  44. package/dist/index.d.ts +11 -3
  45. package/dist/index.js +9 -1
  46. package/dist/lint.d.ts +15 -0
  47. package/dist/lint.js +469 -82
  48. package/dist/provider.d.ts +6 -6
  49. package/dist/provider.js +3 -3
  50. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  51. package/dist/runtime/browser-telemetry-binding.js +83 -0
  52. package/dist/runtime/browser-telemetry.d.ts +76 -0
  53. package/dist/runtime/browser-telemetry.js +165 -0
  54. package/dist/runtime/browser.d.ts +3 -0
  55. package/dist/runtime/browser.js +208 -47
  56. package/dist/runtime/cache-telemetry.d.ts +71 -0
  57. package/dist/runtime/cache-telemetry.js +177 -0
  58. package/dist/runtime/cache.js +67 -7
  59. package/dist/runtime/capability-response.d.ts +3 -0
  60. package/dist/runtime/capability-response.js +56 -0
  61. package/dist/runtime/capability-telemetry.d.ts +46 -0
  62. package/dist/runtime/capability-telemetry.js +68 -0
  63. package/dist/runtime/diagnostic-env.d.ts +3 -0
  64. package/dist/runtime/diagnostic-env.js +10 -1
  65. package/dist/runtime/engine-mode.d.ts +74 -0
  66. package/dist/runtime/engine-mode.js +152 -0
  67. package/dist/runtime/handle.js +9 -1
  68. package/dist/runtime/http-telemetry-guard.d.ts +10 -0
  69. package/dist/runtime/http-telemetry-guard.js +62 -10
  70. package/dist/runtime/http.js +141 -35
  71. package/dist/runtime/instrumentation.js +92 -13
  72. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  73. package/dist/runtime/ocr-telemetry.js +192 -0
  74. package/dist/runtime/ocr.js +35 -8
  75. package/dist/runtime/request-telemetry.d.ts +2 -0
  76. package/dist/runtime/request-telemetry.js +2 -1
  77. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  78. package/dist/runtime/resolver-runtime-options.js +33 -0
  79. package/dist/runtime/resolver-shared.d.ts +3 -2
  80. package/dist/runtime/resolver-shared.js +4 -4
  81. package/dist/runtime/resolver-telemetry.d.ts +1 -0
  82. package/dist/runtime/resolver-telemetry.js +1 -1
  83. package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
  84. package/dist/runtime/resolver-vendors/browser.js +46 -0
  85. package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
  86. package/dist/runtime/resolver-vendors/hosts.js +35 -0
  87. package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
  88. package/dist/runtime/resolver-vendors/types.d.ts +5 -4
  89. package/dist/runtime/resolver.d.ts +4 -1
  90. package/dist/runtime/resolver.js +46 -13
  91. package/dist/runtime/state-telemetry.d.ts +79 -0
  92. package/dist/runtime/state-telemetry.js +194 -0
  93. package/dist/runtime/state.d.ts +3 -0
  94. package/dist/runtime/state.js +26 -7
  95. package/dist/runtime/stealth-cookies.d.ts +5 -1
  96. package/dist/runtime/stealth-cookies.js +21 -1
  97. package/dist/runtime/stealth-owned-headers.d.ts +26 -0
  98. package/dist/runtime/stealth-owned-headers.js +37 -0
  99. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  100. package/dist/runtime/stealth-telemetry.js +179 -0
  101. package/dist/runtime/stealth.d.ts +4 -1
  102. package/dist/runtime/stealth.js +228 -85
  103. package/dist/runtime/stt-telemetry.d.ts +77 -0
  104. package/dist/runtime/stt-telemetry.js +176 -0
  105. package/dist/runtime/stt.js +15 -6
  106. package/dist/runtime-boundary-lint.d.ts +132 -0
  107. package/dist/runtime-boundary-lint.js +586 -0
  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 +7 -0
  111. package/dist/server/index.js +4 -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 +51 -2
  118. package/dist/server/serve-implementation.js +337 -90
  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 +123 -1
  125. package/dist/typescript-module.d.ts +39 -0
  126. package/dist/typescript-module.js +72 -0
  127. package/package.json +6 -1
  128. package/src/cli/commands.ts +14 -0
  129. package/src/cli/deployment-intent.ts +364 -0
  130. package/src/cli/migrate-deployment-intent.ts +1908 -0
  131. package/src/cli/migrate-provider-shape.ts +10 -4
  132. package/src/cli/resolver-runtime.ts +72 -0
  133. package/src/define.ts +13 -0
  134. package/src/dev.ts +9 -2
  135. package/src/engine.ts +38 -2
  136. package/src/error-resolution.ts +58 -0
  137. package/src/errors.ts +77 -1
  138. package/src/handle-meta.ts +51 -1
  139. package/src/handle.ts +92 -10
  140. package/src/health-scenario.ts +38 -0
  141. package/src/i18n/error-messages.ts +255 -0
  142. package/src/i18n/index.ts +1 -0
  143. package/src/i18n/keys.ts +80 -6
  144. package/src/index.ts +86 -0
  145. package/src/lint.ts +604 -91
  146. package/src/provider.ts +12 -0
  147. package/src/runtime/browser-telemetry-binding.ts +92 -0
  148. package/src/runtime/browser-telemetry.ts +289 -0
  149. package/src/runtime/browser.ts +249 -65
  150. package/src/runtime/cache-telemetry.ts +247 -0
  151. package/src/runtime/cache.ts +68 -17
  152. package/src/runtime/capability-response.ts +53 -0
  153. package/src/runtime/capability-telemetry.ts +101 -0
  154. package/src/runtime/diagnostic-env.ts +11 -1
  155. package/src/runtime/engine-mode.ts +233 -0
  156. package/src/runtime/handle.ts +9 -1
  157. package/src/runtime/http-telemetry-guard.ts +66 -13
  158. package/src/runtime/http.ts +168 -37
  159. package/src/runtime/instrumentation.ts +105 -16
  160. package/src/runtime/ocr-telemetry.ts +308 -0
  161. package/src/runtime/ocr.ts +114 -74
  162. package/src/runtime/request-telemetry.ts +2 -1
  163. package/src/runtime/resolver-runtime-options.ts +50 -0
  164. package/src/runtime/resolver-shared.ts +9 -4
  165. package/src/runtime/resolver-telemetry.ts +1 -1
  166. package/src/runtime/resolver-vendors/browser.ts +65 -7
  167. package/src/runtime/resolver-vendors/hosts.ts +43 -0
  168. package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
  169. package/src/runtime/resolver-vendors/types.ts +5 -4
  170. package/src/runtime/resolver.ts +64 -21
  171. package/src/runtime/state-telemetry.ts +298 -0
  172. package/src/runtime/state.ts +46 -45
  173. package/src/runtime/stealth-cookies.ts +24 -1
  174. package/src/runtime/stealth-owned-headers.ts +41 -0
  175. package/src/runtime/stealth-telemetry.ts +304 -0
  176. package/src/runtime/stealth.ts +355 -150
  177. package/src/runtime/stt-telemetry.ts +282 -0
  178. package/src/runtime/stt.ts +93 -71
  179. package/src/runtime-boundary-lint.ts +703 -0
  180. package/src/server/error-stack-frames.ts +214 -0
  181. package/src/server/index.ts +53 -0
  182. package/src/server/sdk-version.ts +22 -0
  183. package/src/server/self-test.ts +1 -21
  184. package/src/server/sensitive-values.ts +14 -0
  185. package/src/server/serve-implementation.ts +569 -108
  186. package/src/server/types.ts +7 -0
  187. package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
  188. package/src/stateful/stateful-provider-runtime-context.ts +4 -0
  189. package/src/types.ts +128 -1
  190. package/src/typescript-module.ts +100 -0
  191. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
  192. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
  193. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
  194. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
  195. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
  196. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
  197. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
  198. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
  199. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
  200. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
  201. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
  202. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
  203. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
  204. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
  205. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
  206. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
  207. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
  208. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
  209. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
  210. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
  211. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
  212. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
  213. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
  214. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
  215. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
  216. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
  217. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
  218. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
  219. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
  220. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
  221. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
  222. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
  244. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
  245. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
  246. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
  247. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
  248. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
  249. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
  250. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
  251. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
  252. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
  253. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
  254. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
  255. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
  256. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
  257. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
  258. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
  259. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
  260. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
  261. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
package/src/provider.ts CHANGED
@@ -115,8 +115,13 @@ export {
115
115
  isProviderError,
116
116
  isSessionExpiredError,
117
117
  isTransportError,
118
+ ProviderEgressDeniedError,
119
+ ProviderEngineAuthenticationError,
120
+ ProviderEngineProtocolVersionError,
121
+ ProviderEngineUnavailableError,
118
122
  ProviderError,
119
123
  type ProviderErrorObservability,
124
+ SDKError,
120
125
  SessionExpiredError,
121
126
  TransportError,
122
127
  ValidationError,
@@ -134,6 +139,7 @@ export {
134
139
  isEngineOwnedRuntimeEnvName,
135
140
  isEngineOwnedTelemetryEnvName,
136
141
  PROVIDER_CAPABILITY_KEYS,
142
+ PROVIDER_ENGINE_MODE_ENV,
137
143
  PROVIDER_ENGINE_PROTOCOL_VERSION,
138
144
  readEngineProxyCredentials,
139
145
  } from "./engine.js";
@@ -143,6 +149,7 @@ export type {
143
149
  ProviderEngineAttachmentInput,
144
150
  ProviderEngineBindingCandidates,
145
151
  ProviderEngineCapabilitySurface,
152
+ ProviderEngineMode,
146
153
  ProviderEngineRequest,
147
154
  ProviderEngineResidentSurface,
148
155
  ProviderEngineSession,
@@ -150,6 +157,7 @@ export type {
150
157
  } from "./engine.js";
151
158
  export {
152
159
  getProviderLocalePath,
160
+ type ProviderErrorMessageParams,
153
161
  providerLocaleKey,
154
162
  qualifyProviderLocaleKey,
155
163
  } from "./i18n/index.js";
@@ -158,6 +166,8 @@ export {
158
166
  APIFUSE_HANDLE_META_KEY,
159
167
  HANDLE_KIND_NAME_PATTERN,
160
168
  handleFieldDescription,
169
+ handleFieldNameFor,
170
+ handleHasDirectionalFieldNames,
161
171
  isHandleFieldMeta,
162
172
  } from "./handle-meta.js";
163
173
  export {
@@ -212,6 +222,8 @@ export type {
212
222
  HealthJourneyRunContext,
213
223
  HealthJourneyRunResult,
214
224
  HealthScheduleRandomization,
225
+ HttpAttemptContext,
226
+ HttpHeadersFactory,
215
227
  HttpRedirectFailureReason,
216
228
  HttpRedirectPolicy,
217
229
  HttpRedirectPolicyMode,
@@ -0,0 +1,92 @@
1
+ import type { BrowserClient } from "../types.js";
2
+ import type { BrowserTelemetrySink } from "./browser-telemetry.js";
3
+ import { observeTelemetryCallback } from "./http-telemetry-guard.js";
4
+
5
+ const methods = new Set(["newPage", "rawPage", "withIsolatedContext", "solveChallenge"]);
6
+ type State = { sink: BrowserTelemetrySink; adapter: BrowserClient };
7
+ const adapters = new WeakMap<object, State>();
8
+ let warned = false;
9
+
10
+ export function isSupportedBrowserBinding(value: unknown): value is BrowserClient {
11
+ if ((typeof value !== "object" && typeof value !== "function") || value === null) return false;
12
+ return [...methods].some((method) => {
13
+ try {
14
+ return typeof Reflect.get(value, method) === "function";
15
+ } catch {
16
+ return false;
17
+ }
18
+ });
19
+ }
20
+
21
+ export function warnUnsupportedBrowserBinding(): void {
22
+ if (warned) return;
23
+ warned = true;
24
+ try {
25
+ console.warn("[apifuse] browser telemetry not attached; reason=unsupported_binding_shape");
26
+ } catch {}
27
+ }
28
+
29
+ export function bindBrowserTelemetry(
30
+ client: BrowserClient,
31
+ sink: BrowserTelemetrySink,
32
+ ): BrowserClient {
33
+ const existing = adapters.get(client as object);
34
+ if (existing) {
35
+ existing.sink = sink;
36
+ return existing.adapter;
37
+ }
38
+ const wrappers = new Map<
39
+ PropertyKey,
40
+ { original: unknown; wrapped: (...args: unknown[]) => unknown }
41
+ >();
42
+ const adapter = new Proxy(Object.create(client) as BrowserClient, {
43
+ get(_target, property) {
44
+ const original = Reflect.get(client, property, client);
45
+ if (typeof property !== "string" || !methods.has(property) || typeof original !== "function")
46
+ return original;
47
+ const cached = wrappers.get(property);
48
+ if (cached && cached.original === original) return cached.wrapped;
49
+ const wrapped = function (this: unknown, ...args: unknown[]) {
50
+ const receiver = this === adapter ? client : this;
51
+ observeTelemetryCallback(state.sink, () => {
52
+ const declared = client.engine;
53
+ const engine =
54
+ declared === "playwright-stealth" ||
55
+ declared === "nodriver" ||
56
+ declared === "selenium-uc"
57
+ ? declared
58
+ : "host";
59
+ return state.sink.recordEngine(engine);
60
+ });
61
+ if (property === "newPage" || property === "rawPage" || property === "withIsolatedContext")
62
+ observeTelemetryCallback(state.sink, () =>
63
+ state.sink.recordPoolAcquire("not_configured"),
64
+ );
65
+ let result: unknown;
66
+ try {
67
+ result = Reflect.apply(original, receiver, args);
68
+ } catch (error) {
69
+ observeTelemetryCallback(state.sink, () => state.sink.recordError("other"));
70
+ throw error;
71
+ }
72
+ try {
73
+ if (result instanceof Promise)
74
+ void Promise.prototype.then.call(result, undefined, () => {
75
+ observeTelemetryCallback(state.sink, () => state.sink.recordError("other"));
76
+ });
77
+ } catch (error) {
78
+ observeTelemetryCallback(state.sink, () => {
79
+ throw error;
80
+ });
81
+ }
82
+ return result;
83
+ };
84
+ wrappers.set(property, { original, wrapped });
85
+ return wrapped;
86
+ },
87
+ });
88
+ const state: State = { sink, adapter };
89
+ adapters.set(client as object, state);
90
+ adapters.set(adapter as object, state);
91
+ return adapter;
92
+ }
@@ -0,0 +1,289 @@
1
+ import type { BrowserEngine } from "../types.js";
2
+ import { Buffer } from "node:buffer";
3
+ export type BrowserTelemetryEngine = BrowserEngine | "host";
4
+ import {
5
+ closedEnum,
6
+ type ClosedEnum,
7
+ type SpanIndex,
8
+ type TelemetryContributor,
9
+ } from "./request-telemetry.js";
10
+
11
+ export type BrowserTelemetryPoolAcquireOutcome =
12
+ | "ok"
13
+ | "not_configured"
14
+ | "queue_full"
15
+ | "timed_out"
16
+ | "shutting_down"
17
+ | "unknown_lease"
18
+ | "unknown_method"
19
+ | "missing_allowed_hosts"
20
+ | "transport_failure"
21
+ | "other";
22
+
23
+ export type BrowserTelemetryErrorCode =
24
+ | "BROWSER_CDP_POOL_REQUIRED"
25
+ | "BROWSER_PROXY_INVALID"
26
+ | "BROWSER_RUNTIME_UNSUPPORTED"
27
+ | "BROWSER_CDP_POOL_ERROR"
28
+ | "other";
29
+
30
+ export type BrowserTelemetrySampleName =
31
+ | "browser.newPage"
32
+ | "browser.page.goto"
33
+ | "browser.page.fill"
34
+ | "browser.page.click"
35
+ | "browser.page.type"
36
+ | "browser.page.waitForSelector"
37
+ | "browser.evaluate"
38
+ | "browser.content"
39
+ | "browser.screenshot"
40
+ | "other";
41
+
42
+ export type BrowserTelemetryLogPayload = {
43
+ allocateMs: number;
44
+ pages: number;
45
+ navigations: number;
46
+ actions: number;
47
+ evaluate: number;
48
+ content: number;
49
+ screenshot: number;
50
+ poolAcquireOutcome?: BrowserTelemetryPoolAcquireOutcome;
51
+ poolAcquireAttempts: number;
52
+ poolAcquireFailures: number;
53
+ poolAcquireUnknownCode?: number;
54
+ proxyAuthChallenges: number;
55
+ engine?: BrowserTelemetryEngine;
56
+ lastErrorCode?: BrowserTelemetryErrorCode;
57
+ samples: {
58
+ name: BrowserTelemetrySampleName;
59
+ ms: number;
60
+ status: "ok" | "error";
61
+ diagnostics?: string;
62
+ }[];
63
+ dropped: number;
64
+ telemetryFailed?: true;
65
+ };
66
+
67
+ export type BrowserTelemetryHeaderPayload = {
68
+ allocateMs: number;
69
+ pages: number;
70
+ navigations: number;
71
+ actions: number;
72
+ evaluate: number;
73
+ content: number;
74
+ screenshot: number;
75
+ poolAcquireOutcome?: ClosedEnum<BrowserTelemetryPoolAcquireOutcome>;
76
+ poolAcquireAttempts: number;
77
+ poolAcquireFailures: number;
78
+ proxyAuthChallenges: number;
79
+ engine?: ClosedEnum<BrowserTelemetryEngine>;
80
+ lastErrorCode?: ClosedEnum<BrowserTelemetryErrorCode>;
81
+ samples: {
82
+ name: ClosedEnum<BrowserTelemetrySampleName>;
83
+ ms: number;
84
+ status: ClosedEnum<"ok" | "error">;
85
+ }[];
86
+ dropped: number;
87
+ };
88
+
89
+ export interface BrowserTelemetrySink {
90
+ recordPoolAcquire(outcome: BrowserTelemetryPoolAcquireOutcome): void;
91
+ recordPoolAcquireUnknownCode?(code: number): void;
92
+ recordProxyAuthChallenge(): void;
93
+ recordEngine(engine: BrowserTelemetryEngine): void;
94
+ recordError(code: BrowserTelemetryErrorCode): void;
95
+ markTelemetryFailed?(): void;
96
+ }
97
+
98
+ const MAX_SAMPLES = 24;
99
+ const SAMPLE_NAMES = new Set<BrowserTelemetrySampleName>([
100
+ "browser.newPage",
101
+ "browser.page.goto",
102
+ "browser.page.fill",
103
+ "browser.page.click",
104
+ "browser.page.type",
105
+ "browser.page.waitForSelector",
106
+ "browser.evaluate",
107
+ "browser.content",
108
+ "browser.screenshot",
109
+ ]);
110
+ function sampleName(name: string): BrowserTelemetrySampleName {
111
+ if (name === "browser.page.evaluate") return "browser.evaluate";
112
+ if (name === "browser.page.content") return "browser.content";
113
+ if (name === "browser.page.screenshot") return "browser.screenshot";
114
+ return name === "[REDACTION_FAILED]" || !SAMPLE_NAMES.has(name as BrowserTelemetrySampleName)
115
+ ? "other"
116
+ : (name as BrowserTelemetrySampleName);
117
+ }
118
+
119
+ function boundedDiagnostics(text: string, redact?: (value: string) => string): string {
120
+ let result: string;
121
+ try {
122
+ result = stripBrowserHeaderMaterial(redact?.(text) ?? text);
123
+ } catch {
124
+ return "[REDACTION_FAILED]";
125
+ }
126
+ const length = Math.min(result.length, 300);
127
+ const units = Buffer.alloc(length * 2);
128
+ for (let i = 0; i < length; i += 1) units.writeUInt16LE(result.charCodeAt(i), i * 2);
129
+ return units.toString("utf16le");
130
+ }
131
+
132
+ function integer(value: number): number {
133
+ return Math.min(
134
+ Number.MAX_SAFE_INTEGER,
135
+ Math.max(0, Math.floor(Number.isFinite(value) ? value : 0)),
136
+ );
137
+ }
138
+
139
+ function add(a: number, b: number): number {
140
+ return Math.min(Number.MAX_SAFE_INTEGER, integer(a) + integer(b));
141
+ }
142
+
143
+ export class BrowserTelemetryCollector
144
+ implements
145
+ TelemetryContributor<BrowserTelemetryLogPayload, BrowserTelemetryHeaderPayload>,
146
+ BrowserTelemetrySink
147
+ {
148
+ readonly key = "browser" as const;
149
+ #poolAcquireOutcome: BrowserTelemetryPoolAcquireOutcome | undefined;
150
+ #poolAcquireAttempts = 0;
151
+ #poolAcquireFailures = 0;
152
+ #poolAcquireUnknownCode: number | undefined;
153
+ #telemetryFailed = false;
154
+ #proxyAuthChallenges = 0;
155
+ #engine: BrowserTelemetryEngine | undefined;
156
+ #lastErrorCode: BrowserTelemetryErrorCode | undefined;
157
+ readonly #redact: ((value: string) => string) | undefined;
158
+
159
+ constructor(options: { redact?: (value: string) => string } = {}) {
160
+ this.#redact = options.redact;
161
+ }
162
+
163
+ recordPoolAcquire(outcome: BrowserTelemetryPoolAcquireOutcome): void {
164
+ this.#poolAcquireOutcome = outcome;
165
+ this.#poolAcquireAttempts = add(this.#poolAcquireAttempts, 1);
166
+ if (outcome !== "ok") this.#poolAcquireFailures = add(this.#poolAcquireFailures, 1);
167
+ }
168
+ recordPoolAcquireUnknownCode(code: number): void {
169
+ this.#poolAcquireUnknownCode = code;
170
+ }
171
+ recordProxyAuthChallenge(): void {
172
+ this.#proxyAuthChallenges = add(this.#proxyAuthChallenges, 1);
173
+ }
174
+ recordEngine(engine: BrowserTelemetryEngine): void {
175
+ this.#engine = engine;
176
+ }
177
+ recordError(code: BrowserTelemetryErrorCode): void {
178
+ this.#lastErrorCode = code;
179
+ }
180
+ markTelemetryFailed(): void {
181
+ this.#telemetryFailed = true;
182
+ }
183
+
184
+ toLogPayload(spans: SpanIndex): BrowserTelemetryLogPayload | undefined {
185
+ const browserSpans = spans.spans.filter(
186
+ (span) =>
187
+ span.name === "browser.newPage" ||
188
+ span.name === "browser.rawPage" ||
189
+ span.name === "browser.withIsolatedContext" ||
190
+ span.name.startsWith("browser.page.") ||
191
+ /^browser\.(evaluate|content|screenshot)$/.test(span.name),
192
+ );
193
+ const failedSpan = spans.spans.some((span) => span.name === "[REDACTION_FAILED]");
194
+ if (
195
+ browserSpans.length === 0 &&
196
+ !failedSpan &&
197
+ !this.#poolAcquireOutcome &&
198
+ this.#proxyAuthChallenges === 0 &&
199
+ !this.#engine &&
200
+ !this.#lastErrorCode &&
201
+ !this.#telemetryFailed
202
+ )
203
+ return undefined;
204
+ const count = (name: string) => spans.count(name);
205
+ const sampleSpans = failedSpan
206
+ ? [...browserSpans, ...spans.spans.filter((span) => span.name === "[REDACTION_FAILED]")]
207
+ : browserSpans;
208
+ const samples: BrowserTelemetryLogPayload["samples"] = sampleSpans
209
+ .slice(0, MAX_SAMPLES)
210
+ .map((span) => ({
211
+ name: sampleName(span.name),
212
+ ms: integer(span.duration_ms),
213
+ status: (span.status === "error" ? "error" : "ok") as "ok" | "error",
214
+ ...(span.name === "[REDACTION_FAILED]"
215
+ ? { diagnostics: "[REDACTION_FAILED]" }
216
+ : span.error
217
+ ? { diagnostics: boundedDiagnostics(span.error, this.#redact) }
218
+ : {}),
219
+ }));
220
+ return {
221
+ allocateMs: integer(
222
+ browserSpans
223
+ .filter((span) => span.name === "browser.newPage")
224
+ .reduce((sum, span) => sum + Number(span.attributes.allocate_ms ?? span.duration_ms), 0),
225
+ ),
226
+ pages: add(
227
+ add(count("browser.newPage"), count("browser.rawPage")),
228
+ count("browser.withIsolatedContext"),
229
+ ),
230
+ navigations: integer(count("browser.page.goto")),
231
+ actions: ["fill", "click", "type", "waitForSelector"].reduce(
232
+ (sum, method) => add(sum, count(`browser.page.${method}`)),
233
+ 0,
234
+ ),
235
+ evaluate: add(count("browser.evaluate"), count("browser.page.evaluate")),
236
+ content: add(count("browser.page.content"), count("browser.content")),
237
+ screenshot: add(count("browser.page.screenshot"), count("browser.screenshot")),
238
+ ...(this.#poolAcquireOutcome ? { poolAcquireOutcome: this.#poolAcquireOutcome } : {}),
239
+ poolAcquireAttempts: this.#poolAcquireAttempts,
240
+ poolAcquireFailures: this.#poolAcquireFailures,
241
+ ...(this.#poolAcquireUnknownCode === undefined
242
+ ? {}
243
+ : { poolAcquireUnknownCode: this.#poolAcquireUnknownCode }),
244
+ proxyAuthChallenges: this.#proxyAuthChallenges,
245
+ ...(this.#engine ? { engine: this.#engine } : {}),
246
+ ...(this.#lastErrorCode ? { lastErrorCode: this.#lastErrorCode } : {}),
247
+ samples,
248
+ dropped: Math.max(0, sampleSpans.length - samples.length),
249
+ ...(this.#telemetryFailed ? { telemetryFailed: true as const } : {}),
250
+ };
251
+ }
252
+
253
+ toHeaderPayload(log: BrowserTelemetryLogPayload): BrowserTelemetryHeaderPayload {
254
+ return {
255
+ allocateMs: log.allocateMs,
256
+ pages: log.pages,
257
+ navigations: log.navigations,
258
+ actions: log.actions,
259
+ evaluate: log.evaluate,
260
+ content: log.content,
261
+ screenshot: log.screenshot,
262
+ ...(log.poolAcquireOutcome ? { poolAcquireOutcome: closedEnum(log.poolAcquireOutcome) } : {}),
263
+ poolAcquireAttempts: log.poolAcquireAttempts,
264
+ poolAcquireFailures: log.poolAcquireFailures,
265
+ proxyAuthChallenges: log.proxyAuthChallenges,
266
+ ...(log.engine ? { engine: closedEnum(log.engine) } : {}),
267
+ ...(log.lastErrorCode ? { lastErrorCode: closedEnum(log.lastErrorCode) } : {}),
268
+ samples: log.samples.map((sample) => ({
269
+ name: closedEnum(sample.name),
270
+ ms: sample.ms,
271
+ status: closedEnum(sample.status),
272
+ })),
273
+ dropped: log.dropped,
274
+ };
275
+ }
276
+ }
277
+
278
+ /** Defence in depth for diagnostics that accidentally contain protocol headers. */
279
+ export function stripBrowserHeaderMaterial(value: string): string {
280
+ return value
281
+ .replace(
282
+ /(^|[^\p{L}\p{N}_-])[\t ]*(?:cookie|set-cookie|authorization)[\t ]*(?::|=)[^\r\n]*/giu,
283
+ "$1[REDACTED]",
284
+ )
285
+ .replace(
286
+ /"(?:cookie|set-cookie|authorization)"[\t ]*:[\t ]*"(?:\\.|[^"\\])*"/giu,
287
+ "[REDACTED]",
288
+ );
289
+ }