@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.31

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 (342) hide show
  1. package/AUTHORING.md +493 -5
  2. package/CHANGELOG.md +131 -1
  3. package/README.md +52 -6
  4. package/SUBMISSION.md +1 -1
  5. package/bin/apifuse-check.ts +106 -62
  6. package/bin/apifuse-create.ts +1 -1
  7. package/bin/apifuse-dev.ts +63 -55
  8. package/bin/apifuse-pack-check.ts +22 -2
  9. package/bin/apifuse-pack-smoke.ts +78 -82
  10. package/bin/apifuse-pack-types.ts +583 -0
  11. package/bin/apifuse-perf.ts +59 -140
  12. package/bin/apifuse-record.ts +698 -113
  13. package/bin/apifuse-submit-check.ts +517 -44
  14. package/bin/apifuse-sync-assets.ts +117 -0
  15. package/bin/apifuse.ts +1 -1
  16. package/bin/submit-check-delimited-text.ts +50 -0
  17. package/bin/submit-check-xml.ts +1 -1
  18. package/dist/auth-turn/index.d.ts +4 -4
  19. package/dist/auth-turn/index.js +1 -1
  20. package/dist/auth.d.ts +16 -2
  21. package/dist/auth.js +76 -18
  22. package/dist/ceremonies/index.d.ts +9 -1
  23. package/dist/ceremonies/index.js +117 -29
  24. package/dist/cli/commands.d.ts +1 -1
  25. package/dist/cli/commands.js +8 -0
  26. package/dist/cli/create.d.ts +3 -0
  27. package/dist/cli/create.js +34 -35
  28. package/dist/cli/prompt-assets.d.ts +80 -0
  29. package/dist/cli/prompt-assets.js +743 -0
  30. package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
  31. package/dist/cli/templates/provider/README.md.tpl +4 -4
  32. package/dist/config/loader.d.ts +176 -17
  33. package/dist/config/loader.js +434 -161
  34. package/dist/contract-serialization.d.ts +2 -2
  35. package/dist/contract-serialization.js +7 -14
  36. package/dist/contract-types.d.ts +3 -2
  37. package/dist/contract.d.ts +3 -3
  38. package/dist/contract.js +6 -6
  39. package/dist/declaration-validation.d.ts +23 -0
  40. package/dist/declaration-validation.js +159 -0
  41. package/dist/define.d.ts +13 -1
  42. package/dist/define.js +391 -122
  43. package/dist/dev.d.ts +1 -1
  44. package/dist/dev.js +1 -1
  45. package/dist/error-resolution.d.ts +4 -0
  46. package/dist/error-resolution.js +123 -0
  47. package/dist/errors.d.ts +19 -1
  48. package/dist/errors.js +41 -3
  49. package/dist/fixture-sanitization.d.ts +26 -0
  50. package/dist/fixture-sanitization.js +216 -0
  51. package/dist/i18n/catalog.d.ts +2 -2
  52. package/dist/i18n/catalog.js +4 -10
  53. package/dist/i18n/index.d.ts +2 -2
  54. package/dist/i18n/index.js +2 -2
  55. package/dist/i18n/keys.d.ts +2 -2
  56. package/dist/index.d.ts +50 -42
  57. package/dist/index.js +41 -37
  58. package/dist/lint.d.ts +6 -1
  59. package/dist/lint.js +370 -18
  60. package/dist/native-address.d.ts +43 -0
  61. package/dist/native-address.js +281 -0
  62. package/dist/native-egress-policy.d.ts +31 -0
  63. package/dist/native-egress-policy.js +288 -0
  64. package/dist/observability.d.ts +5 -2
  65. package/dist/observability.js +48 -1
  66. package/dist/provider.d.ts +13 -11
  67. package/dist/provider.js +10 -9
  68. package/dist/public-schema-field-lint.d.ts +1 -1
  69. package/dist/recipes/gov-api.js +1 -1
  70. package/dist/runtime/auth-flow.d.ts +3 -1
  71. package/dist/runtime/auth-flow.js +8 -3
  72. package/dist/runtime/browser.d.ts +1 -1
  73. package/dist/runtime/browser.js +138 -40
  74. package/dist/runtime/cache.d.ts +2 -1
  75. package/dist/runtime/cache.js +173 -23
  76. package/dist/runtime/choice-wordlist.d.ts +9 -0
  77. package/dist/runtime/choice-wordlist.js +138 -0
  78. package/dist/runtime/choice.d.ts +14 -1
  79. package/dist/runtime/choice.js +566 -101
  80. package/dist/runtime/credential.d.ts +1 -1
  81. package/dist/runtime/credential.js +1 -1
  82. package/dist/runtime/env.d.ts +1 -1
  83. package/dist/runtime/executor.d.ts +1 -1
  84. package/dist/runtime/executor.js +25 -3
  85. package/dist/runtime/http.d.ts +3 -2
  86. package/dist/runtime/http.js +517 -55
  87. package/dist/runtime/insights.d.ts +1 -1
  88. package/dist/runtime/insights.js +6 -13
  89. package/dist/runtime/instrumentation.d.ts +2 -2
  90. package/dist/runtime/instrumentation.js +371 -23
  91. package/dist/runtime/keyring.js +1 -1
  92. package/dist/runtime/namespace.js +1 -1
  93. package/dist/runtime/native-network-errors.d.ts +33 -0
  94. package/dist/runtime/native-network-errors.js +69 -0
  95. package/dist/runtime/native-network.d.ts +96 -0
  96. package/dist/runtime/native-network.js +1232 -0
  97. package/dist/runtime/ocr.d.ts +29 -0
  98. package/dist/runtime/ocr.js +440 -0
  99. package/dist/runtime/otlp.d.ts +1 -1
  100. package/dist/runtime/perf.d.ts +1 -1
  101. package/dist/runtime/provider.d.ts +1 -1
  102. package/dist/runtime/provider.js +1 -2
  103. package/dist/runtime/proxy-errors.d.ts +1 -1
  104. package/dist/runtime/proxy-errors.js +9 -7
  105. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  106. package/dist/runtime/proxy-nodemaven.js +146 -0
  107. package/dist/runtime/proxy-retry-policy.d.ts +2 -2
  108. package/dist/runtime/proxy-retry-policy.js +2 -2
  109. package/dist/runtime/proxy-telemetry.d.ts +2 -1
  110. package/dist/runtime/proxy-telemetry.js +58 -52
  111. package/dist/runtime/redirects.d.ts +29 -0
  112. package/dist/runtime/redirects.js +36 -0
  113. package/dist/runtime/redis.d.ts +1 -1
  114. package/dist/runtime/redis.js +5 -5
  115. package/dist/runtime/request-options.d.ts +68 -1
  116. package/dist/runtime/request-options.js +548 -0
  117. package/dist/runtime/resolver-config.d.ts +6 -0
  118. package/dist/runtime/resolver-config.js +6 -0
  119. package/dist/runtime/resolver-public.d.ts +1 -0
  120. package/dist/runtime/resolver-public.js +1 -0
  121. package/dist/runtime/resolver-shared.d.ts +3 -0
  122. package/dist/runtime/resolver-shared.js +12 -0
  123. package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
  124. package/dist/runtime/resolver-vendors/bindings.js +40 -0
  125. package/dist/runtime/resolver-vendors/browser.d.ts +20 -0
  126. package/dist/runtime/resolver-vendors/browser.js +282 -0
  127. package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
  128. package/dist/runtime/resolver-vendors/hosts.js +33 -0
  129. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
  130. package/dist/runtime/resolver-vendors/twocaptcha.js +368 -0
  131. package/dist/runtime/resolver-vendors/types.d.ts +83 -0
  132. package/dist/runtime/resolver-vendors/types.js +69 -0
  133. package/dist/runtime/resolver.d.ts +59 -0
  134. package/dist/runtime/resolver.js +705 -0
  135. package/dist/runtime/secrets.d.ts +27 -0
  136. package/dist/runtime/secrets.js +51 -0
  137. package/dist/runtime/state.d.ts +5 -2
  138. package/dist/runtime/state.js +280 -74
  139. package/dist/runtime/stealth-cookies.d.ts +20 -0
  140. package/dist/runtime/stealth-cookies.js +111 -0
  141. package/dist/runtime/stealth.d.ts +30 -5
  142. package/dist/runtime/stealth.js +523 -259
  143. package/dist/runtime/stt.d.ts +1 -1
  144. package/dist/runtime/stt.js +12 -27
  145. package/dist/runtime/timeout.d.ts +5 -0
  146. package/dist/runtime/timeout.js +12 -0
  147. package/dist/runtime/trace.d.ts +2 -2
  148. package/dist/runtime/trace.js +2 -4
  149. package/dist/runtime/waterfall.d.ts +1 -1
  150. package/dist/schema.d.ts +1 -1
  151. package/dist/schema.js +7 -15
  152. package/dist/serve.d.ts +1 -1
  153. package/dist/serve.js +1 -1
  154. package/dist/server/index.d.ts +7 -7
  155. package/dist/server/index.js +6 -6
  156. package/dist/server/self-test-input-tokens.d.ts +2 -1
  157. package/dist/server/self-test-input-tokens.js +18 -14
  158. package/dist/server/self-test-redaction.d.ts +1 -1
  159. package/dist/server/self-test-redaction.js +1 -1
  160. package/dist/server/self-test.d.ts +117 -3
  161. package/dist/server/self-test.js +787 -151
  162. package/dist/server/serve-implementation.d.ts +210 -0
  163. package/dist/server/serve-implementation.js +2078 -0
  164. package/dist/server/serve.d.ts +1 -70
  165. package/dist/server/serve.js +1 -1143
  166. package/dist/server/types.d.ts +34 -9
  167. package/dist/server/types.js +8 -1
  168. package/dist/stateful/errors.d.ts +19 -0
  169. package/dist/stateful/errors.js +24 -0
  170. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  171. package/dist/stateful/http-provider-event-emitter.js +237 -0
  172. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  173. package/dist/stateful/http-session-owner-registry.js +210 -0
  174. package/dist/stateful/index.d.ts +18 -0
  175. package/dist/stateful/index.js +18 -0
  176. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  177. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  178. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  179. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  180. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  181. package/dist/stateful/provider-event-pipeline.js +1 -0
  182. package/dist/stateful/provider-events.d.ts +101 -0
  183. package/dist/stateful/provider-events.js +289 -0
  184. package/dist/stateful/session-key.d.ts +15 -0
  185. package/dist/stateful/session-key.js +86 -0
  186. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  187. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  188. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  189. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  190. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  191. package/dist/stateful/stateful-provider-adapter.js +287 -0
  192. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  193. package/dist/stateful/stateful-provider-observability.js +161 -0
  194. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  195. package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
  196. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  197. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  198. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  199. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  200. package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
  201. package/dist/stateful/stateful-provider-session-routing.js +345 -0
  202. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  203. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  204. package/dist/stateful-signing.d.ts +18 -0
  205. package/dist/stateful-signing.js +27 -0
  206. package/dist/stealth/profiles.d.ts +1 -1
  207. package/dist/stealth/profiles.js +21 -21
  208. package/dist/stream-evidence.d.ts +74 -0
  209. package/dist/stream-evidence.js +785 -0
  210. package/dist/stream.d.ts +1 -1
  211. package/dist/stream.js +7 -1
  212. package/dist/testing/index.d.ts +3 -2
  213. package/dist/testing/index.js +3 -2
  214. package/dist/testing/run.d.ts +32 -2
  215. package/dist/testing/run.js +488 -28
  216. package/dist/types.d.ts +566 -19
  217. package/dist/types.js +1 -0
  218. package/dist/user-input.d.ts +30 -0
  219. package/dist/user-input.js +66 -0
  220. package/package.json +42 -7
  221. package/src/auth-turn/index.ts +2 -2
  222. package/src/auth.ts +146 -86
  223. package/src/ceremonies/index.ts +167 -92
  224. package/src/cli/commands.ts +10 -0
  225. package/src/cli/create.ts +42 -35
  226. package/src/cli/prompt-assets.ts +865 -0
  227. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  228. package/src/cli/templates/provider/README.md.tpl +4 -4
  229. package/src/config/loader.ts +667 -289
  230. package/src/contract-serialization.ts +10 -18
  231. package/src/contract-types.ts +3 -2
  232. package/src/contract.ts +14 -28
  233. package/src/declaration-validation.ts +202 -0
  234. package/src/define.ts +631 -495
  235. package/src/dev.ts +4 -9
  236. package/src/error-resolution.ts +128 -0
  237. package/src/errors.ts +56 -11
  238. package/src/fixture-sanitization.ts +247 -0
  239. package/src/i18n/catalog.ts +10 -32
  240. package/src/i18n/index.ts +2 -2
  241. package/src/i18n/keys.ts +5 -11
  242. package/src/index.ts +158 -44
  243. package/src/lint.ts +488 -154
  244. package/src/native-address.ts +340 -0
  245. package/src/native-egress-policy.ts +358 -0
  246. package/src/observability.ts +51 -1
  247. package/src/provider.ts +66 -11
  248. package/src/public-schema-field-lint.ts +7 -33
  249. package/src/recipes/gov-api.ts +2 -5
  250. package/src/runtime/auth-flow.ts +13 -7
  251. package/src/runtime/browser.ts +252 -207
  252. package/src/runtime/cache.ts +209 -81
  253. package/src/runtime/choice-wordlist.ts +145 -0
  254. package/src/runtime/choice.ts +758 -197
  255. package/src/runtime/credential.ts +2 -2
  256. package/src/runtime/env.ts +1 -1
  257. package/src/runtime/executor.ts +37 -19
  258. package/src/runtime/http.ts +645 -65
  259. package/src/runtime/insights.ts +15 -53
  260. package/src/runtime/instrumentation.ts +530 -67
  261. package/src/runtime/keyring.ts +7 -19
  262. package/src/runtime/namespace.ts +2 -7
  263. package/src/runtime/native-network-errors.ts +99 -0
  264. package/src/runtime/native-network.ts +1605 -0
  265. package/src/runtime/ocr.ts +523 -0
  266. package/src/runtime/otlp.ts +12 -23
  267. package/src/runtime/perf.ts +1 -1
  268. package/src/runtime/provider.ts +4 -9
  269. package/src/runtime/proxy-errors.ts +29 -42
  270. package/src/runtime/proxy-nodemaven.ts +221 -0
  271. package/src/runtime/proxy-retry-policy.ts +3 -3
  272. package/src/runtime/proxy-telemetry.ts +84 -77
  273. package/src/runtime/redirects.ts +66 -0
  274. package/src/runtime/redis.ts +10 -13
  275. package/src/runtime/request-options.ts +679 -9
  276. package/src/runtime/resolver-config.ts +6 -0
  277. package/src/runtime/resolver-public.ts +18 -0
  278. package/src/runtime/resolver-shared.ts +17 -0
  279. package/src/runtime/resolver-vendors/bindings.ts +56 -0
  280. package/src/runtime/resolver-vendors/browser.ts +408 -0
  281. package/src/runtime/resolver-vendors/hosts.ts +38 -0
  282. package/src/runtime/resolver-vendors/twocaptcha.ts +500 -0
  283. package/src/runtime/resolver-vendors/types.ts +173 -0
  284. package/src/runtime/resolver.ts +1060 -0
  285. package/src/runtime/secrets.ts +64 -0
  286. package/src/runtime/state.ts +399 -161
  287. package/src/runtime/stealth-cookies.ts +132 -0
  288. package/src/runtime/stealth.ts +681 -295
  289. package/src/runtime/stt.ts +39 -113
  290. package/src/runtime/timeout.ts +18 -0
  291. package/src/runtime/trace.ts +14 -44
  292. package/src/runtime/waterfall.ts +5 -18
  293. package/src/schema.ts +23 -84
  294. package/src/serve.ts +6 -1
  295. package/src/server/index.ts +30 -7
  296. package/src/server/self-test-input-tokens.ts +29 -14
  297. package/src/server/self-test-redaction.ts +2 -2
  298. package/src/server/self-test.ts +1030 -180
  299. package/src/server/serve-implementation.ts +3062 -0
  300. package/src/server/serve.ts +1 -1781
  301. package/src/server/types.ts +12 -13
  302. package/src/stateful/README.md +146 -0
  303. package/src/stateful/errors.ts +35 -0
  304. package/src/stateful/http-provider-event-emitter.ts +314 -0
  305. package/src/stateful/http-session-owner-registry.ts +306 -0
  306. package/src/stateful/index.ts +18 -0
  307. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  308. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  309. package/src/stateful/provider-event-pipeline.ts +61 -0
  310. package/src/stateful/provider-events.ts +462 -0
  311. package/src/stateful/session-key.ts +111 -0
  312. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  313. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  314. package/src/stateful/stateful-provider-adapter.ts +562 -0
  315. package/src/stateful/stateful-provider-observability.ts +261 -0
  316. package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
  317. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  318. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  319. package/src/stateful/stateful-provider-session-routing.ts +546 -0
  320. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  321. package/src/stateful-signing.ts +46 -0
  322. package/src/stealth/profiles.ts +27 -33
  323. package/src/stream-evidence.ts +988 -0
  324. package/src/stream.ts +16 -20
  325. package/src/testing/index.ts +11 -2
  326. package/src/testing/run.ts +668 -74
  327. package/src/types.ts +665 -35
  328. package/src/user-input.ts +118 -0
  329. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  330. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  331. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  332. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  333. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  334. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  335. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  336. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  337. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  338. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  339. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  340. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  341. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  342. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
