@apifuse/provider-sdk 2.2.0-beta.1 → 2.2.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/AUTHORING.md +106 -0
  2. package/CHANGELOG.md +41 -0
  3. package/README.md +5 -1
  4. package/SUBMISSION.md +1 -1
  5. package/bin/apifuse-check.ts +44 -59
  6. package/bin/apifuse-create.ts +1 -1
  7. package/bin/apifuse-dev.ts +27 -52
  8. package/bin/apifuse-pack-check.ts +14 -0
  9. package/bin/apifuse-pack-smoke.ts +22 -81
  10. package/bin/apifuse-pack-types.ts +266 -0
  11. package/bin/apifuse-perf.ts +45 -127
  12. package/bin/apifuse-record.ts +53 -70
  13. package/bin/apifuse-submit-check.ts +510 -45
  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-semantics.ts +204 -0
  18. package/bin/submit-check-xml.ts +134 -0
  19. package/dist/auth-turn/index.d.ts +3 -3
  20. package/dist/auth.d.ts +2 -2
  21. package/dist/auth.js +9 -18
  22. package/dist/ceremonies/index.d.ts +1 -1
  23. package/dist/ceremonies/index.js +8 -18
  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/config/loader.d.ts +149 -8
  32. package/dist/config/loader.js +378 -89
  33. package/dist/contract-serialization.d.ts +2 -2
  34. package/dist/contract-serialization.js +3 -6
  35. package/dist/contract-types.d.ts +2 -2
  36. package/dist/contract.d.ts +3 -3
  37. package/dist/contract.js +4 -6
  38. package/dist/define.d.ts +8 -1
  39. package/dist/define.js +119 -122
  40. package/dist/dev.d.ts +1 -1
  41. package/dist/dev.js +1 -1
  42. package/dist/errors.d.ts +4 -1
  43. package/dist/errors.js +48 -0
  44. package/dist/i18n/catalog.d.ts +2 -2
  45. package/dist/i18n/catalog.js +4 -10
  46. package/dist/i18n/index.d.ts +2 -2
  47. package/dist/i18n/index.js +2 -2
  48. package/dist/i18n/keys.d.ts +2 -2
  49. package/dist/index.d.ts +44 -42
  50. package/dist/index.js +39 -37
  51. package/dist/lint.js +8 -15
  52. package/dist/provider.d.ts +11 -11
  53. package/dist/provider.js +9 -9
  54. package/dist/public-schema-field-lint.d.ts +1 -1
  55. package/dist/recipes/gov-api.js +1 -1
  56. package/dist/runtime/auth-flow.d.ts +1 -1
  57. package/dist/runtime/auth-flow.js +3 -3
  58. package/dist/runtime/browser.d.ts +1 -1
  59. package/dist/runtime/browser.js +15 -29
  60. package/dist/runtime/cache.d.ts +1 -1
  61. package/dist/runtime/cache.js +4 -8
  62. package/dist/runtime/choice.d.ts +1 -1
  63. package/dist/runtime/choice.js +31 -35
  64. package/dist/runtime/credential.d.ts +1 -1
  65. package/dist/runtime/credential.js +1 -1
  66. package/dist/runtime/env.d.ts +1 -1
  67. package/dist/runtime/executor.d.ts +1 -1
  68. package/dist/runtime/executor.js +15 -3
  69. package/dist/runtime/http.d.ts +2 -2
  70. package/dist/runtime/http.js +144 -348
  71. package/dist/runtime/insights.d.ts +1 -1
  72. package/dist/runtime/insights.js +6 -13
  73. package/dist/runtime/instrumentation.d.ts +2 -2
  74. package/dist/runtime/instrumentation.js +56 -19
  75. package/dist/runtime/keyring.js +1 -1
  76. package/dist/runtime/namespace.js +1 -1
  77. package/dist/runtime/otlp.d.ts +1 -1
  78. package/dist/runtime/perf.d.ts +1 -1
  79. package/dist/runtime/provider.d.ts +1 -1
  80. package/dist/runtime/provider.js +1 -2
  81. package/dist/runtime/proxy-errors.d.ts +1 -1
  82. package/dist/runtime/proxy-errors.js +9 -7
  83. package/dist/runtime/proxy-nodemaven.d.ts +35 -0
  84. package/dist/runtime/proxy-nodemaven.js +128 -0
  85. package/dist/runtime/proxy-retry-policy.d.ts +40 -0
  86. package/dist/runtime/proxy-retry-policy.js +326 -0
  87. package/dist/runtime/proxy-telemetry.d.ts +2 -1
  88. package/dist/runtime/proxy-telemetry.js +55 -52
  89. package/dist/runtime/redis.d.ts +1 -1
  90. package/dist/runtime/redis.js +2 -4
  91. package/dist/runtime/request-options.d.ts +1 -1
  92. package/dist/runtime/secrets.d.ts +27 -0
  93. package/dist/runtime/secrets.js +51 -0
  94. package/dist/runtime/state.d.ts +2 -2
  95. package/dist/runtime/state.js +15 -4
  96. package/dist/runtime/stealth.d.ts +2 -2
  97. package/dist/runtime/stealth.js +108 -212
  98. package/dist/runtime/stt.d.ts +1 -1
  99. package/dist/runtime/stt.js +11 -15
  100. package/dist/runtime/trace.d.ts +2 -2
  101. package/dist/runtime/trace.js +2 -4
  102. package/dist/runtime/waterfall.d.ts +1 -1
  103. package/dist/schema.d.ts +1 -1
  104. package/dist/schema.js +7 -15
  105. package/dist/serve.d.ts +1 -1
  106. package/dist/serve.js +1 -1
  107. package/dist/server/index.d.ts +7 -7
  108. package/dist/server/index.js +6 -6
  109. package/dist/server/self-test-redaction.d.ts +1 -1
  110. package/dist/server/self-test-redaction.js +1 -1
  111. package/dist/server/self-test.d.ts +104 -3
  112. package/dist/server/self-test.js +673 -115
  113. package/dist/server/serve.d.ts +105 -4
  114. package/dist/server/serve.js +588 -80
  115. package/dist/server/types.d.ts +10 -9
  116. package/dist/server/types.js +3 -7
  117. package/dist/stateful/errors.d.ts +14 -0
  118. package/dist/stateful/errors.js +14 -0
  119. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  120. package/dist/stateful/http-provider-event-emitter.js +237 -0
  121. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  122. package/dist/stateful/http-session-owner-registry.js +210 -0
  123. package/dist/stateful/index.d.ts +18 -0
  124. package/dist/stateful/index.js +18 -0
  125. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  126. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  127. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  128. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  129. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  130. package/dist/stateful/provider-event-pipeline.js +1 -0
  131. package/dist/stateful/provider-events.d.ts +101 -0
  132. package/dist/stateful/provider-events.js +289 -0
  133. package/dist/stateful/session-key.d.ts +15 -0
  134. package/dist/stateful/session-key.js +86 -0
  135. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  136. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  137. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  138. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  139. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  140. package/dist/stateful/stateful-provider-adapter.js +287 -0
  141. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  142. package/dist/stateful/stateful-provider-observability.js +161 -0
  143. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  144. package/dist/stateful/stateful-provider-owner-forwarder.js +207 -0
  145. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  146. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  147. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  148. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  149. package/dist/stateful/stateful-provider-session-routing.d.ts +71 -0
  150. package/dist/stateful/stateful-provider-session-routing.js +353 -0
  151. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  152. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  153. package/dist/stateful-signing.d.ts +18 -0
  154. package/dist/stateful-signing.js +27 -0
  155. package/dist/stealth/profiles.d.ts +1 -1
  156. package/dist/stealth/profiles.js +5 -14
  157. package/dist/stream.d.ts +1 -1
  158. package/dist/testing/index.d.ts +2 -2
  159. package/dist/testing/index.js +2 -2
  160. package/dist/testing/run.d.ts +1 -1
  161. package/dist/testing/run.js +7 -14
  162. package/dist/types.d.ts +87 -1
  163. package/dist/user-input.d.ts +30 -0
  164. package/dist/user-input.js +66 -0
  165. package/package.json +14 -5
  166. package/src/auth-turn/index.ts +1 -1
  167. package/src/auth.ts +28 -86
  168. package/src/ceremonies/index.ts +24 -78
  169. package/src/cli/commands.ts +10 -0
  170. package/src/cli/create.ts +42 -35
  171. package/src/cli/prompt-assets.ts +865 -0
  172. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  173. package/src/config/loader.ts +543 -208
  174. package/src/contract-serialization.ts +5 -11
  175. package/src/contract-types.ts +2 -2
  176. package/src/contract.ts +12 -28
  177. package/src/define.ts +247 -505
  178. package/src/dev.ts +4 -9
  179. package/src/errors.ts +58 -5
  180. package/src/i18n/catalog.ts +10 -32
  181. package/src/i18n/index.ts +2 -2
  182. package/src/i18n/keys.ts +5 -11
  183. package/src/index.ts +49 -42
  184. package/src/lint.ts +89 -159
  185. package/src/provider.ts +15 -11
  186. package/src/public-schema-field-lint.ts +7 -33
  187. package/src/recipes/gov-api.ts +2 -5
  188. package/src/runtime/auth-flow.ts +5 -7
  189. package/src/runtime/browser.ts +64 -187
  190. package/src/runtime/cache.ts +20 -67
  191. package/src/runtime/choice.ts +79 -132
  192. package/src/runtime/credential.ts +2 -2
  193. package/src/runtime/env.ts +1 -1
  194. package/src/runtime/executor.ts +23 -20
  195. package/src/runtime/http.ts +195 -559
  196. package/src/runtime/insights.ts +15 -53
  197. package/src/runtime/instrumentation.ts +78 -65
  198. package/src/runtime/keyring.ts +7 -19
  199. package/src/runtime/namespace.ts +2 -7
  200. package/src/runtime/otlp.ts +12 -23
  201. package/src/runtime/perf.ts +1 -1
  202. package/src/runtime/provider.ts +4 -9
  203. package/src/runtime/proxy-errors.ts +29 -42
  204. package/src/runtime/proxy-nodemaven.ts +178 -0
  205. package/src/runtime/proxy-retry-policy.ts +469 -0
  206. package/src/runtime/proxy-telemetry.ts +79 -77
  207. package/src/runtime/redis.ts +4 -12
  208. package/src/runtime/request-options.ts +4 -13
  209. package/src/runtime/secrets.ts +64 -0
  210. package/src/runtime/state.ts +41 -110
  211. package/src/runtime/stealth.ts +162 -377
  212. package/src/runtime/stt.ts +38 -94
  213. package/src/runtime/trace.ts +14 -44
  214. package/src/runtime/waterfall.ts +5 -18
  215. package/src/schema.ts +23 -84
  216. package/src/serve.ts +1 -1
  217. package/src/server/index.ts +24 -7
  218. package/src/server/self-test-redaction.ts +2 -2
  219. package/src/server/self-test.ts +857 -132
  220. package/src/server/serve.ts +859 -266
  221. package/src/server/types.ts +7 -19
  222. package/src/stateful/README.md +146 -0
  223. package/src/stateful/errors.ts +23 -0
  224. package/src/stateful/http-provider-event-emitter.ts +314 -0
  225. package/src/stateful/http-session-owner-registry.ts +306 -0
  226. package/src/stateful/index.ts +18 -0
  227. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  228. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  229. package/src/stateful/provider-event-pipeline.ts +61 -0
  230. package/src/stateful/provider-events.ts +462 -0
  231. package/src/stateful/session-key.ts +111 -0
  232. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  233. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  234. package/src/stateful/stateful-provider-adapter.ts +562 -0
  235. package/src/stateful/stateful-provider-observability.ts +261 -0
  236. package/src/stateful/stateful-provider-owner-forwarder.ts +279 -0
  237. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  238. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  239. package/src/stateful/stateful-provider-session-routing.ts +555 -0
  240. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  241. package/src/stateful-signing.ts +46 -0
  242. package/src/stealth/profiles.ts +10 -26
  243. package/src/stream.ts +8 -19
  244. package/src/testing/index.ts +2 -2
  245. package/src/testing/run.ts +19 -67
  246. package/src/types.ts +88 -1
  247. package/src/user-input.ts +118 -0
  248. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  249. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  250. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  251. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  252. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  253. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  254. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  255. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  256. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  257. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  258. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  259. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  260. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  261. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
