@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
package/src/dev.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { serve } from "./server/serve";
2
- import type { ProviderDefinition } from "./types";
1
+ import { serve } from "./server/serve.js";
2
+ import type { ProviderDefinition } from "./types.js";
3
3
 
4
4
  export interface DevServerOptions {
5
5
  port?: number;
@@ -18,17 +18,12 @@ export function createDevServer(
18
18
  console.log(
19
19
  `[apifuse dev] ${provider.id}@${provider.version} running at http://localhost:${port}`,
20
20
  );
21
- console.log(
22
- `[apifuse dev] Operations: ${Object.keys(provider.operations).join(", ")}`,
23
- );
21
+ console.log(`[apifuse dev] Operations: ${Object.keys(provider.operations).join(", ")}`);
24
22
  console.log(`[apifuse dev] Health: http://localhost:${port}/health`);
25
23
  },
26
24
  };
27
25
  }
28
26
 
29
- export function startDevServer(
30
- provider: ProviderDefinition,
31
- options?: DevServerOptions,
32
- ): void {
27
+ export function startDevServer(provider: ProviderDefinition, options?: DevServerOptions): void {
33
28
  createDevServer(provider, options).start();
34
29
  }
@@ -0,0 +1,128 @@
1
+ import type { ProviderErrorStatus } from "./types.js";
2
+
3
+ // This set suppresses the unregistered-provider-error-code signal for codes
4
+ // intentionally emitted by SDK paths. It is not the complete authority for
5
+ // runtime error resolution: branded errors and additional canonical SDK codes
6
+ // must also remain immune to provider-declared status/retryability overrides.
7
+ export const SDK_OWNED_PROVIDER_ERROR_CODES = new Set([
8
+ "MISSING_SECRET",
9
+ "AUTH_PROMPT_UNAVAILABLE",
10
+ "BROWSER_CDP_POOL_REQUIRED",
11
+ "BROWSER_RUNTIME_UNSUPPORTED",
12
+ "STEALTH_RUNTIME_UNSUPPORTED",
13
+ "SSE_EVENT_UNDECLARED",
14
+ "STREAM_EVENT_TOO_LARGE",
15
+ "STREAM_CHUNK_TOO_LARGE",
16
+ "SSE_RESULT_UNSUPPORTED",
17
+ "STREAM_RESULT_UNSUPPORTED",
18
+ "AUTH_FLOW_NOT_CONFIGURED",
19
+ "refresh_not_supported",
20
+ "RUNTIME_UNSUPPORTED",
21
+ "PROVIDER_STATE_UNSUPPORTED",
22
+ "CHOICE_TOKEN_MASTER_SECRET_NOT_CONFIGURED",
23
+ "CHOICE_WORD_ISSUANCE_INVALID",
24
+ "CHOICE_STATE_PAYLOAD_TOO_LARGE",
25
+ "CHOICE_STATE_UNAVAILABLE",
26
+ "CHOICE_CONTEXT_REQUIRED",
27
+ "unsupported_stealth_cookie_store_version",
28
+ "provider_secret_error",
29
+ "credential_key_error",
30
+ "credential_mode_error",
31
+ "flow_expired",
32
+ "turn_validation_error",
33
+ "context_access_error",
34
+ "OCR_UPSTREAM_FAILED",
35
+ "UNSUPPORTED_STT_OPTION",
36
+ "INVALID_STT_AUDIO",
37
+ "STT_AUDIO_TOO_LARGE",
38
+ "STT_UPSTREAM_FAILED",
39
+ "INVALID_STT_VERIFICATION_CODE_OPTIONS",
40
+ "NO_CODE_FOUND",
41
+ "AMBIGUOUS_CODE",
42
+ "retry_invalid_policy",
43
+ "retry_unsafe_method",
44
+ "stealth_cookie_store_serialize_failed",
45
+ "response_too_large",
46
+ "transport_stream_unavailable",
47
+ "transport_invalid_method",
48
+ "http_transport_override_unsupported",
49
+ "http_redirect_policy_invalid",
50
+ "http_redirect_stopped",
51
+ "http_redirect_max_hops",
52
+ "http_redirect_missing_location",
53
+ "http_redirect_loop",
54
+ "transport_invalid_url",
55
+ "retry_exhausted",
56
+ "auth_abort_unsafe_data",
57
+ "credentials_auth_missing_credential_keys",
58
+ "credentials_auth_missing_credential",
59
+ "credentials_auth_invalid_login_result",
60
+ "credentials_auth_unknown_challenge",
61
+ "credentials_auth_unknown_pending_challenge",
62
+ "STATEFUL_FORWARDING_NOT_CONFIGURED",
63
+ "STATEFUL_FORWARDING_SIGNATURE_MISSING",
64
+ "STATEFUL_FORWARDING_NONCE_INVALID",
65
+ "STATEFUL_FORWARDING_TIMESTAMP_INVALID",
66
+ "STATEFUL_FORWARDING_SIGNATURE_INVALID",
67
+ "STATEFUL_FORWARDING_REPLAY_DETECTED",
68
+ "STATEFUL_FORWARDING_REPLAY_CACHE_FULL",
69
+ "STATEFUL_FORWARDING_ENVELOPE_INVALID",
70
+ "STATEFUL_FORWARDING_PROVIDER_MISMATCH",
71
+ "STATEFUL_FORWARDING_SOURCE_POD_MISMATCH",
72
+ "STATEFUL_FORWARDING_OWNER_FENCE_INVALID",
73
+ "STATEFUL_FORWARDING_REQUEST_FAILED",
74
+ "STATEFUL_FORWARDING_CONTEXT_MISSING",
75
+ "STATEFUL_FORWARDING_BAD_RESPONSE",
76
+ "STATEFUL_INTERNAL_EXECUTOR_NOT_CONFIGURED",
77
+ "STATEFUL_FILE_FORWARDING_UNSUPPORTED",
78
+ "STATEFUL_CONTROL_PLANE_OPERATION_AMBIGUOUS",
79
+ "STATEFUL_CONTROL_PLANE_REQUEST_FAILED",
80
+ "STATEFUL_CONTROL_PLANE_HTTP_ERROR",
81
+ "STATEFUL_CONTROL_PLANE_INVALID_RESPONSE",
82
+ ]);
83
+
84
+ // Complete code authority for provider-declared runtime resolution. Keep this
85
+ // separate from signal suppression: declarations may document these codes, but
86
+ // their status and retryability can never override the SDK's canonical result.
87
+ export const SDK_RUNTIME_OWNED_ERROR_CODES = new Set([
88
+ ...SDK_OWNED_PROVIDER_ERROR_CODES,
89
+ "reauth_required",
90
+ "OCR_UNAVAILABLE",
91
+ "UNSUPPORTED_OCR_BACKEND",
92
+ "STT_UNAVAILABLE",
93
+ "UNSUPPORTED_STT_BACKEND",
94
+ "OUTPUT_VALIDATION_FAILED",
95
+ "NOT_FOUND",
96
+ "not_found",
97
+ ]);
98
+
99
+ // Canonical SDK status mapping for recognized provider-thrown error codes.
100
+ // serve.ts toStatusCode consults this map (after operation-declared overrides
101
+ // for non-SDK-owned codes), and the authoring lint treats these codes as
102
+ // SDK-registered. Add new codes here instead of duplicating literals in
103
+ // either consumer.
104
+ export const SDK_STATUS_MAPPED_PROVIDER_ERROR_CODES: ReadonlyMap<string, ProviderErrorStatus> =
105
+ new Map<string, ProviderErrorStatus>([
106
+ ["AUTH_REQUIRED", 401],
107
+ ["reauth_required", 401],
108
+ // Unprovisioned declared secret: a deployment/config defect, never an
109
+ // upstream failure — explicit 400.
110
+ ["MISSING_SECRET", 400],
111
+ ["NOT_FOUND", 404],
112
+ ["not_found", 404],
113
+ ["NO_DATA", 404],
114
+ ["RATE_LIMITED", 429],
115
+ ["UPSTREAM_RATE_LIMIT", 429],
116
+ ["LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR", 429],
117
+ // Deterministic upstream business refusal (honest-provider-error-
118
+ // contract): the upstream evaluated the request and said no under its
119
+ // own rules — a conflict with upstream state, never a 5xx.
120
+ ["UPSTREAM_REJECTED", 409],
121
+ ["UPSTREAM_ERROR", 502],
122
+ ["BLOCKED", 502],
123
+ ["OCR_UNAVAILABLE", 503],
124
+ ["UNSUPPORTED_OCR_BACKEND", 503],
125
+ ["STT_UNAVAILABLE", 503],
126
+ ["UNSUPPORTED_STT_BACKEND", 503],
127
+ ["STATEFUL_FORWARDING_REPLAY_CACHE_FULL", 503],
128
+ ]);
package/src/errors.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { ProviderErrorCategory } from "./observability";
1
+ import type { ProviderErrorCategory } from "./observability.js";
2
+ import type { HttpRedirectFailureReason } from "./types.js";
2
3
 
3
4
  // Versioned, cross-realm brands. `Symbol.for` resolves to the same symbol in
4
5
  // any copy/entrypoint of this SDK major version, so an error created by a
@@ -8,10 +9,9 @@ import type { ProviderErrorCategory } from "./observability";
8
9
  // future breaking change to this contract mint a distinct key.
9
10
  const PROVIDER_ERROR_BRAND = Symbol.for("@apifuse/provider-sdk/error-brand@1");
10
11
  const PROVIDER_ERROR_BRAND_VALUE = 1;
11
- const SESSION_EXPIRED_BRAND = Symbol.for(
12
- "@apifuse/provider-sdk/error-kind/session-expired@1",
13
- );
12
+ const SESSION_EXPIRED_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/session-expired@1");
14
13
  const TRANSPORT_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/transport@1");
14
+ const VALIDATION_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/validation@1");
15
15
 
16
16
  // Defines a non-enumerable, non-writable, non-configurable own data property.
17
17
  // Immutable + own means a guard can trust it via a single descriptor read
@@ -35,9 +35,7 @@ function hasOwnBrand(value: unknown, brand: symbol, expected: number | true): bo
35
35
  }