@@ -0,0 +1,29 @@
1
+ import type { OcrCaptchaCandidate, OcrCaptchaOptions, OcrContext, ProviderOcrConfig } from "../types.js";
2
+ export { CLOUDFLARE_ACCOUNT_ID_ENV } from "./stt.js";
3
+ export declare const APIFUSE__OCR__BACKEND_ENV = "APIFUSE__OCR__BACKEND";
4
+ export declare const APIFUSE__OCR__MODEL_ENV = "APIFUSE__OCR__MODEL";
5
+ export declare const APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV = "APIFUSE__OCR__CLOUDFLARE_API_TOKEN";
6
+ export declare const APIFUSE__OCR__BASE_URL_ENV = "APIFUSE__OCR__BASE_URL";
7
+ export declare const APIFUSE__OCR__API_KEY_ENV = "APIFUSE__OCR__API_KEY";
8
+ export declare const CLOUDFLARE_WORKERS_AI_OCR_BACKEND = "cloudflare-workers-ai";
9
+ export declare const OPENAI_COMPATIBLE_OCR_BACKEND = "openai-compatible";
10
+ export declare const DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL = "@cf/google/gemma-4-26b-a4b-it";
11
+ export declare const DEFAULT_OCR_TIMEOUT_MS = 30000;
12
+ type EnvLike = Record<string, string | undefined>;
13
+ type CloudflareWorkersAiOcrClientOptions = {
14
+ accountId: string;
15
+ apiToken: string;
16
+ model?: string;
17
+ fetch?: typeof fetch;
18
+ };
19
+ type OpenAiCompatibleOcrClientOptions = {
20
+ baseUrl: string;
21
+ apiKey?: string;
22
+ model: string;
23
+ fetch?: typeof fetch;
24
+ };
25
+ export declare function createUnsupportedOcrClient(reason?: string): OcrContext;
26
+ export declare function createOcrClientFromEnv(config: ProviderOcrConfig | undefined, env?: EnvLike): OcrContext;
27
+ export declare function createCloudflareWorkersAiOcrClient(options: CloudflareWorkersAiOcrClientOptions): OcrContext;
28
+ export declare function createOpenAiCompatibleOcrClient(options: OpenAiCompatibleOcrClientOptions): OcrContext;
29
+ export declare function extractCaptchaCandidates(modelText: string, options?: OcrCaptchaOptions): readonly OcrCaptchaCandidate[];
@@ -0,0 +1,440 @@
1
+ import { ProviderError, TransportError } from "../errors.js";
2
+ import { CLOUDFLARE_ACCOUNT_ID_ENV } from "./stt.js";
3
+ import { createTimeoutController, isTimeoutLikeError } from "./timeout.js";
4
+ export { CLOUDFLARE_ACCOUNT_ID_ENV } from "./stt.js";
5
+ export const APIFUSE__OCR__BACKEND_ENV = "APIFUSE__OCR__BACKEND";
6
+ export const APIFUSE__OCR__MODEL_ENV = "APIFUSE__OCR__MODEL";
7
+ export const APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV = "APIFUSE__OCR__CLOUDFLARE_API_TOKEN";
8
+ export const APIFUSE__OCR__BASE_URL_ENV = "APIFUSE__OCR__BASE_URL";
9
+ export const APIFUSE__OCR__API_KEY_ENV = "APIFUSE__OCR__API_KEY";
10
+ export const CLOUDFLARE_WORKERS_AI_OCR_BACKEND = "cloudflare-workers-ai";
11
+ export const OPENAI_COMPATIBLE_OCR_BACKEND = "openai-compatible";
12
+ export const DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL = "@cf/google/gemma-4-26b-a4b-it";
13
+ export const DEFAULT_OCR_TIMEOUT_MS = 30_000;
14
+ const DEFAULT_CAPTCHA_MAX_TOKENS = 64;
15
+ const DEFAULT_DOCUMENT_MAX_TOKENS = 4_096;
16
+ const KIMI_MIN_MAX_TOKENS = 3_000;
17
+ const DEFAULT_MAX_CAPTCHA_CANDIDATES = 3;
18
+ const MAX_HOMOGLYPH_SEARCH_NODES = 512;
19
+ const HOMOGLYPH_CLASSES = [
20
+ ["I", "l", "1", "i"],
21
+ ["O", "0", "o"],
22
+ ["S", "5", "s"],
23
+ ["Z", "2", "z"],
24
+ ["B", "8"],
25
+ ];
26
+ const HINT_PROMPTS = {
27
+ captcha: "Read the CAPTCHA image. Return only the characters, with no explanation. Preserve character case.",
28
+ document: "Transcribe all visible text in the document image.",
29
+ generic: "Read and return the visible text in this image.",
30
+ };
31
+ function providerError(message, options) {
32
+ return new ProviderError(message, options);
33
+ }
34
+ function createErrorOcrClient(options) {
35
+ const unavailable = () => {
36
+ throw providerError(options.message, {
37
+ code: options.code,
38
+ fix: options.fix,
39
+ });
40
+ };
41
+ return {
42
+ async recognize() {
43
+ return unavailable();
44
+ },
45
+ async extractCaptchaText() {
46
+ return unavailable();
47
+ },
48
+ };
49
+ }
50
+ export function createUnsupportedOcrClient(reason) {
51
+ return createErrorOcrClient({
52
+ code: "OCR_UNAVAILABLE",
53
+ message: reason ?? "OCR runtime is not configured",
54
+ fix: `Configure ${APIFUSE__OCR__BACKEND_ENV} and ${APIFUSE__OCR__MODEL_ENV}; Cloudflare uses ${CLOUDFLARE_ACCOUNT_ID_ENV} and ${APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV}, while openai-compatible uses ${APIFUSE__OCR__BASE_URL_ENV} and optional ${APIFUSE__OCR__API_KEY_ENV}. Alternatively, provide a test OcrContext override.`,
55
+ });
56
+ }
57
+ function normalizedEnvValue(env, key) {
58
+ const value = env[key]?.trim();
59
+ return value ? value : undefined;
60
+ }
61
+ export function createOcrClientFromEnv(config, env = process.env) {
62
+ if (!config) {
63
+ return createUnsupportedOcrClient("Provider does not declare OCR capability");
64
+ }
65
+ const backend = normalizedEnvValue(env, APIFUSE__OCR__BACKEND_ENV) ?? CLOUDFLARE_WORKERS_AI_OCR_BACKEND;
66
+ const configuredModel = normalizedEnvValue(env, APIFUSE__OCR__MODEL_ENV);
67
+ if (backend === CLOUDFLARE_WORKERS_AI_OCR_BACKEND) {
68
+ const model = configuredModel ?? DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL;
69
+ const accountId = normalizedEnvValue(env, CLOUDFLARE_ACCOUNT_ID_ENV);
70
+ const apiToken = normalizedEnvValue(env, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV);
71
+ if (!accountId || !apiToken) {
72
+ return createUnsupportedOcrClient(`OCR backend ${backend} requires ${CLOUDFLARE_ACCOUNT_ID_ENV} and ${APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV}`);
73
+ }
74
+ return createCloudflareWorkersAiOcrClient({ accountId, apiToken, model });
75
+ }
76
+ if (backend === OPENAI_COMPATIBLE_OCR_BACKEND) {
77
+ const baseUrl = normalizedEnvValue(env, APIFUSE__OCR__BASE_URL_ENV);
78
+ if (!baseUrl) {
79
+ return createUnsupportedOcrClient(`OCR backend ${backend} requires ${APIFUSE__OCR__BASE_URL_ENV}`);
80
+ }
81
+ if (!configuredModel) {
82
+ return createErrorOcrClient({
83
+ code: "OCR_UNAVAILABLE",
84
+ message: `OCR backend ${backend} requires ${APIFUSE__OCR__MODEL_ENV}`,
85
+ fix: `Set ${APIFUSE__OCR__MODEL_ENV} to the exact model ID served by your self-hosted endpoint, for example ${APIFUSE__OCR__MODEL_ENV}=zai-org/GLM-OCR.`,
86
+ });
87
+ }
88
+ return createOpenAiCompatibleOcrClient({
89
+ baseUrl,
90
+ apiKey: normalizedEnvValue(env, APIFUSE__OCR__API_KEY_ENV),
91
+ model: configuredModel,
92
+ });
93
+ }
94
+ return createErrorOcrClient({
95
+ code: "UNSUPPORTED_OCR_BACKEND",
96
+ message: `Unsupported OCR backend "${backend}"`,
97
+ fix: `Use ${APIFUSE__OCR__BACKEND_ENV}=${CLOUDFLARE_WORKERS_AI_OCR_BACKEND} or ${APIFUSE__OCR__BACKEND_ENV}=${OPENAI_COMPATIBLE_OCR_BACKEND}, or provide a custom OcrContext override.`,
98
+ });
99
+ }
100
+ function unknownRecord(value) {
101
+ if (!value || typeof value !== "object" || Array.isArray(value))
102
+ return undefined;
103
+ return Object.fromEntries(Object.entries(value));
104
+ }
105
+ function imageUrl(image) {
106
+ if (image.kind === "url")
107
+ return image.url.trim();
108
+ return `data:${image.mediaType?.trim() || "image/png"};base64,${image.data.trim()}`;
109
+ }
110
+ function resolvePrompt(request) {
111
+ return request.prompt ?? HINT_PROMPTS[request.hint ?? "generic"];
112
+ }
113
+ function isGemmaModel(model) {
114
+ return model.toLowerCase().includes("gemma");
115
+ }
116
+ function isKimiModel(model) {
117
+ return model.toLowerCase().includes("kimi");
118
+ }
119
+ function isMoondreamModel(model) {
120
+ return model.toLowerCase().includes("moondream");
121
+ }
122
+ function defaultMaxTokens(request) {
123
+ return request.hint === "captcha" ? DEFAULT_CAPTCHA_MAX_TOKENS : DEFAULT_DOCUMENT_MAX_TOKENS;
124
+ }
125
+ function resolvedMaxTokens(request, model = "") {
126
+ const requestedMaxTokens = request.maxTokens ?? defaultMaxTokens(request);
127
+ return isKimiModel(model)
128
+ ? Math.max(requestedMaxTokens, KIMI_MIN_MAX_TOKENS)
129
+ : requestedMaxTokens;
130
+ }
131
+ function messagesPayload(request, model) {
132
+ const payload = {
133
+ ...(model ? { model } : {}),
134
+ messages: [
135
+ {
136
+ role: "user",
137
+ content: [
138
+ { type: "text", text: resolvePrompt(request) },
139
+ { type: "image_url", image_url: { url: imageUrl(request.image) } },
140
+ ],
141
+ },
142
+ ],
143
+ max_tokens: resolvedMaxTokens(request, model),
144
+ temperature: 0,
145
+ };
146
+ if (isGemmaModel(model ?? "")) {
147
+ payload.chat_template_kwargs = { enable_thinking: false };
148
+ }
149
+ return payload;
150
+ }
151
+ function cloudflareMessagesPayload(request, model) {
152
+ const payload = messagesPayload(request, model);
153
+ delete payload.model;
154
+ return payload;
155
+ }
156
+ function moondreamPayload(request) {
157
+ return {
158
+ task: "query",
159
+ image: imageUrl(request.image),
160
+ question: resolvePrompt(request),
161
+ stream: true,
162
+ reasoning: false,
163
+ temperature: 0,
164
+ max_tokens: resolvedMaxTokens(request),
165
+ };
166
+ }
167
+ function incompleteResponseError(model, finishReason) {
168
+ return new TransportError(`OCR model "${model}" did not complete normally (finish_reason: ${finishReason})`, {
169
+ code: "OCR_INCOMPLETE_RESPONSE",
170
+ status: 502,
171
+ details: { finishReason },
172
+ });
173
+ }
174
+ function responseContent(payload, cloudflare, model) {
175
+ const envelope = unknownRecord(payload);
176
+ const root = cloudflare ? unknownRecord(envelope?.result) : envelope;
177
+ const choices = root?.choices;
178
+ if (!Array.isArray(choices))
179
+ return undefined;
180
+ const choice = unknownRecord(choices[0]);
181
+ if (typeof choice?.finish_reason === "string" && choice.finish_reason !== "stop") {
182
+ throw incompleteResponseError(model, choice.finish_reason);
183
+ }
184
+ const message = unknownRecord(choice?.message);
185
+ return typeof message?.content === "string" ? message.content.trim() || undefined : undefined;
186
+ }
187
+ function malformedResponseError(model, cause) {
188
+ return new TransportError(`OCR model "${model}" returned a malformed response`, {
189
+ code: "OCR_UPSTREAM_FAILED",
190
+ status: 502,
191
+ cause,
192
+ });
193
+ }
194
+ async function responseJson(response, model) {
195
+ try {
196
+ return await response.json();
197
+ }
198
+ catch (error) {
199
+ if (isTimeoutLikeError(error))
200
+ throw toOcrTransportError(error);
201
+ throw malformedResponseError(model, error instanceof Error ? error : new Error("Failed to decode OCR response JSON"));
202
+ }
203
+ }
204
+ function moondreamSseContent(body, model) {
205
+ let finalAnswer;
206
+ let firstDecodingFailure;
207
+ let terminalFinishReason;
208
+ for (const line of body.split(/\r?\n/u)) {
209
+ const trimmed = line.trim();
210
+ if (!trimmed.startsWith("data:"))
211
+ continue;
212
+ const data = trimmed.slice("data:".length).trim();
213
+ if (!data || data === "[DONE]")
214
+ continue;
215
+ let parsed;
216
+ try {
217
+ parsed = JSON.parse(data);
218
+ }
219
+ catch (error) {
220
+ firstDecodingFailure ??=
221
+ error instanceof Error ? error : new Error("Failed to decode OCR SSE event");
222
+ continue;
223
+ }
224
+ const event = unknownRecord(parsed);
225
+ const chunk = unknownRecord(event?.chunk) ?? unknownRecord(event?.result) ?? event;
226
+ if (chunk?.finish_reason === "stop" &&
227
+ typeof chunk.answer === "string" &&
228
+ chunk.answer.trim()) {
229
+ finalAnswer = chunk.answer.trim();
230
+ }
231
+ else if (typeof chunk?.finish_reason === "string") {
232
+ terminalFinishReason = chunk.finish_reason;
233
+ }
234
+ }
235
+ if (finalAnswer)
236
+ return finalAnswer;
237
+ if (terminalFinishReason)
238
+ throw incompleteResponseError(model, terminalFinishReason);
239
+ if (firstDecodingFailure)
240
+ throw malformedResponseError(model, firstDecodingFailure);
241
+ return finalAnswer;
242
+ }
243
+ function emptyResponseError(model) {
244
+ return new TransportError(`OCR model "${model}" returned no usable text`, {
245
+ code: "OCR_UPSTREAM_FAILED",
246
+ status: 502,
247
+ fix: `Verify ${APIFUSE__OCR__MODEL_ENV}="${model}" supports image input and the runtime calling convention for that model.`,
248
+ });
249
+ }
250
+ function toOcrTransportError(error) {
251
+ if (error instanceof TransportError)
252
+ return error;
253
+ if (isTimeoutLikeError(error)) {
254
+ return new TransportError("OCR upstream request timed out", {
255
+ code: "transport_timeout",
256
+ status: 0,
257
+ cause: error,
258
+ });
259
+ }
260
+ return new TransportError("OCR upstream network request failed", {
261
+ code: "transport_network_error",
262
+ status: 0,
263
+ cause: error instanceof Error ? error : undefined,
264
+ });
265
+ }
266
+ function createOcrClient(model, recognize) {
267
+ return {
268
+ recognize,
269
+ async extractCaptchaText(image, options = {}) {
270
+ const result = await recognize({ image, hint: "captcha" });
271
+ const candidates = extractCaptchaCandidates(result.text, options);
272
+ const primary = candidates[0];
273
+ if (!primary?.text)
274
+ throw emptyResponseError(model);
275
+ return {
276
+ text: primary.text,
277
+ candidates,
278
+ satisfiesConstraints: primary.satisfiesConstraints,
279
+ model: result.model,
280
+ };
281
+ },
282
+ };
283
+ }
284
+ export function createCloudflareWorkersAiOcrClient(options) {
285
+ const model = options.model ?? DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL;
286
+ const runFetch = options.fetch ?? fetch;
287
+ return createOcrClient(model, async (request) => {
288
+ const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
289
+ try {
290
+ let response;
291
+ try {
292
+ response = await runFetch(`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(options.accountId)}/ai/run/${model}`, {
293
+ method: "POST",
294
+ headers: {
295
+ Authorization: `Bearer ${options.apiToken}`,
296
+ "Content-Type": "application/json",
297
+ },
298
+ body: JSON.stringify(isMoondreamModel(model)
299
+ ? moondreamPayload(request)
300
+ : cloudflareMessagesPayload(request, model)),
301
+ signal: timeout.controller.signal,
302
+ });
303
+ }
304
+ catch (error) {
305
+ throw toOcrTransportError(error);
306
+ }
307
+ if (!response.ok) {
308
+ throw new TransportError("OCR upstream request failed", {
309
+ code: "OCR_UPSTREAM_FAILED",
310
+ status: response.status,
311
+ upstreamStatus: response.status,
312
+ });
313
+ }
314
+ const text = isMoondreamModel(model)
315
+ ? moondreamSseContent(await response.text(), model)
316
+ : responseContent(await responseJson(response, model), true, model);
317
+ if (!text)
318
+ throw emptyResponseError(model);
319
+ return { text, model };
320
+ }
321
+ catch (error) {
322
+ throw toOcrTransportError(error);
323
+ }
324
+ finally {
325
+ timeout.clear();
326
+ }
327
+ });
328
+ }
329
+ export function createOpenAiCompatibleOcrClient(options) {
330
+ const model = options.model;
331
+ const runFetch = options.fetch ?? fetch;
332
+ return createOcrClient(model, async (request) => {
333
+ const headers = { "Content-Type": "application/json" };
334
+ if (options.apiKey)
335
+ headers.Authorization = `Bearer ${options.apiKey}`;
336
+ const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_OCR_TIMEOUT_MS);
337
+ try {
338
+ let response;
339
+ try {
340
+ response = await runFetch(`${options.baseUrl.replace(/\/+$/u, "")}/chat/completions`, {
341
+ method: "POST",
342
+ headers,
343
+ body: JSON.stringify(messagesPayload(request, model)),
344
+ signal: timeout.controller.signal,
345
+ });
346
+ }
347
+ catch (error) {
348
+ throw toOcrTransportError(error);
349
+ }
350
+ if (!response.ok) {
351
+ throw new TransportError("OCR upstream request failed", {
352
+ code: "OCR_UPSTREAM_FAILED",
353
+ status: response.status,
354
+ upstreamStatus: response.status,
355
+ });
356
+ }
357
+ const text = responseContent(await responseJson(response, model), false, model);
358
+ if (!text)
359
+ throw emptyResponseError(model);
360
+ return { text, model };
361
+ }
362
+ catch (error) {
363
+ throw toOcrTransportError(error);
364
+ }
365
+ finally {
366
+ timeout.clear();
367
+ }
368
+ });
369
+ }
370
+ function cleanCaptchaText(text) {
371
+ const afterColon = text.slice(text.lastIndexOf(":") + 1).trim();
372
+ return afterColon.replace(/^[\s\p{P}\p{S}]+|[\s\p{P}\p{S}]+$/gu, "");
373
+ }
374
+ function caseFold(value, caseSensitive) {
375
+ return caseSensitive ? value : value.toLocaleLowerCase();
376
+ }
377
+ function matchesCharset(text, charset, caseSensitive) {
378
+ if (charset === undefined)
379
+ return true;
380
+ if (typeof charset === "string") {
381
+ const allowed = new Set([...caseFold(charset, caseSensitive)]);
382
+ return [...caseFold(text, caseSensitive)].every((character) => allowed.has(character));
383
+ }
384
+ const flags = caseSensitive || charset.flags.includes("i") ? charset.flags : `${charset.flags}i`;
385
+ const matcher = new RegExp(charset.source, flags);
386
+ return [...text].every((character) => {
387
+ matcher.lastIndex = 0;
388
+ return matcher.test(character);
389
+ });
390
+ }
391
+ function satisfiesCaptchaConstraints(text, options) {
392
+ const lengthMatches = options.length === undefined || [...text].length === options.length;
393
+ return lengthMatches && matchesCharset(text, options.charset, options.caseSensitive !== false);
394
+ }
395
+ function homoglyphAlternatives(character) {
396
+ const group = HOMOGLYPH_CLASSES.find((characters) => characters.includes(character));
397
+ return group?.filter((alternative) => alternative !== character) ?? [];
398
+ }
399
+ export function extractCaptchaCandidates(modelText, options = {}) {
400
+ const primaryText = cleanCaptchaText(modelText);
401
+ const primary = {
402
+ text: primaryText,
403
+ satisfiesConstraints: satisfiesCaptchaConstraints(primaryText, options),
404
+ };
405
+ const requestedMaxCandidates = options.maxCandidates ?? DEFAULT_MAX_CAPTCHA_CANDIDATES;
406
+ const maxCandidates = Number.isFinite(requestedMaxCandidates)
407
+ ? Math.max(1, Math.floor(requestedMaxCandidates))
408
+ : DEFAULT_MAX_CAPTCHA_CANDIDATES;
409
+ if (primary.satisfiesConstraints || maxCandidates === 1)
410
+ return [primary];
411
+ if (options.length !== undefined && [...primaryText].length !== options.length)
412
+ return [primary];
413
+ const candidates = [primary];
414
+ const queue = [primaryText];
415
+ const visited = new Set(queue);
416
+ for (let index = 0; index < queue.length && candidates.length < maxCandidates; index += 1) {
417
+ const current = queue[index] ?? "";
418
+ const characters = [...current];
419
+ for (let position = 0; position < characters.length; position += 1) {
420
+ const character = characters[position] ?? "";
421
+ for (const alternative of homoglyphAlternatives(character)) {
422
+ const nextCharacters = [...characters];
423
+ nextCharacters[position] = alternative;
424
+ const next = nextCharacters.join("");
425
+ if (visited.has(next))
426
+ continue;
427
+ visited.add(next);
428
+ queue.push(next);
429
+ if (satisfiesCaptchaConstraints(next, options)) {
430
+ candidates.push({ text: next, satisfiesConstraints: true });
431
+ if (candidates.length >= maxCandidates)
432
+ return candidates;
433
+ }
434
+ if (visited.size >= MAX_HOMOGLYPH_SEARCH_NODES)
435
+ return candidates;
436
+ }
437
+ }
438
+ }
439
+ return candidates;
440
+ }
@@ -1,4 +1,4 @@
1
- import type { TraceSpan } from "../types";
1
+ import type { TraceSpan } from "../types.js";
2
2
  export interface OTLPExportOptions {
3
3
  endpoint: string;
4
4
  headers?: Record<string, string>;
@@ -1,4 +1,4 @@
1
- import type { Span } from "./trace";
1
+ import type { Span } from "./trace.js";
2
2
  export type PerfStats = {
3
3
  p50: number;
4
4
  p95: number;
@@ -1,2 +1,2 @@
1
- import type { ProviderDefinition } from "../types";
1
+ import type { ProviderDefinition } from "../types.js";
2
2
  export declare function getProviderBaseUrl(provider: ProviderDefinition): string | undefined;
@@ -1,8 +1,7 @@
1
1
  export function getProviderBaseUrl(provider) {
2
2
  const operations = Object.values(provider.operations);
3
3
  for (const operation of operations) {
4
- const baseUrl = operation.upstream
5
- ?.baseUrl;
4
+ const baseUrl = operation.upstream?.baseUrl;
6
5
  if (typeof baseUrl === "string" && baseUrl.length > 0) {
7
6
  return baseUrl;
8
7
  }
@@ -1,4 +1,4 @@
1
- import { TransportError } from "../errors";
1
+ import { TransportError } from "../errors.js";
2
2
  export declare const PROXY_AUTH_IP_DENIED_CODE = "PROXY_AUTH_IP_DENIED";
3
3
  export declare const PROXY_AUTH_IP_DENIED_MESSAGE = "Proxy source IP is not authorized. Add the runtime egress IP to the proxy provider allowlist.";
4
4
  export declare const PROXY_EDGE_AUTH_REJECTED_CODE = "PROXY_EDGE_AUTH_REJECTED";
@@ -1,4 +1,4 @@
1
- import { TransportError } from "../errors";
1
+ import { TransportError } from "../errors.js";
2
2
  export const PROXY_AUTH_IP_DENIED_CODE = "PROXY_AUTH_IP_DENIED";
3
3
  export const PROXY_AUTH_IP_DENIED_MESSAGE = "Proxy source IP is not authorized. Add the runtime egress IP to the proxy provider allowlist.";
4
4
  export const PROXY_EDGE_AUTH_REJECTED_CODE = "PROXY_EDGE_AUTH_REJECTED";
@@ -11,8 +11,12 @@ const PROXY_POOL_STALE_STATUS_CODES = new Set([509, 512]);
11
11
  const PROXY_EDGE_TLS_REJECTED_STATUS_CODES = new Set([495]);
12
12
  const PROXY_AUTH_IP_DENIED_PATTERN = /\b(?:source|egress|client)\s+ip\b.{0,120}\b(?:deny|denied|unauthori[sz]ed|not\s+authori[sz]ed|white\s*list|allow\s*list)\b|\b(?:white\s*list|allow\s*list)\b.{0,120}\b(?:source|egress|client)\s+ip\b/i;
13
13
  const PROXY_EDGE_AUTH_REJECTED_PATTERN = /\bauth\s+ip\s+err\b|\bproxy\b.{0,120}\bauth(?:entication)?\b.{0,120}\b(?:reject(?:ed)?|fail(?:ed)?|invalid|den(?:y|ied)|unauthori[sz]ed)\b|\bauth(?:entication)?\b.{0,120}\b(?:reject(?:ed)?|fail(?:ed)?|invalid|den(?:y|ied)|unauthori[sz]ed)\b.{0,120}\bproxy\b/i;
14
- const PROXY_POOL_STALE_MESSAGE_PATTERN = /\bproxy\b.{0,120}\b(?:pool|lease|expired|unavailable|exhausted|non[\s-]?200\s+code:\s*(?:509|512))\b|\bnon[\s-]?200\s+code:\s*(?:509|512)\b.{0,120}\bproxy\b|\bsmartproxy\b.{0,120}\b(?:509|512)\b/i;
15
- const PROXY_EDGE_TLS_REJECTED_MESSAGE_PATTERN = /\b(?:smartproxy|proxy)\b.{0,160}\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\s-]?200)\b|\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\s-]?200)\b.{0,160}\b(?:smartproxy|proxy)\b/i;
14
+ // Vendor host tokens that can appear in upstream error strings. Adding a proxy
15
+ // vendor updates every classifier below in one place. `proxy` is the generic
16
+ // fallback so vendor-agnostic messages still classify.
17
+ const PROXY_VENDOR_ALTERNATION = "smartproxy|nodemaven|proxy";
18
+ const PROXY_POOL_STALE_MESSAGE_PATTERN = new RegExp(`\\bproxy\\b.{0,120}\\b(?:pool|lease|expired|unavailable|exhausted|non[\\s-]?200\\s+code:\\s*(?:509|512))\\b|\\bnon[\\s-]?200\\s+code:\\s*(?:509|512)\\b.{0,120}\\bproxy\\b|\\b(?:${PROXY_VENDOR_ALTERNATION})\\b.{0,120}\\b(?:509|512)\\b`, "i");
19
+ const PROXY_EDGE_TLS_REJECTED_MESSAGE_PATTERN = new RegExp(`\\b(?:${PROXY_VENDOR_ALTERNATION})\\b.{0,160}\\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\\s-]?200)\\b|\\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\\s-]?200)\\b.{0,160}\\b(?:${PROXY_VENDOR_ALTERNATION})\\b`, "i");
16
20
  export function isProxyAuthIpDeniedMessage(message) {
17
21
  return PROXY_AUTH_IP_DENIED_PATTERN.test(message);
18
22
  }