@@ -1,19 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import {
4
- type ChildProcess,
5
- execFileSync,
6
- spawn,
7
- spawnSync,
8
- } from "node:child_process";
9
- import {
10
- existsSync,
11
- mkdirSync,
12
- mkdtempSync,
13
- readFileSync,
14
- rmSync,
15
- writeFileSync,
16
- } from "node:fs";
3
+ import { type ChildProcess, execFileSync, spawn, spawnSync } from "node:child_process";
4
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
17
5
  import { createServer } from "node:net";
18
6
  import { tmpdir } from "node:os";
19
7
  import { join, resolve } from "node:path";
@@ -41,9 +29,7 @@ const PING_RESPONSE_SCHEMA = z.object({
41
29
 
42
30
  const KEEP_TEMP = process.env.APIFUSE__PACK_SMOKE__KEEP_TEMP === "1";
43
31
 
44
- const tempRoot = mkdtempSync(
45
- join(tmpdir(), "apifuse-provider-sdk-pack-smoke-"),
46
- );
32
+ const tempRoot = mkdtempSync(join(tmpdir(), "apifuse-provider-sdk-pack-smoke-"));
47
33
  const packDir = join(tempRoot, "pack");
48
34
  const consumerDir = join(tempRoot, "consumer");
49
35
  const externalWorkspaceDir = join(tempRoot, "external-workspace");
@@ -81,15 +67,7 @@ try {
81
67
 
82
68
  run(
83
69
  "bun",
84
- [
85
- cliBin,
86
- "create",
87
- "dx-smoke",
88
- "--yes",
89
- "--json",
90
- "--sdk-specifier",
91
- tarballSpecifier,
92
- ],
70
+ [cliBin, "create", "dx-smoke", "--yes", "--json", "--sdk-specifier", tarballSpecifier],
93
71
  consumerDir,
94
72
  );
95
73
 
@@ -99,11 +77,7 @@ try {
99
77
  run("bun", ["run", "test"], generatedProviderDir);
100
78
  assertGeneratedReadme(generatedProviderDir);
101
79
  await smokeGeneratedDevServer(generatedProviderDir);
102
- assertExternalWorkspaceTopology(
103
- cliBin,
104
- externalWorkspaceDir,
105
- tarballSpecifier,
106
- );
80
+ assertExternalWorkspaceTopology(cliBin, externalWorkspaceDir, tarballSpecifier);
107
81
 
108
82
  console.log(
109
83
  `Provider SDK packed-artifact smoke passed: ${tarballPath} -> ${generatedProviderDir}`,
@@ -148,15 +122,8 @@ function assertExternalWorkspaceTopology(
148
122
  externalWorkspaceDir,
149
123
  );
150
124
 
151
- const generatedProviderDir = join(
152
- externalWorkspaceDir,
153
- "external-workspace-smoke",
154
- );
155
- const forbiddenProviderDir = join(
156
- externalWorkspaceDir,
157
- "providers",
158
- "external-workspace-smoke",
159
- );
125
+ const generatedProviderDir = join(externalWorkspaceDir, "external-workspace-smoke");
126
+ const forbiddenProviderDir = join(externalWorkspaceDir, "providers", "external-workspace-smoke");
160
127
  if (!existsSync(generatedProviderDir)) {
161
128
  throw new Error(
162
129
  "Public create must generate a one-provider repository at <name>/ even when providers/ exists.",
@@ -168,9 +135,7 @@ function assertExternalWorkspaceTopology(
168
135
  );
169
136
  }
170
137
 
171
- const packageJson = JSON.parse(
172
- readFileSync(join(generatedProviderDir, "package.json"), "utf8"),
173
- );
138
+ const packageJson = JSON.parse(readFileSync(join(generatedProviderDir, "package.json"), "utf8"));
174
139
  const sdkDependency = packageJson?.dependencies?.["@apifuse/provider-sdk"];
175
140
  if (sdkDependency !== tarballSpecifier) {
176
141
  throw new Error(
@@ -178,9 +143,7 @@ function assertExternalWorkspaceTopology(
178
143
  );
179
144
  }
180
145
  if (JSON.stringify(packageJson).includes("workspace:")) {
181
- throw new Error(
182
- "External bounty workspace scaffold must not contain workspace: dependencies.",
183
- );
146
+ throw new Error("External bounty workspace scaffold must not contain workspace: dependencies.");
184
147
  }
185
148
 
186
149
  run("bun", ["install"], generatedProviderDir);
@@ -199,30 +162,20 @@ function assertExternalWorkspaceTopology(
199
162
  },
200
163
  );
201
164
  if (monorepoAttempt.status === 0) {
202
- throw new Error(
203
- "--preset monorepo must reject outside the private APIFuse monorepo.",
204
- );
165
+ throw new Error("--preset monorepo must reject outside the private APIFuse monorepo.");
205
166
  }
206
167
  const rejectionOutput = `${monorepoAttempt.stdout}\n${monorepoAttempt.stderr}`;
207
- if (
208
- !rejectionOutput.includes(
209
- "Monorepo preset is internal to the APIFuse repository",
210
- )
211
- ) {
168
+ if (!rejectionOutput.includes("Monorepo preset is internal to the APIFuse repository")) {
212
169
  throw new Error(`Unexpected monorepo rejection output: ${rejectionOutput}`);
213
170
  }
214
171
  }
215
172
 
216
173
  function packSdk(destination: string): { filename: string } {
217
- const raw = execFileSync(
218
- "npm",
219
- ["pack", "--json", "--pack-destination", destination],
220
- {
221
- cwd: process.cwd(),
222
- encoding: "utf8",
223
- stdio: ["ignore", "pipe", "inherit"],
224
- },
225
- );
174
+ const raw = execFileSync("npm", ["pack", "--json", "--pack-destination", destination], {
175
+ cwd: process.cwd(),
176
+ encoding: "utf8",
177
+ stdio: ["ignore", "pipe", "inherit"],
178
+ });
226
179
  const parsed = PACK_RESULT_SCHEMA.parse(JSON.parse(raw));
227
180
  const first = parsed[0];
228
181
  if (!first) {
@@ -252,29 +205,19 @@ function run(command: string, args: string[], cwd: string): void {
252
205
  function assertGeneratedReadme(providerDir: string): void {
253
206
  const readme = readFileSync(join(providerDir, "README.md"), "utf8");
254
207
  if (!readme.includes('"requestId":"req_local_ping"')) {
255
- throw new Error(
256
- "Generated README is missing requestId in local smoke docs.",
257
- );
208
+ throw new Error("Generated README is missing requestId in local smoke docs.");
258
209
  }
259
210
  if (readme.includes('"connection":null')) {
260
- throw new Error(
261
- "Generated README must not document connection:null for no-auth local smoke.",
262
- );
211
+ throw new Error("Generated README must not document connection:null for no-auth local smoke.");
263
212
  }
264
213
  if (!readme.includes("bunx playwright install chromium")) {
265
- throw new Error(
266
- "Generated README is missing browser runtime troubleshooting guidance.",
267
- );
214
+ throw new Error("Generated README is missing browser runtime troubleshooting guidance.");
268
215
  }
269
216
  if (!readme.includes("impit")) {
270
- throw new Error(
271
- "Generated README is missing impit stealth runtime guidance.",
272
- );
217
+ throw new Error("Generated README is missing impit stealth runtime guidance.");
273
218
  }
274
219
  if (!readme.includes("bun run submit-check")) {
275
- throw new Error(
276
- "Generated README must document the submit-check pre-submission workflow.",
277
- );
220
+ throw new Error("Generated README must document the submit-check pre-submission workflow.");
278
221
  }
279
222
  if (!readme.includes("bun run record -- --operation <operation>")) {
280
223
  throw new Error(
@@ -368,9 +311,7 @@ async function waitForHttp(
368
311
 
369
312
  while (Date.now() < deadline) {
370
313
  if (server.exitCode !== null) {
371
- throw new Error(
372
- `Dev server exited early with code ${server.exitCode}\n${getOutput()}`,
373
- );
314
+ throw new Error(`Dev server exited early with code ${server.exitCode}\n${getOutput()}`);
374
315
  }
375
316
 
376
317
  try {
@@ -0,0 +1,266 @@
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
+ // A deliberate negative control proves 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 tempRoot = mkdtempSync(join(tmpdir(), "apifuse-provider-sdk-pack-types-"));
40
+ const packDir = join(tempRoot, "pack");
41
+ const consumerDir = join(tempRoot, "consumer");
42
+
43
+ try {
44
+ mkdirSync(packDir, { recursive: true });
45
+ mkdirSync(consumerDir, { recursive: true });
46
+
47
+ const packed = packSdk(packDir);
48
+ const tarballPath = resolve(packDir, packed.filename);
49
+
50
+ runAreTheTypesWrong(tarballPath);
51
+ setUpFixtureConsumer(consumerDir, tarballPath);
52
+ run("bun", ["install"], consumerDir);
53
+ compileFixtureConsumer(consumerDir);
54
+ assertNegativeControlFails(consumerDir);
55
+ runNodeRuntimeImport(consumerDir);
56
+
57
+ console.log(`Packed artifact types OK under nodenext: ${tarballPath}`);
58
+ } finally {
59
+ if (KEEP_TEMP) {
60
+ console.log(`Keeping pack-types temp directory: ${tempRoot}`);
61
+ } else {
62
+ rmSync(tempRoot, { recursive: true, force: true });
63
+ }
64
+ }
65
+
66
+ function runAreTheTypesWrong(tarballPath: string): void {
67
+ // esm-only profile: this package publishes ESM only, so CJS-consumer
68
+ // resolution failures are expected and out of scope for this guard.
69
+ run(
70
+ "bun",
71
+ [join(sdkRoot, "node_modules", ".bin", "attw"), tarballPath, "--profile", "esm-only"],
72
+ sdkRoot,
73
+ );
74
+ }
75
+
76
+ function setUpFixtureConsumer(consumerDir: string, tarballPath: string): void {
77
+ writeFileSync(
78
+ join(consumerDir, "package.json"),
79
+ `${JSON.stringify(
80
+ {
81
+ private: true,
82
+ type: "module",
83
+ dependencies: {
84
+ "@apifuse/provider-sdk": `file:${tarballPath}`,
85
+ },
86
+ devDependencies: {
87
+ // Pinned to TS 5.x independently of the repo's own TypeScript 7
88
+ // toolchain: this must reflect what external provider polyrepos
89
+ // (e.g. apifuse-provider-tabelog) run in their CI.
90
+ typescript: "^5.9.3",
91
+ // skipLibCheck:false type-checks transitive deps too (ioredis
92
+ // references Buffer), so the fixture needs node types like any
93
+ // real provider repo.
94
+ "@types/node": "^25.9.3",
95
+ },
96
+ },
97
+ null,
98
+ 2,
99
+ )}\n`,
100
+ );
101
+
102
+ writeFileSync(
103
+ join(consumerDir, "tsconfig.json"),
104
+ `${JSON.stringify(
105
+ {
106
+ compilerOptions: {
107
+ target: "ES2022",
108
+ module: "nodenext",
109
+ moduleResolution: "nodenext",
110
+ strict: true,
111
+ // skipLibCheck must stay off: it is exactly what masked the
112
+ // extensionless-d.ts regression downstream.
113
+ skipLibCheck: false,
114
+ noEmit: true,
115
+ },
116
+ include: ["consumer.ts"],
117
+ },
118
+ null,
119
+ 2,
120
+ )}\n`,
121
+ );
122
+
123
+ writeFileSync(
124
+ join(consumerDir, "consumer.ts"),
125
+ [
126
+ 'import { ProviderError, SessionExpiredError, z } from "@apifuse/provider-sdk";',
127
+ 'import { defineCredentialsAuth } from "@apifuse/provider-sdk/provider";',
128
+ 'import { extractProviderContract } from "@apifuse/provider-sdk/contract";',
129
+ 'import { AUTH_TURN_SCHEMA } from "@apifuse/provider-sdk/auth-turn";',
130
+ 'import { serve } from "@apifuse/provider-sdk/server";',
131
+ 'import { runStandardTests } from "@apifuse/provider-sdk/testing";',
132
+ "",
133
+ "// ProviderError must keep its inherited Error members under nodenext.",
134
+ "// When dist d.ts imports fail to resolve, the class type degrades and",
135
+ "// name/message disappear (the tabelog false-error mode).",
136
+ 'const providerError = new ProviderError("boom");',
137
+ "const inheritedName: string = providerError.name;",
138
+ "const inheritedMessage: string = providerError.message;",
139
+ "const inheritedStack: string | undefined = providerError.stack;",
140
+ "const isError: Error = providerError;",
141
+ "const sessionExpired: ProviderError = new SessionExpiredError();",
142
+ "",
143
+ "// Re-exported zod must keep .refine() callback parameter inference.",
144
+ "const refined = z.object({ shopId: z.string() }).refine((value) => value.shopId.length > 0);",
145
+ 'const refinedString = z.string().refine((value) => value.startsWith("tabelog:"));',
146
+ "",
147
+ "export const witnesses = {",
148
+ " inheritedName,",
149
+ " inheritedMessage,",
150
+ " inheritedStack,",
151
+ " isError,",
152
+ " sessionExpired,",
153
+ " refined,",
154
+ " refinedString,",
155
+ " defineCredentialsAuth,",
156
+ " extractProviderContract,",
157
+ " AUTH_TURN_SCHEMA,",
158
+ " serve,",
159
+ " runStandardTests,",
160
+ "};",
161
+ "",
162
+ ].join("\n"),
163
+ );
164
+
165
+ writeFileSync(
166
+ join(consumerDir, "negative-control.ts"),
167
+ [
168
+ 'import { ProviderError } from "@apifuse/provider-sdk";',
169
+ "",
170
+ "// Intentionally wrong: name is a string. If this file compiles, the",
171
+ "// fixture consumer is not actually type-checking and the guard is void.",
172
+ 'export const mustNotCompile: number = new ProviderError("boom").name;',
173
+ "",
174
+ ].join("\n"),
175
+ );
176
+ }
177
+
178
+ function compileFixtureConsumer(consumerDir: string): void {
179
+ run(
180
+ "bun",
181
+ [join(consumerDir, "node_modules", ".bin", "tsc"), "-p", "tsconfig.json"],
182
+ consumerDir,
183
+ );
184
+ }
185
+
186
+ function assertNegativeControlFails(consumerDir: string): void {
187
+ const result = spawnSync(
188
+ "bun",
189
+ [
190
+ join(consumerDir, "node_modules", ".bin", "tsc"),
191
+ "--target",
192
+ "ES2022",
193
+ "--module",
194
+ "nodenext",
195
+ "--moduleResolution",
196
+ "nodenext",
197
+ "--strict",
198
+ "--noEmit",
199
+ "negative-control.ts",
200
+ ],
201
+ { cwd: consumerDir, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] },
202
+ );
203
+ if (result.status === 0) {
204
+ throw new Error(
205
+ "Negative control compiled cleanly: the fixture consumer is not detecting type errors, so the nodenext guard proves nothing.",
206
+ );
207
+ }
208
+ if (!`${result.stdout}\n${result.stderr}`.includes("TS2322")) {
209
+ throw new Error(
210
+ `Negative control failed for an unexpected reason (wanted TS2322):\n${result.stdout}\n${result.stderr}`,
211
+ );
212
+ }
213
+ }
214
+
215
+ function runNodeRuntimeImport(consumerDir: string): void {
216
+ // Node, not bun: bun resolves extensionless relative specifiers in
217
+ // published dist/*.js, node correctly refuses them (ERR_MODULE_NOT_FOUND).
218
+ run(
219
+ "node",
220
+ [
221
+ "--input-type=module",
222
+ "-e",
223
+ [
224
+ 'const sdk = await import("@apifuse/provider-sdk");',
225
+ 'const error = new sdk.ProviderError("boom");',
226
+ 'if (error.name !== "ProviderError" || error.message !== "boom" || !(error instanceof Error)) {',
227
+ ' throw new Error("ProviderError runtime shape is wrong: " + JSON.stringify({ name: error.name, message: error.message }));',
228
+ "}",
229
+ 'console.log("node ESM runtime import OK");',
230
+ ].join("\n"),
231
+ ],
232
+ consumerDir,
233
+ );
234
+ }
235
+
236
+ function packSdk(destination: string): { filename: string } {
237
+ const raw = execFileSync("npm", ["pack", "--json", "--pack-destination", destination], {
238
+ cwd: sdkRoot,
239
+ encoding: "utf8",
240
+ stdio: ["ignore", "pipe", "inherit"],
241
+ });
242
+ const parsed = PACK_RESULT_SCHEMA.parse(JSON.parse(raw));
243
+ const first = parsed[0];
244
+ if (!first) {
245
+ throw new Error("npm pack --json returned no package metadata.");
246
+ }
247
+ return first;
248
+ }
249
+
250
+ function run(command: string, args: string[], cwd: string): void {
251
+ const result = spawnSync(command, args, {
252
+ cwd,
253
+ env: process.env,
254
+ stdio: "inherit",
255
+ });
256
+
257
+ if (result.error) {
258
+ throw result.error;
259
+ }
260
+
261
+ if (result.status !== 0) {
262
+ throw new Error(
263
+ `Command failed (${[command, ...args].join(" ")}) in ${cwd} with exit code ${result.status}`,
264
+ );
265
+ }
266
+ }