36
36
  const descriptor = Object.getOwnPropertyDescriptor(value, brand);
37
37
  return (
38
- descriptor !== undefined &&
39
- Object.hasOwn(descriptor, "value") &&
40
- descriptor.value === expected
38
+ descriptor !== undefined && Object.hasOwn(descriptor, "value") && descriptor.value === expected
41
39
  );
42
40
  }
43
41
 
@@ -83,6 +81,21 @@ export class SDKError extends ProviderError {
83
81
  }
84
82
  }
85
83
 
84
+ /** Raised when persisted stealth cookies use a store version this SDK cannot read. */
85
+ export class StealthCookieStoreVersionError extends SDKError {
86
+ constructor(public readonly version: unknown) {
87
+ const displayedVersion =
88
+ typeof version === "string" || typeof version === "number"
89
+ ? String(version)
90
+ : "missing or invalid";
91
+ super(`Unsupported stealth cookie store version: ${displayedVersion}`, {
92
+ code: "unsupported_stealth_cookie_store_version",
93
+ details: { receivedVersion: version, supportedVersions: [1] },
94
+ });
95
+ this.name = "StealthCookieStoreVersionError";
96
+ }
97
+ }
98
+
86
99
  export class AuthError extends ProviderError {
87
100
  constructor(message: string, options?: ProviderErrorOptions) {
88
101
  super(message, options);
@@ -91,10 +104,7 @@ export class AuthError extends ProviderError {
91
104
  }
92
105
 
93
106
  export class SessionExpiredError extends AuthError {
94
- constructor(
95
- message = "Provider session expired",
96
- options?: ProviderErrorOptions,
97
- ) {
107
+ constructor(message = "Provider session expired", options?: ProviderErrorOptions) {
98
108
  super(message, {
99
109
  code: "reauth_required",
100
110
  category: "credential_expired",
@@ -117,6 +127,7 @@ export class ValidationError extends ProviderError {
117
127
  super(message, options);
118
128
  this.name = "ValidationError";
119
129
  this.zodError = options?.zodError;
130
+ defineErrorBrand(this, VALIDATION_BRAND, true);
120
131
  }
121
132
  }
122
133
 
@@ -138,6 +149,33 @@ export class TransportError extends ProviderError {
138
149
  }
139
150
  }
140
151
 
152
+ export type HttpRedirectErrorOptions = TransportErrorOptions & {
153
+ reason: HttpRedirectFailureReason;
154
+ /** Redacted redirect target suitable for provider diagnostics. */
155
+ target?: string;
156
+ };
157
+
158
+ /** Raised when an opt-in ctx.http redirect policy refuses or cannot resolve a hop. */
159
+ export class HttpRedirectError extends TransportError {
160
+ readonly reason: HttpRedirectFailureReason;
161
+ readonly target?: string;
162
+
163
+ constructor(message: string, options: HttpRedirectErrorOptions) {
164
+ const { reason, target, ...transportOptions } = options;
165
+ super(message, {
166
+ ...transportOptions,
167
+ code: `http_redirect_${reason}`,
168
+ details: {
169
+ reason,
170
+ ...(target ? { target } : {}),
171
+ },
172
+ });
173
+ this.name = "HttpRedirectError";
174
+ this.reason = reason;
175
+ this.target = target;
176
+ }
177
+ }
178
+
141
179
  // Cross-module type guards. Prefer these over `instanceof` at any boundary that
142
180
  // may receive an error from a different copy/entrypoint of the SDK (see the HTTP
143
181
  // server error boundary). They recognize branded errors regardless of which
@@ -154,6 +192,13 @@ export function isTransportError(value: unknown): value is TransportError {
154
192
  return isProviderError(value) && hasOwnBrand(value, TRANSPORT_BRAND, true);
155
193
  }
156
194
 
195
+ export function isValidationError(value: unknown): value is ValidationError {
196
+ return (
197
+ isProviderError(value) &&
198
+ (hasOwnBrand(value, VALIDATION_BRAND, true) || value.name === "ValidationError")
199
+ );
200
+ }
201
+
157
202
  export class ProviderSecretError extends ProviderError {
158
203
  constructor(message: string, options?: ProviderErrorOptions) {
159
204
  super(message, { code: "provider_secret_error", ...options });
@@ -0,0 +1,247 @@
1
+ import type { JsonValue } from "./contract-json.js";
2
+
3
+ export const REDACTED_FIXTURE_VALUE = "[REDACTED]";
4
+
5
+ const OPAQUE_TOKEN = /^[A-Za-z0-9_+/=.:~-]+$/;
6
+ const OPAQUE_TOKEN_RUN = /[A-Za-z0-9_+/=.:~-]{24,}/g;
7
+ const URL_RUN = /https?:\/\/[^\s"'<>]+/gi;
8
+ const PEM_PRIVATE_KEY =
9
+ /-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/g;
10
+
11
+ /** Matches credential field names without treating benign prefixes such as `author` as `auth`. */
12
+ export function isSensitiveFixtureKey(key: string): boolean {
13
+ const normalized = key.replace(/[-_\s]/g, "").toLowerCase();
14
+ const candidates = [normalized, normalized.replace(/(?:value|payload|header)$/, "")];
15
+ return candidates.some(
16
+ (candidate) =>
17
+ /^(?:authorization|authentication|auth|bearer|cookie|credential|password|passwd|privatekey|secret|session|sessionid|token)$/.test(
18
+ candidate,
19
+ ) ||
20
+ /^(?:api|client|service|access|consumer)(?:key|secret|token)$/.test(candidate) ||
21
+ /(?:authorization|credential|password|passwd|privatekey|secret|sessionid|token)$/.test(
22
+ candidate,
23
+ ),
24
+ );
25
+ }
26
+
27
+ /**
28
+ * Returns JSON fixture data with credential-bearing keys and heuristic-confirmed string secrets
29
+ * replaced. Ordinary short prose and identifiers are retained.
30
+ */
31
+ export function sanitizeFixture(value: JsonValue): JsonValue {
32
+ if (Array.isArray(value)) {
33
+ return value.map((item) => sanitizeFixture(item));
34
+ }
35
+
36
+ if (typeof value === "string") return sanitizeFixtureString(value);
37
+ if (value === null || typeof value !== "object") return value;
38
+
39
+ return Object.fromEntries(
40
+ Object.entries(value).map(([key, entryValue]) => [
41
+ key,
42
+ isSensitiveFixtureKey(key) ? REDACTED_FIXTURE_VALUE : sanitizeFixture(entryValue),
43
+ ]),
44
+ );
45
+ }
46
+
47
+ /** Applies the shared credential-key policy to ordinary JSON fixtures. */
48
+ export function sanitizeOrdinaryFixture(value: JsonValue): JsonValue {
49
+ if (Array.isArray(value)) return value.map((item) => sanitizeOrdinaryFixture(item));
50
+ if (value === null || typeof value !== "object") return value;
51
+ return Object.fromEntries(
52
+ Object.entries(value).map(([key, entryValue]) => [
53
+ key,
54
+ isSensitiveFixtureKey(key) ? REDACTED_FIXTURE_VALUE : sanitizeOrdinaryFixture(entryValue),
55
+ ]),
56
+ );
57
+ }
58
+
59
+ /** Sanitizes a primitive fixture string only when textual-secret heuristics match. */
60
+ export function sanitizeFixtureString(value: string): string {
61
+ let sanitized = value.replace(PEM_PRIVATE_KEY, REDACTED_FIXTURE_VALUE);
62
+ const retainedUrls: string[] = [];
63
+ sanitized = sanitized.replace(URL_RUN, (url) => {
64
+ const index =
65
+ retainedUrls.push(isCredentialBearingUrl(url) ? sanitizeUrlForLogs(url) : url) - 1;
66
+ return `APIFUSEURL${index}X`;
67
+ });
68
+ sanitized = redactSensitiveAssignments(sanitized);
69
+ sanitized = sanitized.replace(OPAQUE_TOKEN_RUN, (candidate) =>
70
+ isSensitiveFixtureValue(candidate) ? REDACTED_FIXTURE_VALUE : candidate,
71
+ );
72
+ sanitized = sanitized.replace(
73
+ /APIFUSEURL(\d+)X/g,
74
+ (_match, index: string) => retainedUrls[Number(index)] ?? REDACTED_FIXTURE_VALUE,
75
+ );
76
+ return sanitized;
77
+ }
78
+
79
+ /** True for opaque values that are unsafe to retain in paths or unstructured text. */
80
+ export function isSensitiveFixtureValue(value: string): boolean {
81
+ const candidate = decodePathSegment(value);
82
+ if (/^bot(?:\d{6,}:)?[A-Za-z0-9_-]{16,}$/i.test(candidate)) return true;
83
+ if (/^\d{6,}:[A-Za-z0-9_-]{20,}$/.test(candidate)) return true;
84
+ if (/^(?:gh[opusr]_|sk[-_]|xox[baprs]-)[A-Za-z0-9_-]{16,}$/i.test(candidate)) return true;
85
+ if (!OPAQUE_TOKEN.test(candidate) || candidate.length < 24) return false;
86
+ if (/^[a-f0-9]{32,}$/i.test(candidate)) return true;
87
+ return shannonEntropy(candidate) >= 3.5;
88
+ }
89
+
90
+ /** Sanitizes every path segment and values following a credential-like segment name. */
91
+ export function sanitizePathname(pathname: string): string {
92
+ const segments = pathname.split("/");
93
+ return segments
94
+ .map((segment, index) => {
95
+ if (!segment) return segment;
96
+ const decoded = decodePathSegment(segment);
97
+ const previous = index > 0 ? decodePathSegment(segments[index - 1] as string) : "";
98
+ if (
99
+ isSensitivePathSegment(decoded) ||
100
+ isCredentialPathKey(previous) ||
101
+ isSensitiveFixtureValue(decoded)
102
+ ) {
103
+ return REDACTED_FIXTURE_VALUE;
104
+ }
105
+ return segment;
106
+ })
107
+ .join("/");
108
+ }
109
+
110
+ function isCredentialPathKey(key: string): boolean {
111
+ const finalPathPart = key.split("/").at(-1) ?? "";
112
+ const baseSegment = finalPathPart.split(";", 1)[0] ?? "";
113
+ return isSensitiveFixtureKey(baseSegment.split(/[=:]/, 1)[0] ?? "");
114
+ }
115
+
116
+ function isSensitivePathSegment(segment: string): boolean {
117
+ return segment
118
+ .split(/[;/]/)
119
+ .some((part) => isSensitiveFixtureKey(part.split(/[=:]/, 1)[0] ?? ""));
120
+ }
121
+
122
+ /** Removes userinfo, query values, fragments, and credential-like path segments from log URLs. */
123
+ export function sanitizeUrlForLogs(value: string): string {
124
+ try {
125
+ const parsed = new URL(value, "https://fixture.invalid");
126
+ const queryMarker = parsed.search ? `?${REDACTED_FIXTURE_VALUE}` : "";
127
+ const path = sanitizePathname(parsed.pathname);
128
+ if (parsed.origin === "https://fixture.invalid" && !hasExplicitOrigin(value)) {
129
+ return `${path}${queryMarker}`;
130
+ }
131
+ return `${parsed.origin}${path}${queryMarker}`;
132
+ } catch {
133
+ return sanitizePathname(value.split(/[?#]/, 1)[0]);
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Returns query-free request provenance with each path segment scrubbed for credential-like values.
139
+ * Origins, URL userinfo, query values, and fragments are never persisted in request provenance.
140
+ */
141
+ export function requestPathForFixture(value: string): string {
142
+ try {
143
+ return sanitizePathname(new URL(value, "https://fixture.invalid").pathname);
144
+ } catch {
145
+ const path = value.split(/[?#]/, 1)[0];
146
+ return sanitizePathname(path.startsWith("/") ? path : `/${path}`);
147
+ }
148
+ }
149
+
150
+ /** Scrubs secrets and terminal/log control characters before diagnostic text is emitted. */
151
+ export function sanitizeDiagnosticText(value: string): string {
152
+ let sanitized = value
153
+ .replace(URL_RUN, (url) => sanitizeUrlForLogs(url))
154
+ .replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, `Bearer ${REDACTED_FIXTURE_VALUE}`);
155
+ sanitized = redactSensitiveAssignments(sanitized);
156
+ sanitized = sanitized.replace(OPAQUE_TOKEN_RUN, (candidate, offset: number, source: string) => {
157
+ if (/^(?:request|trace|correlation)[-_]?id[:=]/i.test(candidate)) return candidate;
158
+ const prefix = source.slice(Math.max(0, offset - 32), offset);
159
+ if (/(?:request|trace|correlation)[-_]?id\s*[:=]\s*$/i.test(prefix)) return candidate;
160
+ return isSensitiveFixtureValue(candidate) ? REDACTED_FIXTURE_VALUE : candidate;
161
+ });
162
+ return encodeDiagnosticControls(sanitized);
163
+ }
164
+
165
+ function redactSensitiveAssignments(value: string): string {
166
+ return value.replace(
167
+ /((["']?)([\w-]+)\2\s*[:=]\s*)("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;&]+)/gi,
168
+ (match, prefix: string, _quote: string, key: string, assignmentValue: string) => {
169
+ if (!isSensitiveFixtureKey(key) && key.toLowerCase() !== "key") return match;
170
+ const quote = assignmentValue.startsWith('"')
171
+ ? '"'
172
+ : assignmentValue.startsWith("'")
173
+ ? "'"
174
+ : "";
175
+ return `${prefix}${quote}${REDACTED_FIXTURE_VALUE}${quote}`;
176
+ },
177
+ );
178
+ }
179
+
180
+ function isCredentialBearingUrl(value: string): boolean {
181
+ try {
182
+ const parsed = new URL(value);
183
+ return (
184
+ parsed.username !== "" ||
185
+ parsed.password !== "" ||
186
+ parsed.hash !== "" ||
187
+ parsed.search !== "" ||
188
+ parsed.pathname.split("/").some((segment, index, segments) => {
189
+ const decoded = decodePathSegment(segment);
190
+ const previous = decodePathSegment(segments[index - 1] ?? "");
191
+ return (
192
+ isSensitiveFixtureKey(decoded) ||
193
+ isCredentialPathKey(previous) ||
194
+ isSensitiveFixtureValue(decoded)
195
+ );
196
+ })
197
+ );
198
+ } catch {
199
+ return false;
200
+ }
201
+ }
202
+
203
+ function encodeDiagnosticControls(value: string): string {
204
+ let result = "";
205
+ for (const character of value) {
206
+ const code = character.codePointAt(0) ?? 0;
207
+ if (code === 0x0a || code === 0x0d || code === 0x2028 || code === 0x2029) {
208
+ result += " ";
209
+ } else if (
210
+ (code >= 0 && code <= 0x1f) ||
211
+ (code >= 0x7f && code <= 0x9f) ||
212
+ code === 0x061c ||
213
+ code === 0x200e ||
214
+ code === 0x200f ||
215
+ (code >= 0x202a && code <= 0x202e) ||
216
+ (code >= 0x2066 && code <= 0x2069)
217
+ ) {
218
+ result += `\\u${code.toString(16).padStart(4, "0")}`;
219
+ } else {
220
+ result += character;
221
+ }
222
+ }
223
+ return result;
224
+ }
225
+
226
+ function decodePathSegment(value: string): string {
227
+ try {
228
+ return decodeURIComponent(value);
229
+ } catch {
230
+ return value;
231
+ }
232
+ }
233
+
234
+ function hasExplicitOrigin(value: string): boolean {
235
+ return /^[a-z][a-z\d+.-]*:\/\//i.test(value);
236
+ }
237
+
238
+ function shannonEntropy(value: string): number {
239
+ const counts = new Map<string, number>();
240
+ for (const character of value) counts.set(character, (counts.get(character) ?? 0) + 1);
241
+ let entropy = 0;
242
+ for (const count of counts.values()) {
243
+ const probability = count / value.length;
244
+ entropy -= probability * Math.log2(probability);
245
+ }
246
+ return entropy;
247
+ }
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
 
4
- import type { AuthTurn } from "../types";
4
+ import type { AuthTurn } from "../types.js";
5
5
  import {
6
6
  getProviderLocalePath,
7
7
  isProviderLocaleValue,
@@ -10,12 +10,9 @@ import {
10
10
  type ProviderLocaleKey,
11
11
  type ProviderLocaleValue,
12
12
  providerLocaleKey,
13
- } from "./keys";
13
+ } from "./keys.js";
14
14
 
15
- export type ProviderLocaleCatalogMap = Record<
16
- ProviderLocale,
17
- ProviderLocaleCatalog
18
- >;
15
+ export type ProviderLocaleCatalogMap = Record<ProviderLocale, ProviderLocaleCatalog>;
19
16
 
20
17
  export interface LoadProviderLocaleCatalogsOptions {
21
18
  providerDir: string;
@@ -58,9 +55,7 @@ export function resolveProviderLocaleValue(
58
55
  );
59
56
  }
60
57
 
61
- function asStringValue(
62
- value: ProviderLocaleValue | undefined,
63
- ): string | undefined {
58
+ function asStringValue(value: ProviderLocaleValue | undefined): string | undefined {
64
59
  return typeof value === "string" ? value : undefined;
65
60
  }
66
61
 
@@ -82,9 +77,7 @@ function localizeAuthInputSchema(
82
77
  },
83
78
  ): Record<string, unknown> | undefined {
84
79
  if (!expectedInput) return undefined;
85
- const schema = isRecord(expectedInput.schema)
86
- ? expectedInput.schema
87
- : expectedInput;
80
+ const schema = isRecord(expectedInput.schema) ? expectedInput.schema : expectedInput;
88
81
  const localizedSchema = localizeAuthSchemaObject(schema, options);
89
82
  if (localizedSchema === schema) return undefined;
90
83
  return isRecord(expectedInput.schema)
@@ -104,21 +97,16 @@ function localizeAuthSchemaObject(
104
97
  fallbackLocale: ProviderLocale;
105
98
  },
106
99
  ): Record<string, unknown> {
107
- const properties = isRecord(schema.properties)
108
- ? schema.properties
109
- : undefined;
100
+ const properties = isRecord(schema.properties) ? schema.properties : undefined;
110
101
  if (!properties) return schema;
111
102
 
112
103
  let changed = false;
113
104
  const localizedProperties = Object.fromEntries(
114
105
  Object.entries(properties).map(([fieldName, property]) => {
115
106
  if (!isRecord(property)) return [fieldName, property];
116
- const nameKey =
117
- typeof property.nameKey === "string" ? property.nameKey : undefined;
107
+ const nameKey = typeof property.nameKey === "string" ? property.nameKey : undefined;
118
108
  const descriptionKey =
119
- typeof property.descriptionKey === "string"
120
- ? property.descriptionKey
121
- : undefined;
109
+ typeof property.descriptionKey === "string" ? property.descriptionKey : undefined;
122
110
  const title = nameKey
123
111
  ? asStringValue(
124
112
  resolveProviderLocaleValue(
@@ -166,12 +154,7 @@ export function localizeAuthTurn(
166
154
  const fallbackLocale = options.fallbackLocale ?? "en";
167
155
  const hint = turn.hintKey
168
156
  ? asStringValue(
169
- resolveProviderLocaleValue(
170
- options.catalogs,
171
- turn.hintKey,
172
- options.locale,
173
- fallbackLocale,
174
- ),
157
+ resolveProviderLocaleValue(options.catalogs, turn.hintKey, options.locale, fallbackLocale),
175
158
  )
176
159
  : undefined;
177
160
  const expectedInput = localizeAuthInputSchema(turn.expectedInput, {
@@ -184,12 +167,7 @@ export function localizeAuthTurn(
184
167
  ? Object.fromEntries(
185
168
  Object.entries(fieldErrorKeys).flatMap(([fieldName, key]) => {
186
169
  const message = asStringValue(
187
- resolveProviderLocaleValue(
188
- options.catalogs,
189
- key,
190
- options.locale,
191
- fallbackLocale,
192
- ),
170
+ resolveProviderLocaleValue(options.catalogs, key, options.locale, fallbackLocale),
193
171
  );
194
172
  return message ? [[fieldName, message]] : [];
195
173
  }),
package/src/i18n/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./catalog";
2
- export * from "./keys";
1
+ export * from "./catalog.js";
2
+ export * from "./keys.js";
package/src/i18n/keys.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ProviderLocaleKey } from "../types";
1
+ import type { ProviderLocaleKey } from "../types.js";
2
2
 
3
- export type { ProviderLocale, ProviderLocaleKey } from "../types";
3
+ export type { ProviderLocale, ProviderLocaleKey } from "../types.js";
4
4
 
5
5
  const PROVIDER_LOCALE_KEY_RE =
6
6
  /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*(?:\.[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*|\.[0-9]+)*$/;
@@ -10,15 +10,11 @@ export function providerLocaleKey(key: string): ProviderLocaleKey {
10
10
  return key;
11
11
  }
12
12
 
13
- export function isProviderLocaleKey(
14
- value: unknown,
15
- ): value is ProviderLocaleKey {
13
+ export function isProviderLocaleKey(value: unknown): value is ProviderLocaleKey {
16
14
  return typeof value === "string" && PROVIDER_LOCALE_KEY_RE.test(value);
17
15
  }
18
16
 
19
- export function assertProviderLocaleKey(
20
- value: unknown,
21
- ): asserts value is ProviderLocaleKey {
17
+ export function assertProviderLocaleKey(value: unknown): asserts value is ProviderLocaleKey {
22
18
  if (!isProviderLocaleKey(value)) {
23
19
  throw new Error(
24
20
  `Provider locale key must be a dot path such as "meta.description" or "operations.search.description"; received ${JSON.stringify(value)}`,
@@ -50,9 +46,7 @@ export function getProviderLocalePath(
50
46
  export type ProviderLocaleValue = string | readonly string[];
51
47
  export type ProviderLocaleCatalog = Record<string, unknown>;
52
48
 
53
- export function isProviderLocaleValue(
54
- value: unknown,
55
- ): value is ProviderLocaleValue {
49
+ export function isProviderLocaleValue(value: unknown): value is ProviderLocaleValue {
56
50
  return (
57
51
  typeof value === "string" ||
58
52
  (Array.isArray(value) && value.every((entry) => typeof entry === "string"))