@@ -42,8 +46,7 @@ export function isProxyPoolStaleMessage(message) {
42
46
  return PROXY_POOL_STALE_MESSAGE_PATTERN.test(message);
43
47
  }
44
48
  export function isProxyPoolRefreshableError(error) {
45
- if (error instanceof TransportError &&
46
- error.code === PROXY_AUTH_IP_DENIED_CODE) {
49
+ if (error instanceof TransportError && error.code === PROXY_AUTH_IP_DENIED_CODE) {
47
50
  return false;
48
51
  }
49
52
  if (error instanceof TransportError &&
@@ -57,8 +60,7 @@ export function isProxyPoolRefreshableError(error) {
57
60
  error instanceof Error ? error.message : String(error),
58
61
  cause instanceof Error ? cause.message : "",
59
62
  ].join(" ");
60
- return (PROXY_POOL_STALE_MESSAGE_PATTERN.test(message) ||
61
- PROXY_EDGE_AUTH_REJECTED_PATTERN.test(message));
63
+ return (PROXY_POOL_STALE_MESSAGE_PATTERN.test(message) || PROXY_EDGE_AUTH_REJECTED_PATTERN.test(message));
62
64
  }
63
65
  export const isProxyPoolStaleError = isProxyPoolRefreshableError;
64
66
  export function createProxyPoolStaleError(status, cause) {
@@ -0,0 +1,56 @@
1
+ import type { ProviderProxyPolicy } from "../types.js";
2
+ export declare const NODEMAVEN_USERNAME_ENV = "APIFUSE__PROXY__NODEMAVEN_USERNAME";
3
+ export declare const NODEMAVEN_PASSWORD_ENV = "APIFUSE__PROXY__NODEMAVEN_PASSWORD";
4
+ export declare const NODEMAVEN_FILTER_ENV = "APIFUSE__PROXY__NODEMAVEN_FILTER";
5
+ export declare const NODEMAVEN_GATEWAY_HOST = "gate.nodemaven.com";
6
+ export type NodemavenCredentials = {
7
+ readonly username: string;
8
+ readonly password: string;
9
+ readonly filter?: string;
10
+ };
11
+ /** Both schemes tunnel bytes end-to-end, preserving the client TLS handshake. */
12
+ export type ProxyProtocol = "http" | "socks5";
13
+ /**
14
+ * NodeMaven's fastest protocol: HTTP CONNECT. Benchmarks (KR, cold + warm)
15
+ * showed socks5 through the gateway adds ~500ms per request over http, so
16
+ * NodeMaven never defaults to socks5.
17
+ */
18
+ export declare const NODEMAVEN_DEFAULT_PROTOCOL: ProxyProtocol;
19
+ export declare const NODEMAVEN_MAX_POOL_SIZE = 50;
20
+ export declare function hasNodemavenCredentials(): boolean;
21
+ export declare function nodemavenPoolSize(policy: ProviderProxyPolicy): number;
22
+ export declare function nodemavenLifetimeMinutes(policy: ProviderProxyPolicy): number;
23
+ export type NodemavenSessionWindow = {
24
+ refreshEpoch: number;
25
+ expiresAt: string;
26
+ };
27
+ /** Stable wall-clock window shared by every process deriving the same sticky sid. */
28
+ export declare function nodemavenSessionWindow(policy: ProviderProxyPolicy, now?: number): NodemavenSessionWindow;
29
+ export type NodemavenSynthesisInput = {
30
+ policy: ProviderProxyPolicy;
31
+ /** Explicit credentials; synthesis never reads process-global state. */
32
+ credentials: NodemavenCredentials;
33
+ affinityKey: string | undefined;
34
+ protocol: ProxyProtocol;
35
+ poolIndex: number;
36
+ refreshEpoch: number;
37
+ /** ISO 3166-1 alpha-2, already resolved by the caller (falls back to env). */
38
+ country?: string;
39
+ /** Clock injection used by native sticky-expiry lifecycle tests. */
40
+ now?: number;
41
+ /** Stable caller-owned hard expiry when the refresh epoch is wall-clock-derived. */
42
+ expiresAt?: string;
43
+ };
44
+ export type NodemavenSynthesis = {
45
+ url: string;
46
+ protocol: ProxyProtocol;
47
+ sticky: boolean;
48
+ sessionId: string;
49
+ expiresAt?: string;
50
+ diagnostics: Record<string, string | number | boolean>;
51
+ };
52
+ /**
53
+ * Synthesize a NodeMaven gateway proxy URL locally from static credentials.
54
+ * There is no allocation API — geo/session are encoded in the username.
55
+ */
56
+ export declare function synthesizeNodemavenProxy(input: NodemavenSynthesisInput): NodemavenSynthesis;