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

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 +127 -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 +122 -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 +13 -1
  79. package/dist/runtime/choice.js +514 -124
  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 +2077 -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 +127 -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 +157 -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 +65 -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 +685 -216
  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 +3060 -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,583 @@
1
+ #!/usr/bin/env bun
2
+
3
+ // Guards the published artifact against the nodenext type-resolution regression
4
+ // shipped in 2.2.0-beta.1/beta.2: emitted dist/*.d.ts (and dist/*.js) carried
5
+ // EXTENSIONLESS relative imports, so external provider repos compiling with
6
+ // moduleResolution nodenext could not resolve them. With skipLibCheck the
7
+ // errors were masked and types silently degraded — re-exported ProviderError
8
+ // lost its inherited Error members (name/message) and re-exported zod stopped
9
+ // inferring .refine() callback params (~17 false type errors in
10
+ // apifuse-provider-tabelog, see its PR #16).
11
+ //
12
+ // Three layers, all against the packed tarball (what consumers actually get):
13
+ // 1. @arethetypeswrong/cli — resolution/module-kind audit of every exports
14
+ // subpath, including internal resolution of relative specifiers in d.ts.
15
+ // 2. A fixture consumer compiled with real tsc under moduleResolution
16
+ // nodenext and skipLibCheck:false, asserting ProviderError keeps
17
+ // inherited Error members and zod re-exports keep .refine() inference.
18
+ // 3. A Node (not bun) ESM runtime import — node does not tolerate
19
+ // extensionless relative specifiers, bun does.
20
+ //
21
+ // Deliberate negative controls prove the fixture compiler actually fails on
22
+ // type errors, so this check cannot rot into a false-positive green.
23
+
24
+ import { execFileSync, spawnSync } from "node:child_process";
25
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
26
+ import { tmpdir } from "node:os";
27
+ import { join, resolve } from "node:path";
28
+ import { z } from "zod";
29
+
30
+ const PACK_RESULT_SCHEMA = z.array(
31
+ z.object({
32
+ filename: z.string(),
33
+ }),
34
+ );
35
+
36
+ const KEEP_TEMP = process.env.APIFUSE__PACK_TYPES__KEEP_TEMP === "1";
37
+ const sdkRoot = process.cwd();
38
+
39
+ const NEGATIVE_CONTROLS = [
40
+ {
41
+ filename: "negative-control-provider-error-name.ts",
42
+ expectedCode: "TS2322",
43
+ description: "ProviderError.name remains a string",
44
+ source: [
45
+ 'import { ProviderError } from "@apifuse/provider-sdk";',
46
+ "",
47
+ "// Intentionally wrong: name is a string. If this file compiles, the",
48
+ "// fixture consumer is not actually type-checking and the guard is void.",
49
+ 'export const mustNotCompile: number = new ProviderError("boom").name;',
50
+ "",
51
+ ].join("\n"),
52
+ },
53
+ {
54
+ filename: "negative-control-unknown-resolver-vendor.ts",
55
+ expectedCode: "TS2322",
56
+ description: "ProviderResolverConfig rejects an unknown vendor",
57
+ source: [
58
+ 'import type { ProviderResolverConfig } from "@apifuse/provider-sdk";',
59
+ "",
60
+ "export const mustNotCompile: ProviderResolverConfig = {",
61
+ '\tvendors: ["unknown-vendor"],',
62
+ '\tkinds: ["turnstile"],',
63
+ "};",
64
+ "",
65
+ ].join("\n"),
66
+ },
67
+ {
68
+ filename: "negative-control-define-provider-resolver-vendor.ts",
69
+ expectedCode: "TS2322",
70
+ description: "defineProvider rejects an unknown resolver vendor",
71
+ source: [
72
+ 'import { defineProvider, z } from "@apifuse/provider-sdk";',
73
+ "",
74
+ "export const mustNotCompile = defineProvider({",
75
+ '\tid: "invalid-resolver-vendor",',
76
+ '\tversion: "1.0.0",',
77
+ '\truntime: "standard",',
78
+ '\tresolver: { vendors: ["unknown-vendor"], kinds: ["turnstile"] },',
79
+ '\tmeta: { displayName: "Invalid Resolver Vendor", descriptionKey: "meta.description", category: "test" },',
80
+ "\toperations: {",
81
+ "\t\tprobe: {",
82
+ "\t\t\tinput: z.object({}),",
83
+ "\t\t\toutput: z.object({ ok: z.boolean() }),",
84
+ "\t\t\thandler: async () => ({ ok: true }),",
85
+ '\t\t\thealthCheckUnsupported: { reason: "type fixture" },',
86
+ "\t\t},",
87
+ "\t},",
88
+ "});",
89
+ "",
90
+ ].join("\n"),
91
+ },
92
+ {
93
+ filename: "negative-control-unknown-challenge-kind.ts",
94
+ expectedCode: "TS2820",
95
+ description: "ProviderChallenge rejects an unknown challenge kind",
96
+ source: [
97
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
98
+ "",
99
+ "export const mustNotCompile: ProviderChallenge = {",
100
+ '\tkind: "funcaptcha",',
101
+ '\tsiteKey: "key",',
102
+ '\tpageUrl: "https://example.com",',
103
+ "};",
104
+ "",
105
+ ].join("\n"),
106
+ },
107
+ {
108
+ filename: "negative-control-provider-challenge-kind.ts",
109
+ expectedCode: "TS2820",
110
+ description: "ProviderChallengeKind rejects an unknown challenge kind",
111
+ source: [
112
+ 'import type { ProviderChallengeKind } from "@apifuse/provider-sdk";',
113
+ "",
114
+ 'export const mustNotCompile: ProviderChallengeKind = "funcaptcha";',
115
+ "",
116
+ ].join("\n"),
117
+ },
118
+ {
119
+ filename: "negative-control-cookie-solution-token-read.ts",
120
+ expectedCode: "TS2339",
121
+ description: "ChallengeSolution requires narrowing before reading token",
122
+ source: [
123
+ 'import type { ChallengeSolution } from "@apifuse/provider-sdk";',
124
+ "",
125
+ "export function mustNotCompile(solution: ChallengeSolution): string {",
126
+ "\treturn solution.token;",
127
+ "}",
128
+ "",
129
+ ].join("\n"),
130
+ },
131
+ {
132
+ filename: "negative-control-cookie-challenge-site-key.ts",
133
+ expectedCode: "TS2353",
134
+ description: "cookie-family challenges reject token-family fields",
135
+ source: [
136
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
137
+ "",
138
+ "export const mustNotCompile: ProviderChallenge = {",
139
+ '\tkind: "cloudflare_interstitial",',
140
+ '\tpageUrl: "https://example.com",',
141
+ '\tsiteKey: "not-allowed",',
142
+ "};",
143
+ "",
144
+ ].join("\n"),
145
+ },
146
+ {
147
+ filename: "negative-control-aws-waf-site-key-type.ts",
148
+ expectedCode: "TS2322",
149
+ description: "aws_waf siteKey must be a string",
150
+ source: [
151
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
152
+ "",
153
+ "export const mustNotCompile: ProviderChallenge = {",
154
+ '\tkind: "aws_waf",',
155
+ '\tpageUrl: "https://example.com",',
156
+ "\tsiteKey: 123,",
157
+ "};",
158
+ "",
159
+ ].join("\n"),
160
+ },
161
+ {
162
+ filename: "negative-control-aws-waf-context-type.ts",
163
+ expectedCode: "TS2322",
164
+ description: "aws_waf context must be a string",
165
+ source: [
166
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
167
+ "",
168
+ "export const mustNotCompile: ProviderChallenge = {",
169
+ '\tkind: "aws_waf",',
170
+ '\tpageUrl: "https://example.com",',
171
+ "\tcontext: 123,",
172
+ "};",
173
+ "",
174
+ ].join("\n"),
175
+ },
176
+ {
177
+ filename: "negative-control-aws-waf-unknown-field.ts",
178
+ expectedCode: "TS2353",
179
+ description: "aws_waf rejects fields it does not declare",
180
+ source: [
181
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
182
+ "",
183
+ "export const mustNotCompile: ProviderChallenge = {",
184
+ '\tkind: "aws_waf",',
185
+ '\tpageUrl: "https://example.com",',
186
+ "\tunknownField: 1,",
187
+ "};",
188
+ "",
189
+ ].join("\n"),
190
+ },
191
+ {
192
+ filename: "negative-control-recaptcha-v3-action.ts",
193
+ expectedCode: "TS2322",
194
+ description: "recaptcha_v3 challenges require action",
195
+ source: [
196
+ 'import type { ProviderChallenge } from "@apifuse/provider-sdk";',
197
+ "",
198
+ "export const mustNotCompile: ProviderChallenge = {",
199
+ '\tkind: "recaptcha_v3",',
200
+ '\tsiteKey: "key",',
201
+ '\tpageUrl: "https://example.com",',
202
+ "};",
203
+ "",
204
+ ].join("\n"),
205
+ },
206
+ {
207
+ filename: "negative-control-browser-cookie-expires.ts",
208
+ expectedCode: "TS2322",
209
+ description: "BrowserCookie.expires remains optional for session cookies",
210
+ source: [
211
+ 'import type { BrowserCookie } from "@apifuse/provider-sdk";',
212
+ "",
213
+ "export function mustNotCompile(cookie: BrowserCookie): number {",
214
+ "\treturn cookie.expires;",
215
+ "}",
216
+ "",
217
+ ].join("\n"),
218
+ },
219
+ {
220
+ filename: "negative-control-resolver-runtime-identity.ts",
221
+ expectedCode: "TS2353",
222
+ description: "ResolverRuntimeOptions does not accept caller-synthesized identity",
223
+ source: [
224
+ 'import type { ResolverRuntimeOptions } from "@apifuse/provider-sdk";',
225
+ "",
226
+ "export const mustNotCompile: ResolverRuntimeOptions = {",
227
+ '\tidentity: "caller-controlled",',
228
+ "};",
229
+ "",
230
+ ].join("\n"),
231
+ },
232
+ {
233
+ filename: "negative-control-resolver-runtime-adapter-factories.ts",
234
+ expectedCode: "TS2353",
235
+ description: "ResolverRuntimeOptions does not accept caller-supplied adapter factories",
236
+ source: [
237
+ 'import type { ResolverRuntimeOptions } from "@apifuse/provider-sdk";',
238
+ "",
239
+ "export const mustNotCompile: ResolverRuntimeOptions = {",
240
+ "\tadapterFactories: {},",
241
+ "};",
242
+ "",
243
+ ].join("\n"),
244
+ },
245
+ {
246
+ filename: "negative-control-resolver-default-user-agent-test-seam.ts",
247
+ expectedCode: "TS2305",
248
+ description: "the resolver subpath does not expose its default user-agent test seam",
249
+ source: [
250
+ 'import { swapResolverDefaultUserAgentForTests } from "@apifuse/provider-sdk/runtime/resolver";',
251
+ "",
252
+ "export const mustNotCompile = swapResolverDefaultUserAgentForTests;",
253
+ "",
254
+ ].join("\n"),
255
+ },
256
+ {
257
+ filename: "negative-control-cache-reset-test-seam.ts",
258
+ expectedCode: "TS2305",
259
+ description: "the package root does not expose its cache-reset test seam",
260
+ source: [
261
+ 'import { resetProviderCacheForTests } from "@apifuse/provider-sdk";',
262
+ "",
263
+ "export const mustNotCompile = resetProviderCacheForTests;",
264
+ "",
265
+ ].join("\n"),
266
+ },
267
+ {
268
+ filename: "negative-control-resolver-runtime-allowed-hosts.ts",
269
+ expectedCode: "TS2322",
270
+ description: "ResolverRuntimeOptions.allowedHosts accepts only host strings",
271
+ source: [
272
+ 'import type { ResolverRuntimeOptions } from "@apifuse/provider-sdk";',
273
+ "",
274
+ "export const mustNotCompile: ResolverRuntimeOptions = {",
275
+ '\tallowedHosts: ["example.com", 42],',
276
+ "};",
277
+ "",
278
+ ].join("\n"),
279
+ },
280
+ {
281
+ filename: "negative-control-resolver-signal.ts",
282
+ expectedCode: "TS2345",
283
+ description: "ResolverContext.solve accepts only AbortSignal as its optional signal",
284
+ source: [
285
+ 'import type { ProviderChallenge, ResolverContext } from "@apifuse/provider-sdk";',
286
+ "",
287
+ "declare const resolver: ResolverContext;",
288
+ "declare const challenge: ProviderChallenge;",
289
+ "resolver.solve(challenge, { aborted: false });",
290
+ "",
291
+ ].join("\n"),
292
+ },
293
+ ] as const;
294
+
295
+ const tempRoot = mkdtempSync(join(tmpdir(), "apifuse-provider-sdk-pack-types-"));
296
+ const packDir = join(tempRoot, "pack");
297
+ const consumerDir = join(tempRoot, "consumer");
298
+
299
+ try {
300
+ mkdirSync(packDir, { recursive: true });
301
+ mkdirSync(consumerDir, { recursive: true });
302
+
303
+ const packed = packSdk(packDir);
304
+ const tarballPath = resolve(packDir, packed.filename);
305
+
306
+ runAreTheTypesWrong(tarballPath);
307
+ setUpFixtureConsumer(consumerDir, tarballPath);
308
+ run("bun", ["install"], consumerDir);
309
+ compileFixtureConsumer(consumerDir);
310
+ assertNegativeControlFails(consumerDir);
311
+ runNodeRuntimeImport(consumerDir);
312
+
313
+ console.log(`Packed artifact types OK under nodenext: ${tarballPath}`);
314
+ } finally {
315
+ if (KEEP_TEMP) {
316
+ console.log(`Keeping pack-types temp directory: ${tempRoot}`);
317
+ } else {
318
+ rmSync(tempRoot, { recursive: true, force: true });
319
+ }
320
+ }
321
+
322
+ function runAreTheTypesWrong(tarballPath: string): void {
323
+ // esm-only profile: this package publishes ESM only, so CJS-consumer
324
+ // resolution failures are expected and out of scope for this guard.
325
+ run(
326
+ "bun",
327
+ [join(sdkRoot, "node_modules", ".bin", "attw"), tarballPath, "--profile", "esm-only"],
328
+ sdkRoot,
329
+ );
330
+ }
331
+
332
+ function setUpFixtureConsumer(consumerDir: string, tarballPath: string): void {
333
+ writeFileSync(
334
+ join(consumerDir, "package.json"),
335
+ `${JSON.stringify(
336
+ {
337
+ private: true,
338
+ type: "module",
339
+ dependencies: {
340
+ "@apifuse/provider-sdk": `file:${tarballPath}`,
341
+ },
342
+ devDependencies: {
343
+ // Pinned to TS 5.x independently of the repo's own TypeScript 7
344
+ // toolchain: this must reflect what external provider polyrepos
345
+ // (e.g. apifuse-provider-tabelog) run in their CI.
346
+ typescript: "^5.9.3",
347
+ // skipLibCheck:false type-checks transitive deps too (ioredis
348
+ // references Buffer), so the fixture needs node types like any
349
+ // real provider repo.
350
+ "@types/node": "^25.9.3",
351
+ },
352
+ },
353
+ null,
354
+ 2,
355
+ )}\n`,
356
+ );
357
+
358
+ writeFileSync(
359
+ join(consumerDir, "tsconfig.json"),
360
+ `${JSON.stringify(
361
+ {
362
+ compilerOptions: {
363
+ target: "ES2022",
364
+ module: "nodenext",
365
+ moduleResolution: "nodenext",
366
+ strict: true,
367
+ // skipLibCheck must stay off: it is exactly what masked the
368
+ // extensionless-d.ts regression downstream.
369
+ skipLibCheck: false,
370
+ noEmit: true,
371
+ },
372
+ include: ["consumer.ts"],
373
+ },
374
+ null,
375
+ 2,
376
+ )}\n`,
377
+ );
378
+
379
+ writeFileSync(
380
+ join(consumerDir, "consumer.ts"),
381
+ [
382
+ 'import { defineProvider, ProviderError, resolveProxy, SessionExpiredError, z } from "@apifuse/provider-sdk";',
383
+ 'import { invalidateResolverSolution } from "@apifuse/provider-sdk/runtime/resolver";',
384
+ 'import type { BrowserCookie, ChallengeSolution, NativeNetworkClient, NativeNetworkConnection, NativeProviderConfig, NativeProviderContext, NativeTcpEgressGrant, ProviderChallenge, ProviderContext, ProviderFileRef, ProviderFilesContext, ProviderResolvedFile, ProviderResolverConfig, ResolverContext, ResolverRuntimeOptions } from "@apifuse/provider-sdk";',
385
+ 'import type { ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyVendorName, RequestOptions, ResolvedProxyConfig } from "@apifuse/provider-sdk";',
386
+ 'import { defineCredentialsAuth } from "@apifuse/provider-sdk/provider";',
387
+ 'import type { NativeNetworkClient as ProviderEntryNativeNetworkClient, ProviderFilesContext as ProviderEntryFilesContext } from "@apifuse/provider-sdk/provider";',
388
+ 'import { extractProviderContract } from "@apifuse/provider-sdk/contract";',
389
+ 'import { AUTH_TURN_SCHEMA } from "@apifuse/provider-sdk/auth-turn";',
390
+ 'import { serve } from "@apifuse/provider-sdk/server";',
391
+ 'import { resetProviderCacheForTests, runStandardTests } from "@apifuse/provider-sdk/testing";',
392
+ "",
393
+ "// ProviderError must keep its inherited Error members under nodenext.",
394
+ "// When dist d.ts imports fail to resolve, the class type degrades and",
395
+ "// name/message disappear (the tabelog false-error mode).",
396
+ 'const providerError = new ProviderError("boom");',
397
+ "const inheritedName: string = providerError.name;",
398
+ "const inheritedMessage: string = providerError.message;",
399
+ "const inheritedStack: string | undefined = providerError.stack;",
400
+ "const isError: Error = providerError;",
401
+ "const sessionExpired: ProviderError = new SessionExpiredError();",
402
+ "",
403
+ "// Re-exported zod must keep .refine() callback parameter inference.",
404
+ "const refined = z.object({ shopId: z.string() }).refine((value) => value.shopId.length > 0);",
405
+ 'const refinedString = z.string().refine((value) => value.startsWith("tabelog:"));',
406
+ 'const proxyOptions: ProxyResolutionOptions = { proxyPolicy: { mode: "disabled" } };',
407
+ 'const proxyProtocol: ProxyProtocol = "http";',
408
+ "const proxyResult: Promise<ResolvedProxyConfig> = resolveProxy(proxyOptions);",
409
+ 'const proxySource: ProxyResolutionSource = "smartproxy-allocator";',
410
+ 'const proxyVendor: ProxyVendorName = "smartproxy";',
411
+ 'const requestFile: ProviderFileRef = { type: "request_file", id: "photo", filename: "photo.jpg", mime_type: "image/jpeg", size: 4 };',
412
+ 'const resolvedFile: ProviderResolvedFile = { type: "request_file", id: requestFile.id, filename: requestFile.filename, size: requestFile.size, sha256: requestFile.sha256, mimeType: requestFile.mime_type, arrayBuffer: async () => new ArrayBuffer(0), bytes: async () => new Uint8Array(), stream: () => new ReadableStream<Uint8Array>() };',
413
+ "const files: ProviderFilesContext = { has: () => true, resolve: async () => resolvedFile };",
414
+ "const providerEntryFiles: ProviderEntryFilesContext = files;",
415
+ "const connection: NativeNetworkConnection = { read: async () => null, write: async () => {}, close: async () => {} };",
416
+ "const network: NativeNetworkClient = { connectTcp: async () => connection, connectTls: async () => connection, grantTcpEgress: () => ({ revoke() {} }) };",
417
+ "const providerEntryNetwork: ProviderEntryNativeNetworkClient = network;",
418
+ "const nativeContext: NativeProviderContext = { network };",
419
+ 'const grant: NativeTcpEgressGrant = network.grantTcpEgress({ sourceHost: "booking-loco.kakao.com", sourcePort: 443, host: "loco.kakao.com", port: 5228, tls: "disabled" });',
420
+ 'const nativeConfig: NativeProviderConfig = { network: { tcp: [{ host: "booking-loco.kakao.com", ports: [443], tls: "required" }] } };',
421
+ "const providerContext = undefined as unknown as ProviderContext;",
422
+ "const optionalFiles: ProviderFilesContext | undefined = providerContext.files;",
423
+ "const optionalNative: NativeProviderContext | undefined = providerContext.native;",
424
+ "export const providerResolver: ResolverContext = providerContext.resolver;",
425
+ 'export const resolverRuntimeOptions: ResolverRuntimeOptions = { allowedHosts: ["example.com"], cache: providerContext.cache };',
426
+ "",
427
+ 'export const turnstileChallenge: ProviderChallenge = { kind: "turnstile", siteKey: "key", pageUrl: "https://example.com" };',
428
+ "export const abortableResolverSolve = providerResolver.solve(turnstileChallenge, new AbortController().signal);",
429
+ 'export const recaptchaV2Challenge: ProviderChallenge = { kind: "recaptcha_v2", siteKey: "key", pageUrl: "https://example.com" };',
430
+ 'export const recaptchaV3Challenge: ProviderChallenge = { kind: "recaptcha_v3", siteKey: "key", pageUrl: "https://example.com", action: "login" };',
431
+ 'export const hcaptchaChallenge: ProviderChallenge = { kind: "hcaptcha", siteKey: "key", pageUrl: "https://example.com" };',
432
+ 'export const cloudflareInterstitialChallenge: ProviderChallenge = { kind: "cloudflare_interstitial", pageUrl: "https://example.com", blockedHtml: "<html></html>" };',
433
+ 'export const awsWafChallenge: ProviderChallenge = { kind: "aws_waf", pageUrl: "https://example.com", captchaScript: "script" };',
434
+ 'export const tokenSolution: ChallengeSolution = { form: "token", token: "solved-token" };',
435
+ 'export const cookieSolution: ChallengeSolution = { form: "cookies", cookies: { cf_clearance: "clearance" }, userAgent: "fixture-agent" };',
436
+ "export const invalidation = invalidateResolverSolution(providerContext.resolver, awsWafChallenge, cookieSolution);",
437
+ 'export const resolverConfig: ProviderResolverConfig = { vendors: ["browser", "capsolver"], kinds: ["cloudflare_interstitial", "turnstile"] };',
438
+ 'export const resolverProvider = defineProvider({ id: "pack-types-resolver", version: "1.0.0", runtime: "standard", resolver: resolverConfig, meta: { displayName: "Pack Types Resolver", descriptionKey: "meta.description", category: "test" }, operations: { probe: { input: z.object({}), output: z.object({ ok: z.boolean() }), handler: async () => ({ ok: true }), healthCheckUnsupported: { reason: "type fixture" } } } });',
439
+ "export const resolverContext: ResolverContext = { solve: async () => tokenSolution };",
440
+ 'export const browserCookie: BrowserCookie = { name: "persistent-id", value: "persistent-token", domain: "example.com", path: "/", expires: 1786698176, httpOnly: true, secure: true };',
441
+ 'const browserPage = undefined as unknown as Awaited<ReturnType<ProviderContext["browser"]["newPage"]>>;',
442
+ "export const browserCookies: Promise<readonly BrowserCookie[]> = browserPage.cookies();",
443
+ 'const queryCredentialOptions: RequestOptions = { sensitiveParams: { serviceKey: "type-test-key" } };',
444
+ "",
445
+ "export const witnesses = {",
446
+ " inheritedName,",
447
+ " inheritedMessage,",
448
+ " inheritedStack,",
449
+ " isError,",
450
+ " sessionExpired,",
451
+ " refined,",
452
+ " refinedString,",
453
+ " proxyResult,",
454
+ " proxyProtocol,",
455
+ " proxySource,",
456
+ " proxyVendor,",
457
+ " requestFile,",
458
+ " resolvedFile,",
459
+ " files,",
460
+ " providerEntryFiles,",
461
+ " connection,",
462
+ " network,",
463
+ " providerEntryNetwork,",
464
+ " nativeContext,",
465
+ " grant,",
466
+ " nativeConfig,",
467
+ " optionalFiles,",
468
+ " optionalNative,",
469
+ " browserCookie,",
470
+ " browserCookies,",
471
+ " queryCredentialOptions,",
472
+ " defineCredentialsAuth,",
473
+ " extractProviderContract,",
474
+ " AUTH_TURN_SCHEMA,",
475
+ " serve,",
476
+ " resetProviderCacheForTests,",
477
+ " runStandardTests,",
478
+ "};",
479
+ "",
480
+ ].join("\n"),
481
+ );
482
+
483
+ for (const negativeControl of NEGATIVE_CONTROLS) {
484
+ writeFileSync(join(consumerDir, negativeControl.filename), negativeControl.source);
485
+ }
486
+ }
487
+
488
+ function compileFixtureConsumer(consumerDir: string): void {
489
+ run(
490
+ "bun",
491
+ [join(consumerDir, "node_modules", ".bin", "tsc"), "-p", "tsconfig.json"],
492
+ consumerDir,
493
+ );
494
+ }
495
+
496
+ function assertNegativeControlFails(consumerDir: string): void {
497
+ for (const negativeControl of NEGATIVE_CONTROLS) {
498
+ const result = spawnSync(
499
+ "bun",
500
+ [
501
+ join(consumerDir, "node_modules", ".bin", "tsc"),
502
+ "--target",
503
+ "ES2022",
504
+ "--module",
505
+ "nodenext",
506
+ "--moduleResolution",
507
+ "nodenext",
508
+ "--strict",
509
+ "--noEmit",
510
+ negativeControl.filename,
511
+ ],
512
+ { cwd: consumerDir, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] },
513
+ );
514
+ if (result.status === 0) {
515
+ throw new Error(
516
+ 'Negative control "' +
517
+ negativeControl.description +
518
+ '" (' +
519
+ negativeControl.filename +
520
+ ") compiled cleanly: the fixture consumer is not detecting its error, so the guard proves nothing.",
521
+ );
522
+ }
523
+ const output = `${result.stdout}\n${result.stderr}`;
524
+ if (!output.includes(negativeControl.expectedCode)) {
525
+ throw new Error(
526
+ `Negative control "${negativeControl.description}" (${negativeControl.filename}) failed for an unexpected reason (wanted ${negativeControl.expectedCode}):\n${output}`,
527
+ );
528
+ }
529
+ }
530
+ }
531
+
532
+ function runNodeRuntimeImport(consumerDir: string): void {
533
+ // Node, not bun: bun resolves extensionless relative specifiers in
534
+ // published dist/*.js, node correctly refuses them (ERR_MODULE_NOT_FOUND).
535
+ run(
536
+ "node",
537
+ [
538
+ "--input-type=module",
539
+ "-e",
540
+ [
541
+ 'const sdk = await import("@apifuse/provider-sdk");',
542
+ 'const error = new sdk.ProviderError("boom");',
543
+ 'if (error.name !== "ProviderError" || error.message !== "boom" || !(error instanceof Error)) {',
544
+ ' throw new Error("ProviderError runtime shape is wrong: " + JSON.stringify({ name: error.name, message: error.message }));',
545
+ "}",
546
+ 'console.log("node ESM runtime import OK");',
547
+ ].join("\n"),
548
+ ],
549
+ consumerDir,
550
+ );
551
+ }
552
+
553
+ function packSdk(destination: string): { filename: string } {
554
+ const raw = execFileSync("npm", ["pack", "--json", "--pack-destination", destination], {
555
+ cwd: sdkRoot,
556
+ encoding: "utf8",
557
+ stdio: ["ignore", "pipe", "inherit"],
558
+ });
559
+ const parsed = PACK_RESULT_SCHEMA.parse(JSON.parse(raw));
560
+ const first = parsed[0];
561
+ if (!first) {
562
+ throw new Error("npm pack --json returned no package metadata.");
563
+ }
564
+ return first;
565
+ }
566
+
567
+ function run(command: string, args: string[], cwd: string): void {
568
+ const result = spawnSync(command, args, {
569
+ cwd,
570
+ env: process.env,
571
+ stdio: "inherit",
572
+ });
573
+
574
+ if (result.error) {
575
+ throw result.error;
576
+ }
577
+
578
+ if (result.status !== 0) {
579
+ throw new Error(
580
+ `Command failed (${[command, ...args].join(" ")}) in ${cwd} with exit code ${result.status}`,
581
+ );
582
+ }
583
+ }