@supatype/cli 0.1.7 → 0.1.10

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 (414) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +125 -122
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/LICENSE +202 -0
  5. package/deno.d.ts +1 -1
  6. package/dist/app/framework.js +1 -1
  7. package/dist/app/framework.js.map +1 -1
  8. package/dist/augmentation-generator.d.ts +1 -1
  9. package/dist/augmentation-generator.js +3 -3
  10. package/dist/augmentation-generator.js.map +1 -1
  11. package/dist/binary-cache.d.ts +30 -8
  12. package/dist/binary-cache.d.ts.map +1 -1
  13. package/dist/binary-cache.js +47 -35
  14. package/dist/binary-cache.js.map +1 -1
  15. package/dist/cache-pins.d.ts +1 -1
  16. package/dist/cache-pins.js +2 -2
  17. package/dist/cache-pins.js.map +1 -1
  18. package/dist/cli-artifacts.d.ts +32 -0
  19. package/dist/cli-artifacts.d.ts.map +1 -0
  20. package/dist/cli-artifacts.js +49 -0
  21. package/dist/cli-artifacts.js.map +1 -0
  22. package/dist/cli-install-method.d.ts +17 -1
  23. package/dist/cli-install-method.d.ts.map +1 -1
  24. package/dist/cli-install-method.js +32 -4
  25. package/dist/cli-install-method.js.map +1 -1
  26. package/dist/cli-package-version.d.ts +1 -1
  27. package/dist/cli-package-version.d.ts.map +1 -1
  28. package/dist/cli-package-version.js +6 -1
  29. package/dist/cli-package-version.js.map +1 -1
  30. package/dist/cli-standalone.d.ts +13 -4
  31. package/dist/cli-standalone.d.ts.map +1 -1
  32. package/dist/cli-standalone.js +86 -31
  33. package/dist/cli-standalone.js.map +1 -1
  34. package/dist/cli-version-embedded.d.ts +10 -0
  35. package/dist/cli-version-embedded.d.ts.map +1 -0
  36. package/dist/cli-version-embedded.js +13 -0
  37. package/dist/cli-version-embedded.js.map +1 -0
  38. package/dist/cli.js +1 -1
  39. package/dist/cli.js.map +1 -1
  40. package/dist/commands/add.js +4 -3
  41. package/dist/commands/add.js.map +1 -1
  42. package/dist/commands/admin.js +6 -6
  43. package/dist/commands/admin.js.map +1 -1
  44. package/dist/commands/adopt.js +1 -1
  45. package/dist/commands/adopt.js.map +1 -1
  46. package/dist/commands/app.js +2 -2
  47. package/dist/commands/app.js.map +1 -1
  48. package/dist/commands/cache.d.ts +1 -1
  49. package/dist/commands/cache.js +3 -3
  50. package/dist/commands/cache.js.map +1 -1
  51. package/dist/commands/db.d.ts +3 -3
  52. package/dist/commands/db.d.ts.map +1 -1
  53. package/dist/commands/db.js +12 -11
  54. package/dist/commands/db.js.map +1 -1
  55. package/dist/commands/deploy.d.ts +9 -9
  56. package/dist/commands/deploy.js +12 -12
  57. package/dist/commands/deploy.js.map +1 -1
  58. package/dist/commands/dev.d.ts +3 -3
  59. package/dist/commands/dev.js +17 -17
  60. package/dist/commands/dev.js.map +1 -1
  61. package/dist/commands/doctor.d.ts +1 -1
  62. package/dist/commands/doctor.js +3 -3
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/engine.d.ts +1 -1
  65. package/dist/commands/engine.js +1 -1
  66. package/dist/commands/functions.d.ts.map +1 -1
  67. package/dist/commands/functions.js +8 -7
  68. package/dist/commands/functions.js.map +1 -1
  69. package/dist/commands/hooks.d.ts +2 -2
  70. package/dist/commands/hooks.js +4 -4
  71. package/dist/commands/hooks.js.map +1 -1
  72. package/dist/commands/init.js +28 -28
  73. package/dist/commands/init.js.map +1 -1
  74. package/dist/commands/internal.d.ts.map +1 -1
  75. package/dist/commands/internal.js +37 -0
  76. package/dist/commands/internal.js.map +1 -1
  77. package/dist/commands/login.d.ts +1 -1
  78. package/dist/commands/login.js +1 -1
  79. package/dist/commands/login.js.map +1 -1
  80. package/dist/commands/logs.d.ts +1 -1
  81. package/dist/commands/migrate.js +5 -5
  82. package/dist/commands/migrate.js.map +1 -1
  83. package/dist/commands/pg.d.ts +1 -1
  84. package/dist/commands/pg.js +1 -1
  85. package/dist/commands/plugins.js +1 -1
  86. package/dist/commands/plugins.js.map +1 -1
  87. package/dist/commands/pull.js +2 -2
  88. package/dist/commands/pull.js.map +1 -1
  89. package/dist/commands/push.js +3 -3
  90. package/dist/commands/push.js.map +1 -1
  91. package/dist/commands/self-host.d.ts +1 -1
  92. package/dist/commands/self-host.js +1 -1
  93. package/dist/commands/self-update.d.ts +2 -8
  94. package/dist/commands/self-update.d.ts.map +1 -1
  95. package/dist/commands/self-update.js +20 -12
  96. package/dist/commands/self-update.js.map +1 -1
  97. package/dist/commands/status.d.ts +1 -1
  98. package/dist/commands/update.d.ts +1 -1
  99. package/dist/commands/update.js +1 -1
  100. package/dist/config.d.ts +23 -1
  101. package/dist/config.d.ts.map +1 -1
  102. package/dist/config.js +37 -18
  103. package/dist/config.js.map +1 -1
  104. package/dist/db-preflight.d.ts +4 -4
  105. package/dist/db-preflight.js +14 -14
  106. package/dist/db-preflight.js.map +1 -1
  107. package/dist/dev-compose.d.ts +3 -3
  108. package/dist/dev-compose.js +27 -27
  109. package/dist/dev-compose.js.map +1 -1
  110. package/dist/dev-log-filter.d.ts +1 -1
  111. package/dist/dev-log-filter.d.ts.map +1 -1
  112. package/dist/dev-log-filter.js +1 -1
  113. package/dist/dev-log-filter.js.map +1 -1
  114. package/dist/dev-ports.d.ts +2 -2
  115. package/dist/dev-ports.d.ts.map +1 -1
  116. package/dist/dev-ports.js +2 -2
  117. package/dist/dev-ports.js.map +1 -1
  118. package/dist/dev-session.d.ts +5 -5
  119. package/dist/dev-session.d.ts.map +1 -1
  120. package/dist/dev-session.js +6 -6
  121. package/dist/dev-session.js.map +1 -1
  122. package/dist/dev-shutdown.d.ts +5 -5
  123. package/dist/dev-shutdown.d.ts.map +1 -1
  124. package/dist/dev-shutdown.js +7 -7
  125. package/dist/dev-shutdown.js.map +1 -1
  126. package/dist/dev-task-colors.d.ts +1 -1
  127. package/dist/dev-task-colors.d.ts.map +1 -1
  128. package/dist/dev-task-colors.js +1 -1
  129. package/dist/dev-task-colors.js.map +1 -1
  130. package/dist/docker-postgres.d.ts +5 -5
  131. package/dist/docker-postgres.d.ts.map +1 -1
  132. package/dist/docker-postgres.js +5 -5
  133. package/dist/docker-postgres.js.map +1 -1
  134. package/dist/docker-runtime.d.ts +2 -2
  135. package/dist/docker-runtime.d.ts.map +1 -1
  136. package/dist/docker-runtime.js +5 -5
  137. package/dist/docker-runtime.js.map +1 -1
  138. package/dist/engine-client.d.ts +1 -1
  139. package/dist/engine-client.js +3 -3
  140. package/dist/engine-client.js.map +1 -1
  141. package/dist/engine-push-output.js +1 -1
  142. package/dist/engine-push-output.js.map +1 -1
  143. package/dist/ensure-binary.d.ts.map +1 -1
  144. package/dist/ensure-binary.js +17 -0
  145. package/dist/ensure-binary.js.map +1 -1
  146. package/dist/ensure-component-binaries.js +1 -1
  147. package/dist/ensure-component-binaries.js.map +1 -1
  148. package/dist/env-file.d.ts +2 -2
  149. package/dist/env-file.d.ts.map +1 -1
  150. package/dist/env-file.js +1 -1
  151. package/dist/env-file.js.map +1 -1
  152. package/dist/field-masking-tier.d.ts +5 -5
  153. package/dist/field-masking-tier.d.ts.map +1 -1
  154. package/dist/field-masking-tier.js +6 -6
  155. package/dist/field-masking-tier.js.map +1 -1
  156. package/dist/functions-deno-types.d.ts +1 -1
  157. package/dist/functions-deno-types.d.ts.map +1 -1
  158. package/dist/functions-deno-types.js +3 -3
  159. package/dist/functions-deno-types.js.map +1 -1
  160. package/dist/functions-router-gen.js +1 -1
  161. package/dist/gitignore.d.ts +2 -2
  162. package/dist/gitignore.d.ts.map +1 -1
  163. package/dist/gitignore.js +3 -3
  164. package/dist/gitignore.js.map +1 -1
  165. package/dist/hook-upload.d.ts +1 -1
  166. package/dist/hook-upload.js +3 -3
  167. package/dist/hooks-generator.d.ts +1 -1
  168. package/dist/hooks-generator.js +9 -9
  169. package/dist/index.d.ts +1 -1
  170. package/dist/index.js +1 -1
  171. package/dist/init-project-detect.d.ts +1 -1
  172. package/dist/init-project-detect.d.ts.map +1 -1
  173. package/dist/init-project-detect.js +1 -1
  174. package/dist/init-project-detect.js.map +1 -1
  175. package/dist/link.d.ts +1 -1
  176. package/dist/link.d.ts.map +1 -1
  177. package/dist/local-secrets.d.ts +5 -5
  178. package/dist/local-secrets.js +5 -5
  179. package/dist/main.d.ts +2 -0
  180. package/dist/main.d.ts.map +1 -0
  181. package/dist/main.js +20 -0
  182. package/dist/main.js.map +1 -0
  183. package/dist/model-hooks.d.ts +3 -3
  184. package/dist/model-hooks.js +4 -4
  185. package/dist/pgbouncer-userlist.d.ts +1 -1
  186. package/dist/pgbouncer-userlist.d.ts.map +1 -1
  187. package/dist/pgbouncer-userlist.js +2 -2
  188. package/dist/pgbouncer-userlist.js.map +1 -1
  189. package/dist/postgres-ctl.d.ts +1 -1
  190. package/dist/postgres-ctl.js +4 -4
  191. package/dist/postgres-ctl.js.map +1 -1
  192. package/dist/process-manager.d.ts +2 -2
  193. package/dist/process-manager.d.ts.map +1 -1
  194. package/dist/process-manager.js +4 -4
  195. package/dist/process-manager.js.map +1 -1
  196. package/dist/project-config.d.ts +12 -12
  197. package/dist/project-config.d.ts.map +1 -1
  198. package/dist/project-config.js +9 -9
  199. package/dist/project-config.js.map +1 -1
  200. package/dist/pull-utils.d.ts +2 -2
  201. package/dist/pull-utils.d.ts.map +1 -1
  202. package/dist/pull-utils.js +4 -4
  203. package/dist/pull-utils.js.map +1 -1
  204. package/dist/realtime-launch.js +1 -1
  205. package/dist/realtime-launch.js.map +1 -1
  206. package/dist/release-pins.d.ts +1 -1
  207. package/dist/release-pins.js +2 -2
  208. package/dist/release-pins.js.map +1 -1
  209. package/dist/resolve-api-url.d.ts.map +1 -1
  210. package/dist/resolve-api-url.js +4 -3
  211. package/dist/resolve-api-url.js.map +1 -1
  212. package/dist/resolve-target.d.ts +1 -1
  213. package/dist/resolve-target.d.ts.map +1 -1
  214. package/dist/rest-cache-admin.js +2 -2
  215. package/dist/rest-cache-admin.js.map +1 -1
  216. package/dist/runtime-routes.d.ts +1 -1
  217. package/dist/runtime-routes.js +1 -1
  218. package/dist/schema-ast-v2.d.ts +3 -3
  219. package/dist/schema-ast-v2.d.ts.map +1 -1
  220. package/dist/schema-ast-v2.js +2 -2
  221. package/dist/schema-ast-v2.js.map +1 -1
  222. package/dist/schema-push-lock.js +3 -3
  223. package/dist/schema-push-lock.js.map +1 -1
  224. package/dist/scripts/postinstall.d.ts +1 -1
  225. package/dist/scripts/postinstall.js +1 -1
  226. package/dist/self-host-compose.d.ts +5 -5
  227. package/dist/self-host-compose.d.ts.map +1 -1
  228. package/dist/self-host-compose.js +24 -24
  229. package/dist/self-host-compose.js.map +1 -1
  230. package/dist/service-role-check.js +3 -3
  231. package/dist/service-role-check.js.map +1 -1
  232. package/dist/storage-provision.d.ts +1 -1
  233. package/dist/storage-provision.js +3 -3
  234. package/dist/storage-provision.js.map +1 -1
  235. package/dist/studio-dev-server.d.ts +1 -1
  236. package/dist/studio-dev-server.d.ts.map +1 -1
  237. package/dist/systemd.d.ts +1 -1
  238. package/dist/systemd.js +1 -1
  239. package/dist/target-client.js +1 -1
  240. package/dist/target-client.js.map +1 -1
  241. package/dist/tsx-runner.d.ts +12 -0
  242. package/dist/tsx-runner.d.ts.map +1 -1
  243. package/dist/tsx-runner.js +36 -2
  244. package/dist/tsx-runner.js.map +1 -1
  245. package/dist/type-extractor.js +27 -27
  246. package/dist/type-extractor.js.map +1 -1
  247. package/dist/type-resolver.js +1 -1
  248. package/dist/type-resolver.js.map +1 -1
  249. package/dist/ui/brand.d.ts +1 -1
  250. package/dist/ui/brand.js +1 -1
  251. package/dist/ui/components/LogoWordmark.d.ts +1 -1
  252. package/dist/ui/components/LogoWordmark.d.ts.map +1 -1
  253. package/dist/ui/components/LogoWordmark.js +1 -1
  254. package/dist/ui/components/LogoWordmark.js.map +1 -1
  255. package/dist/ui/components/SelectField.js +1 -1
  256. package/dist/ui/components/SelectField.js.map +1 -1
  257. package/dist/ui/confirm.d.ts +1 -1
  258. package/dist/ui/confirm.js +1 -1
  259. package/dist/ui/fatal.d.ts +1 -1
  260. package/dist/ui/fatal.d.ts.map +1 -1
  261. package/dist/ui/fatal.js +1 -1
  262. package/dist/ui/fatal.js.map +1 -1
  263. package/dist/ui/flows/prompt-fields.js +1 -1
  264. package/dist/ui/flows/prompt-fields.js.map +1 -1
  265. package/dist/ui/interactive.d.ts +1 -1
  266. package/dist/ui/interactive.d.ts.map +1 -1
  267. package/dist/ui/interactive.js +1 -1
  268. package/dist/ui/interactive.js.map +1 -1
  269. package/dist/ui/progress.d.ts +1 -1
  270. package/dist/ui/progress.js +1 -1
  271. package/dist/ui/runtime/command-chrome.js +1 -1
  272. package/dist/ui/runtime/command-chrome.js.map +1 -1
  273. package/dist/ui/runtime/run-clack-flow.js +1 -1
  274. package/dist/ui/runtime/run-clack-flow.js.map +1 -1
  275. package/dist/ui/runtime/stdin-after-ink.js +1 -1
  276. package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
  277. package/dist/ui/theme.d.ts +1 -1
  278. package/dist/ui/theme.js +1 -1
  279. package/dist/valkey-sidecar.d.ts +1 -1
  280. package/dist/valkey-sidecar.d.ts.map +1 -1
  281. package/dist/valkey-sidecar.js +2 -2
  282. package/dist/valkey-sidecar.js.map +1 -1
  283. package/package.json +3 -2
  284. package/scripts/build-release-artifacts.sh +112 -0
  285. package/scripts/generate-homebrew-formula.mjs +47 -45
  286. package/scripts/mirror-deno-release.sh +1 -1
  287. package/src/TYPE-RESOLUTION.md +31 -31
  288. package/src/app/framework.ts +1 -1
  289. package/src/augmentation-generator.ts +3 -3
  290. package/src/binary-cache.ts +51 -36
  291. package/src/cache-pins.ts +2 -2
  292. package/src/cli-artifacts.ts +65 -0
  293. package/src/cli-install-method.ts +35 -4
  294. package/src/cli-package-version.ts +5 -1
  295. package/src/cli-standalone.ts +116 -34
  296. package/src/cli-version-embedded.ts +12 -0
  297. package/src/cli.ts +1 -1
  298. package/src/commands/add.ts +4 -3
  299. package/src/commands/admin.ts +6 -6
  300. package/src/commands/adopt.ts +1 -1
  301. package/src/commands/app.ts +2 -2
  302. package/src/commands/cache.ts +3 -3
  303. package/src/commands/db.ts +12 -11
  304. package/src/commands/deploy.ts +12 -12
  305. package/src/commands/dev.ts +19 -19
  306. package/src/commands/doctor.ts +3 -3
  307. package/src/commands/engine.ts +1 -1
  308. package/src/commands/functions.ts +8 -7
  309. package/src/commands/hooks.ts +6 -6
  310. package/src/commands/init.ts +28 -28
  311. package/src/commands/internal.ts +37 -0
  312. package/src/commands/login.ts +2 -2
  313. package/src/commands/logs.ts +1 -1
  314. package/src/commands/migrate.ts +5 -5
  315. package/src/commands/pg.ts +1 -1
  316. package/src/commands/plugins.ts +1 -1
  317. package/src/commands/pull.ts +2 -2
  318. package/src/commands/push.ts +3 -3
  319. package/src/commands/self-host.ts +1 -1
  320. package/src/commands/self-update.ts +23 -73
  321. package/src/commands/status.ts +1 -1
  322. package/src/commands/update.ts +1 -1
  323. package/src/config.ts +39 -18
  324. package/src/db-preflight.ts +15 -15
  325. package/src/dev-compose.ts +27 -27
  326. package/src/dev-log-filter.ts +1 -1
  327. package/src/dev-ports.ts +3 -3
  328. package/src/dev-session.ts +6 -6
  329. package/src/dev-shutdown.ts +8 -8
  330. package/src/dev-task-colors.ts +1 -1
  331. package/src/docker-postgres.ts +6 -6
  332. package/src/docker-runtime.ts +5 -5
  333. package/src/engine-client.ts +3 -3
  334. package/src/engine-push-output.ts +1 -1
  335. package/src/ensure-binary.ts +20 -0
  336. package/src/ensure-component-binaries.ts +1 -1
  337. package/src/env-file.ts +2 -2
  338. package/src/field-masking-tier.ts +6 -6
  339. package/src/functions-deno-types.ts +3 -3
  340. package/src/functions-router-gen.ts +1 -1
  341. package/src/gitignore.ts +3 -3
  342. package/src/hook-upload.ts +3 -3
  343. package/src/hooks-generator.ts +9 -9
  344. package/src/index.ts +1 -1
  345. package/src/init-project-detect.ts +1 -1
  346. package/src/link.ts +1 -1
  347. package/src/local-secrets.ts +5 -5
  348. package/src/main.ts +20 -0
  349. package/src/model-hooks.ts +4 -4
  350. package/src/pgbouncer-userlist.ts +2 -2
  351. package/src/postgres-ctl.ts +4 -4
  352. package/src/process-manager.ts +4 -4
  353. package/src/project-config.ts +16 -16
  354. package/src/pull-utils.ts +4 -4
  355. package/src/realtime-launch.ts +1 -1
  356. package/src/release-pins.ts +2 -2
  357. package/src/resolve-api-url.ts +4 -3
  358. package/src/resolve-target.ts +1 -1
  359. package/src/rest-cache-admin.ts +2 -2
  360. package/src/runtime-routes.ts +2 -2
  361. package/src/schema-ast-v2.ts +4 -4
  362. package/src/schema-push-lock.ts +3 -3
  363. package/src/scripts/postinstall.ts +1 -1
  364. package/src/self-host-compose.ts +25 -25
  365. package/src/service-role-check.ts +3 -3
  366. package/src/storage-provision.ts +3 -3
  367. package/src/studio-dev-server.ts +1 -1
  368. package/src/systemd.ts +1 -1
  369. package/src/target-client.ts +1 -1
  370. package/src/tsx-runner.ts +41 -2
  371. package/src/type-extractor.ts +27 -27
  372. package/src/type-resolver.ts +1 -1
  373. package/src/ui/README.md +1 -1
  374. package/src/ui/brand.ts +1 -1
  375. package/src/ui/components/LogoWordmark.tsx +1 -1
  376. package/src/ui/components/SelectField.tsx +1 -1
  377. package/src/ui/confirm.ts +1 -1
  378. package/src/ui/fatal.ts +1 -1
  379. package/src/ui/flows/prompt-fields.tsx +1 -1
  380. package/src/ui/interactive.ts +1 -1
  381. package/src/ui/progress.ts +1 -1
  382. package/src/ui/runtime/command-chrome.ts +1 -1
  383. package/src/ui/runtime/run-clack-flow.tsx +1 -1
  384. package/src/ui/runtime/stdin-after-ink.ts +1 -1
  385. package/src/ui/theme.ts +1 -1
  386. package/src/valkey-sidecar.ts +2 -2
  387. package/tests/access-composition.test.ts +6 -6
  388. package/tests/admin-studio-membership.test.ts +1 -1
  389. package/tests/api-schemas.test.ts +1 -1
  390. package/tests/archive-name-alias.test.ts +1 -1
  391. package/tests/cli-help.test.ts +8 -2
  392. package/tests/config-load-failure.test.ts +44 -0
  393. package/tests/db-preflight.test.ts +1 -1
  394. package/tests/doctor-render.test.ts +3 -3
  395. package/tests/doctor-service-role.test.ts +2 -2
  396. package/tests/engine-push-output.test.ts +1 -1
  397. package/tests/env-file.test.ts +3 -3
  398. package/tests/external-database-compose.test.ts +5 -5
  399. package/tests/external-database-config.test.ts +2 -2
  400. package/tests/field-masking-tier.test.ts +1 -1
  401. package/tests/homebrew-formula.test.ts +68 -26
  402. package/tests/hook-upload.test.ts +1 -1
  403. package/tests/hooks-generator.test.ts +1 -1
  404. package/tests/init.test.ts +2 -2
  405. package/tests/keys.test.ts +8 -2
  406. package/tests/local-secrets.test.ts +3 -3
  407. package/tests/model-hooks.test.ts +6 -6
  408. package/tests/runtime-contract.test.ts +2 -2
  409. package/tests/service-role-check.test.ts +3 -3
  410. package/tests/storage-provision.test.ts +1 -1
  411. package/tests/type-extractor.test.ts +2 -2
  412. package/tsconfig.tsbuildinfo +1 -1
  413. package/vitest.config.ts +7 -1
  414. package/scripts/build-release-bundle.mjs +0 -27
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Progress UI for one-shot commands Ink spinner inside command chrome.
2
+ * Progress UI for one-shot commands, Ink spinner inside command chrome.
3
3
  */
4
4
 
5
5
  import { getActiveFlowApi } from "./runtime/flow-session.js"
@@ -89,7 +89,7 @@ export function isCommandChromeActive(): boolean {
89
89
  return getActiveFlowApi() !== null
90
90
  }
91
91
 
92
- /** Commands that mount their own Ink UI do not wrap with command chrome. */
92
+ /** Commands that mount their own Ink UI, do not wrap with command chrome. */
93
93
  const WIZARD_COMMAND_PATHS = new Set(["dev", "init", "link", "login", "_postinstall"])
94
94
 
95
95
  /** Prefixes for subcommands that call `runClackFlow` internally. */
@@ -55,7 +55,7 @@ function teardownInk(instance: Instance): void {
55
55
  try {
56
56
  instance.clear()
57
57
  } catch {
58
- // ignore terminal may already be reset
58
+ // ignore: terminal may already be reset
59
59
  }
60
60
  instance.unmount()
61
61
  instance.cleanup()
@@ -10,7 +10,7 @@ export function restoreStdinAfterInk(): void {
10
10
  try {
11
11
  if (stdin.isRaw) stdin.setRawMode?.(false)
12
12
  } catch {
13
- // ignore stdin may already be restored
13
+ // ignore: stdin may already be restored
14
14
  }
15
15
 
16
16
  // Pause so one-shot Ink flows (cache list, keys, …) can exit; resume() would keep the
package/src/ui/theme.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Supatype terminal design tokens shared by Ink components and plain CI output.
2
+ * Supatype terminal design tokens, shared by Ink components and plain CI output.
3
3
  */
4
4
 
5
5
  export const RESET = "\x1b[0m"
@@ -100,7 +100,7 @@ export function ensureValkeySidecar(projectName: string): ValkeySidecarResult {
100
100
  sleepMs(100)
101
101
  }
102
102
 
103
- console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet cache may bypass initially.")
103
+ console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet, cache may bypass initially.")
104
104
  return { addr, containerName: name, started: true }
105
105
  }
106
106
 
@@ -109,7 +109,7 @@ export function stopValkeySidecar(containerName: string | null): void {
109
109
  spawnSync("docker", ["rm", "-f", containerName], { stdio: "ignore" })
110
110
  }
111
111
 
112
- /** @internal Test helper probe without subprocess. */
112
+ /** @internal Test helper: probe without subprocess. */
113
113
  export function probeTcp(host: string, port: number): Promise<boolean> {
114
114
  return new Promise((resolve) => {
115
115
  const s = createConnection({ host, port })
@@ -24,7 +24,7 @@ function access(model: ModelAstV2 | undefined): Record<string, unknown> {
24
24
  }
25
25
 
26
26
  // Without OR-composition the rule set is a closed list of single shapes, and the
27
- // commonest real requirement "an admin, or the owner" cannot be written at all.
27
+ // commonest real requirement: "an admin, or the owner", cannot be written at all.
28
28
  describe("Any<[…]>", () => {
29
29
  it("composes rules into an OR-join", () => {
30
30
  const post = extract(
@@ -81,7 +81,7 @@ export type Post = Model<{
81
81
  })
82
82
 
83
83
  // An empty list reads like a grant and compiles to a policy that grants
84
- // nothing exactly the silent denial the unknown-rule error exists to prevent.
84
+ // nothing: exactly the silent denial the unknown-rule error exists to prevent.
85
85
  it("rejects an empty list", () => {
86
86
  expect(() =>
87
87
  extract(
@@ -350,7 +350,7 @@ export type Post = Model<{ id: UUID }, { access: { read: In<"a", Rows<"a b; drop
350
350
  })
351
351
 
352
352
  // The plan's headline parameterisation: the type-level equivalent of Payload's
353
- // access-control factory. Before this, any named alias even unparameterised
353
+ // access-control factory. Before this, any named alias, even unparameterised,
354
354
  // was reported as an unknown rule and had to be written inline at every use.
355
355
  describe("parameterised rule aliases", () => {
356
356
  it("expands a generic alias at the point of use", () => {
@@ -480,7 +480,7 @@ export type Post = Model<{ id: UUID }, { access: { update: { using: Public; wat:
480
480
  })
481
481
 
482
482
 
483
- // "Publish at 09:00 next Tuesday" is *data* the row carries `published_at` and the
483
+ // "Publish at 09:00 next Tuesday" is *data*, the row carries `published_at` and the
484
484
  // rule is the same for every row. There is deliberately no literal-timestamp
485
485
  // operand; the policy re-evaluates per query, so the row starts matching at 09:00
486
486
  // with no cron and no publish worker.
@@ -589,7 +589,7 @@ export type Post = Model<{ id: UUID }, { access: { read: Gte<"a", Ago<${n}, "day
589
589
  `
590
590
  expect(() => extract(bad("0.5"), "ago-frac")).toThrow(/whole number/)
591
591
  // A negative literal is a prefix-unary expression, not a numeric literal, so it
592
- // needs its own branch otherwise the message misses the real advice.
592
+ // needs its own branch, otherwise the message misses the real advice.
593
593
  expect(() => extract(bad("-5"), "ago-neg")).toThrow(/does not take a negative amount/)
594
594
  })
595
595
 
@@ -619,7 +619,7 @@ export type Post = Model<{ id: UUID }, { access: { read: Gte<"a", StartOf<"fortn
619
619
  })
620
620
 
621
621
  // `In<>` asks "is this row's value in the set". Payload's site-access rule guards on
622
- // `user.sites?.length > 0` first without that, an editor with no sites still
622
+ // `user.sites?.length > 0` first, without that, an editor with no sites still
623
623
  // matches the unassigned-rows branch.
624
624
  describe("Exists<> non-empty guard", () => {
625
625
  it("expresses the Payload site-access rule in full", () => {
@@ -68,7 +68,7 @@ async function seedFirstAdmin(): Promise<Recorded[]> {
68
68
 
69
69
  // Capability checks refuse a role they do not recognise, so the CLI's set has to
70
70
  // match the server's (`studioRolePermissions`) and the control plane's
71
- // (`STUDIO_ROLE_PERMISSIONS`) exactly a role only this side knows about creates
71
+ // (`STUDIO_ROLE_PERMISSIONS`) exactly: a role only this side knows about creates
72
72
  // a user who is locked out of the panel they were made for.
73
73
  describe("STUDIO_ROLES", () => {
74
74
  it("matches the roles the servers understand", () => {
@@ -42,7 +42,7 @@ describe("apiSchemas", () => {
42
42
 
43
43
  it("leads with the managed schema when pg_schema moves", () => {
44
44
  // First entry is what PostgREST serves as the default profile, so the managed schema has to
45
- // lead otherwise unprefixed requests would resolve against `supatype`.
45
+ // lead: otherwise unprefixed requests would resolve against `supatype`.
46
46
  expect(apiSchemaList(project({ pg_schema: "app" }))).toBe(
47
47
  "app, supatype, graphql_public, auth",
48
48
  )
@@ -4,7 +4,7 @@ import { archiveNameCandidates } from "../src/binary-cache.js"
4
4
 
5
5
  /**
6
6
  * `supatype-postgres` published the Intel macOS archive as `darwin-x86_64` while the CLI asks for
7
- * `darwin-amd64` the spelling it derives from `process.arch === "x64"` on every platform. So
7
+ * `darwin-amd64`: the spelling it derives from `process.arch === "x64"` on every platform. So
8
8
  * `supatype dev` on an Intel Mac failed with "Checksum not found", and had done for as long as both
9
9
  * sides existed: CI could not run Docker on a macOS runner, so the path was never exercised.
10
10
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Subprocess tests spawn the compiled CLI binary and verify commands are
2
+ * Subprocess tests: spawn the compiled CLI binary and verify commands are
3
3
  * registered. Requires `pnpm build` to have run first (turbo handles this).
4
4
  */
5
5
  import { describe, it, expect } from "vitest"
@@ -17,8 +17,14 @@ const PACKAGE_VERSION = (
17
17
  function runCli(args: string[]): { stdout: string; stderr: string; exitCode: number } {
18
18
  const result = spawnSync(process.execPath, [CLI_BIN, ...args], {
19
19
  encoding: "utf8",
20
- timeout: 10_000,
20
+ timeout: 60_000,
21
21
  })
22
+ if (result.signal) {
23
+ throw new Error(
24
+ `CLI subprocess killed by ${result.signal} after the spawn timeout. `
25
+ + `Args: ${args.join(" ")}. This is usually machine contention, not a CLI fault.`,
26
+ )
27
+ }
22
28
  return {
23
29
  stdout: String(result.stdout ?? ""),
24
30
  stderr: String(result.stderr ?? ""),
@@ -0,0 +1,44 @@
1
+ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs"
2
+ import { join } from "node:path"
3
+ import { tmpdir } from "node:os"
4
+ import { spawnSync } from "node:child_process"
5
+ import { describe, expect, it } from "vitest"
6
+
7
+ const CLI = join(import.meta.dirname, "../bin/supatype.js")
8
+
9
+ function runIn(dir: string, args: string[]): { out: string; code: number } {
10
+ const r = spawnSync(process.execPath, [CLI, ...args], {
11
+ cwd: dir,
12
+ encoding: "utf8",
13
+ timeout: 60_000,
14
+ })
15
+ if (r.signal) throw new Error(`CLI killed by ${r.signal}, usually machine contention`)
16
+ return { out: `${r.stdout ?? ""}${r.stderr ?? ""}`, code: r.status ?? 1 }
17
+ }
18
+
19
+ describe("a config that cannot be read", () => {
20
+ // A broken config used to be indistinguishable from no config: the call sites that catch
21
+ // loadConfig so the CLI works outside a project swallowed both. That is why a standalone
22
+ // binary which could read no config at all still looked like it was working, for a whole
23
+ // release.
24
+ it("is reported, rather than treated as absent", () => {
25
+ const dir = mkdtempSync(join(tmpdir(), "supatype-broken-config-"))
26
+ writeFileSync(
27
+ join(dir, "supatype.config.ts"),
28
+ 'throw new Error("deliberately broken")\n',
29
+ "utf8",
30
+ )
31
+ const { out, code } = runIn(dir, ["db", "check"])
32
+ expect(out).toContain("Failed to load supatype.config.ts")
33
+ expect(out).not.toContain("No connection. Pass --connection")
34
+ expect(code).not.toBe(0)
35
+ })
36
+
37
+ it("does not stop the CLI working with no config at all", () => {
38
+ const dir = mkdtempSync(join(tmpdir(), "supatype-no-config-"))
39
+ mkdirSync(join(dir, "empty"), { recursive: true })
40
+ const { out } = runIn(join(dir, "empty"), ["db", "check"])
41
+ expect(out).toContain("No connection. Pass --connection")
42
+ expect(out).not.toContain("Failed to load")
43
+ })
44
+ })
@@ -44,7 +44,7 @@ describe("splitting remedies", () => {
44
44
 
45
45
  describe("the authenticator password guard", () => {
46
46
  // The credential is the operator's by decision. Executing the placeholder would create a role
47
- // with a password from our source code worse than refusing, and harder to notice.
47
+ // with a password from our source code, worse than refusing, and harder to notice.
48
48
  it("detects a remedy that would execute the placeholder", () => {
49
49
  const remedies = [
50
50
  result({ remedy: `CREATE ROLE authenticator LOGIN NOINHERIT PASSWORD '${PASSWORD_PLACEHOLDER}';` }),
@@ -5,7 +5,7 @@ import { printSection } from "../src/commands/doctor.js"
5
5
  * How a drift item reads to the operator.
6
6
  *
7
7
  * Items are keyed `table` + `name`, which for an index or constraint are different things and for a
8
- * *table* are the same so the natural `table.name` form printed "widget.widget". Tables only
8
+ * *table* are the same, so the natural `table.name` form printed "widget.widget". Tables only
9
9
  * started appearing in this report when the ownership gate got its reporting (E17), and a report an
10
10
  * operator distrusts is worse than no report.
11
11
  */
@@ -30,7 +30,7 @@ describe("printSection", () => {
30
30
  table: "widget",
31
31
  name: "widget",
32
32
  fields: [],
33
- message: "Unmanaged table widget push will not drop; manual decision required",
33
+ message: "Unmanaged table widget, push will not drop; manual decision required",
34
34
  },
35
35
  ])
36
36
  const text = captured.join("\n")
@@ -48,7 +48,7 @@ describe("printSection", () => {
48
48
  table: "widget",
49
49
  name: "widget_name_idx",
50
50
  fields: ["name"],
51
- message: "Unmanaged index widget_name_idx on widget push will not drop",
51
+ message: "Unmanaged index widget_name_idx on widget, push will not drop",
52
52
  },
53
53
  ])
54
54
  expect(captured.join("\n")).toContain("• widget.widget_name_idx (name)")
@@ -36,7 +36,7 @@ describe("printServiceRoleGrants", () => {
36
36
 
37
37
  it("marks a grant that matches no function", () => {
38
38
  printServiceRoleGrants(
39
- { ...empty, errors: [' "send-emial" no functions/send-emial/index.ts'], missing: ["send-emial"] },
39
+ { ...empty, errors: [' "send-emial", no functions/send-emial/index.ts'], missing: ["send-emial"] },
40
40
  ["send-emial", "audit"],
41
41
  )
42
42
  const out = lines.join("\n")
@@ -47,7 +47,7 @@ describe("printServiceRoleGrants", () => {
47
47
 
48
48
  it("passes a redundant-entry warning through", () => {
49
49
  printServiceRoleGrants(
50
- { ...empty, warnings: [' "hooks/x" is not needed a hook receives the key'] },
50
+ { ...empty, warnings: [' "hooks/x" is not needed, a hook receives the key'] },
51
51
  ["hooks/x"],
52
52
  )
53
53
  expect(lines.join("\n")).toContain("is not needed")
@@ -38,7 +38,7 @@ describe("formatEnginePushMessage()", () => {
38
38
  it("formats up_to_date with admin refresh", () => {
39
39
  expect(
40
40
  formatEnginePushMessage({ status: "up_to_date", operations: 0, admin_refreshed: true }),
41
- ).toBe("Schema up to date Studio metadata synced.")
41
+ ).toBe("Schema up to date, Studio metadata synced.")
42
42
  })
43
43
 
44
44
  it("formats up_to_date without admin refresh", () => {
@@ -10,7 +10,7 @@ import { MANAGED_MARKER, readEnvFile, upsertEnvFile } from "../src/env-file.js"
10
10
  * Two defects motivated this: the rewrite rebuilt the file from its assignments alone, so every
11
11
  * comment and blank line vanished; and the image keys derivable from `versions` were deleted
12
12
  * unconditionally, so `SUPATYPE_REALTIME_IMAGE` could be overridden from `.env` and
13
- * `SUPATYPE_SERVER_IMAGE` could not. Same file, same shape, different rules which is how an hour
13
+ * `SUPATYPE_SERVER_IMAGE` could not. Same file, same shape, different rules, which is how an hour
14
14
  * goes into wondering why a locally built image is ignored.
15
15
  */
16
16
  let dir: string
@@ -63,7 +63,7 @@ JWT_SECRET=abc
63
63
 
64
64
  it("does clean up a value it wrote itself", () => {
65
65
  // Otherwise removing a pin from config leaves a stale image reference that silently keeps
66
- // running the old version the reason the deletion existed at all.
66
+ // running the old version, the reason the deletion existed at all.
67
67
  upsertEnvFile(
68
68
  dir,
69
69
  { SUPATYPE_SERVER_IMAGE: "supatype/server:v1.2.3" },
@@ -112,7 +112,7 @@ JWT_SECRET=abc
112
112
  })
113
113
 
114
114
  it("does not treat a commented-out assignment as a value", () => {
115
- // `# FOO=bar` is a note, not a setting the old parser kept it as a key called "# FOO".
115
+ // `# FOO=bar` is a note, not a setting, the old parser kept it as a key called "# FOO".
116
116
  write("# FOO=bar\nREAL=1\n")
117
117
  upsertEnvFile(dir, { REAL: "2" })
118
118
  expect(read()).toContain("# FOO=bar")
@@ -30,7 +30,7 @@ const project = (database: unknown): SupatypeProjectConfig =>
30
30
  const external = (url = EXTERNAL_URL) => project({ external: { url } })
31
31
  const managed = () => project({ provider: "docker" })
32
32
 
33
- describe("external database compose", () => {
33
+ describe("external database: compose", () => {
34
34
  it("omits the db service and says why", () => {
35
35
  const compose = renderSelfHostCompose(external())
36
36
  expect(compose).not.toMatch(/^ {2}db:$/m)
@@ -88,12 +88,12 @@ describe("external database — compose", () => {
88
88
  it("appends GoTrue's search_path with the right separator", () => {
89
89
  // A URL that already has a query string needs `&`; a second `?` produces a DSN that fails to
90
90
  // parse, and GoTrue would exit rather than run its auth migrations.
91
- expect(renderSelfHostCompose(external())).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env required by database.external}?search_path=auth"')
91
+ expect(renderSelfHostCompose(external())).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}?search_path=auth"')
92
92
  expect(
93
93
  renderSelfHostCompose(
94
94
  external("postgres://owner:secret@db.example.com:5432/app?sslmode=require"),
95
95
  ),
96
- ).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env required by database.external}&search_path=auth"')
96
+ ).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}&search_path=auth"')
97
97
  })
98
98
 
99
99
  it("omits realtime entirely when the project turns it off", () => {
@@ -109,7 +109,7 @@ describe("external database — compose", () => {
109
109
  })
110
110
 
111
111
  it("keeps realtime when the flag is unset", () => {
112
- // Unset means "probe it", not "assume it is broken" the service reports its own capability.
112
+ // Unset means "probe it", not "assume it is broken", the service reports its own capability.
113
113
  const compose = renderSelfHostCompose(external())
114
114
  expect(compose).toMatch(/^ {2}realtime:$/m)
115
115
  expect(compose).toContain("SUPATYPE_REALTIME_URL: http://realtime:4000")
@@ -157,7 +157,7 @@ describe("external database — compose", () => {
157
157
 
158
158
  describe("a loopback external URL", () => {
159
159
  // Found by rehearsing a push against a real external Postgres: `db check` passed and `push`
160
- // applied the schema, because the CLI runs on the host then storage, realtime and the server all
160
+ // applied the schema, because the CLI runs on the host, then storage, realtime and the server all
161
161
  // died with ECONNREFUSED against their own loopback, because inside a container `127.0.0.1` is
162
162
  // that container. A retry loop would only have hidden it.
163
163
  it("is detected, whatever form it takes", () => {
@@ -28,7 +28,7 @@ const raw = (database: unknown, rest: Record<string, unknown> = {}): unknown =>
28
28
  const validate = (database: unknown, rest?: Record<string, unknown>) =>
29
29
  validateProjectConfig(raw(database, rest), "supatype.config.ts")
30
30
 
31
- describe("database.external accepted", () => {
31
+ describe("database.external: accepted", () => {
32
32
  it("accepts a url on its own, with no database.provider", () => {
33
33
  const cfg = validate({ external: { url: EXTERNAL_URL } })
34
34
  expect(externalDatabaseUrl(cfg)).toBe(EXTERNAL_URL)
@@ -52,7 +52,7 @@ describe("database.external — accepted", () => {
52
52
  })
53
53
  })
54
54
 
55
- describe("database.external rejected", () => {
55
+ describe("database.external: rejected", () => {
56
56
  it("rejects a missing url", () => {
57
57
  expect(() => validate({ external: {} })).toThrow(/database\.external\.url is required/)
58
58
  expect(() => validate({ external: { url: " " } })).toThrow(
@@ -20,7 +20,7 @@ import { apiSchemaList, validateProjectConfig, type SupatypeProjectConfig } from
20
20
  *
21
21
  * The rule is deliberately **not** "is the database external". A native `supatype dev` has no
22
22
  * extension either, and calling that tier 1 would point PostgREST at a schema whose tables the API
23
- * roles no longer hold privileges on every request denied.
23
+ * roles no longer hold privileges on, every request denied.
24
24
  */
25
25
  const project = (database: unknown, rest: Record<string, unknown> = {}): SupatypeProjectConfig =>
26
26
  validateProjectConfig(
@@ -1,4 +1,5 @@
1
1
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
2
+ import { createHash } from "node:crypto"
2
3
  import { join } from "node:path"
3
4
  import { tmpdir } from "node:os"
4
5
  import { spawnSync } from "node:child_process"
@@ -7,19 +8,36 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"
7
8
  let counter = 0
8
9
  let tmpDir: string
9
10
 
10
- const PLATFORMS = [
11
- "supatype-cli-darwin-arm64",
12
- "supatype-cli-darwin-amd64",
13
- "supatype-cli-linux-arm64",
14
- "supatype-cli-linux-amd64",
11
+ // The published artefacts: one archive per platform, plus the musl variants Homebrew does not
12
+ // use, since Homebrew on Linux is glibc.
13
+ const ARCHIVES = [
14
+ "supatype-cli-darwin-arm64.tar.gz",
15
+ "supatype-cli-darwin-amd64.tar.gz",
16
+ "supatype-cli-linux-arm64.tar.gz",
17
+ "supatype-cli-linux-amd64.tar.gz",
18
+ "supatype-cli-linux-amd64-musl.tar.gz",
19
+ "supatype-cli-windows-amd64.zip",
15
20
  ]
16
21
 
22
+ const script = () => join(import.meta.dirname, "../scripts/generate-homebrew-formula.mjs")
23
+
24
+ /** Write stub archives and the checksums manifest that build-release-artifacts.sh produces. */
25
+ function writeArtifacts(names: string[]): Record<string, string> {
26
+ const hashes: Record<string, string> = {}
27
+ const lines: string[] = []
28
+ for (const name of names) {
29
+ const body = `stub-${name}\n`
30
+ writeFileSync(join(tmpDir, name), body, "utf8")
31
+ hashes[name] = createHash("sha256").update(body).digest("hex")
32
+ lines.push(`${hashes[name]} ${name}`)
33
+ }
34
+ writeFileSync(join(tmpDir, "checksums.sha256"), lines.join("\n") + "\n", "utf8")
35
+ return hashes
36
+ }
37
+
17
38
  beforeEach(() => {
18
39
  tmpDir = join(tmpdir(), `homebrew-formula-${Date.now()}-${++counter}`)
19
40
  mkdirSync(tmpDir, { recursive: true })
20
- for (const name of PLATFORMS) {
21
- writeFileSync(join(tmpDir, name), `stub-${name}\n`, "utf8")
22
- }
23
41
  })
24
42
 
25
43
  afterEach(() => {
@@ -27,32 +45,56 @@ afterEach(() => {
27
45
  })
28
46
 
29
47
  describe("generate-homebrew-formula.mjs", () => {
30
- it("writes a Formula with versioned CDN URLs and sha256 blocks", () => {
48
+ it("points at the published archives, with the hashes from the manifest", () => {
49
+ const hashes = writeArtifacts(ARCHIVES)
31
50
  const outPath = join(tmpDir, "supatype.rb")
32
- const script = join(import.meta.dirname, "../scripts/generate-homebrew-formula.mjs")
33
- const result = spawnSync(
34
- process.execPath,
35
- [script, "9.9.9", tmpDir],
36
- {
37
- encoding: "utf8",
38
- env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
39
- },
40
- )
51
+ const result = spawnSync(process.execPath, [script(), "9.9.9", tmpDir], {
52
+ encoding: "utf8",
53
+ env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
54
+ })
41
55
 
42
56
  expect(result.status, result.stderr).toBe(0)
43
57
  const formula = readFileSync(outPath, "utf8")
58
+
44
59
  expect(formula).toContain('version "9.9.9"')
45
- expect(formula).toContain("https://releases.supatype.com/cli/v9.9.9/supatype-cli-darwin-arm64")
46
- expect(formula).toMatch(/sha256 "[a-f0-9]{64}"/)
60
+ expect(formula).toContain('license "Apache-2.0"')
61
+ expect(formula).toContain(
62
+ "https://releases.supatype.com/cli/v9.9.9/supatype-cli-darwin-arm64.tar.gz",
63
+ )
64
+ // The hash has to be the manifest's, not one the generator computed for itself: the manifest
65
+ // is the signed record of what was published.
66
+ expect(formula).toContain(`sha256 "${hashes["supatype-cli-darwin-arm64.tar.gz"]}"`)
67
+ // Every archive holds one executable called `supatype`, so there is no per-platform rename.
68
+ expect(formula).toContain('bin.install "supatype"')
47
69
  expect(formula).toContain('system bin/"supatype", "_postinstall"')
48
- expect(formula).toContain('bin.install "supatype-cli-#{arch}" => "supatype"')
49
70
  })
50
71
 
51
- it("fails when an artifact is missing", () => {
52
- rmSync(join(tmpDir, "supatype-cli-linux-amd64"))
53
- const script = join(import.meta.dirname, "../scripts/generate-homebrew-formula.mjs")
54
- const result = spawnSync(process.execPath, [script, "1.0.0", tmpDir], { encoding: "utf8" })
72
+ it("does not reference the musl or windows artefacts", () => {
73
+ writeArtifacts(ARCHIVES)
74
+ const outPath = join(tmpDir, "supatype.rb")
75
+ const result = spawnSync(process.execPath, [script(), "9.9.9", tmpDir], {
76
+ encoding: "utf8",
77
+ env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
78
+ })
79
+
80
+ expect(result.status, result.stderr).toBe(0)
81
+ const formula = readFileSync(outPath, "utf8")
82
+ expect(formula).not.toContain("musl")
83
+ expect(formula).not.toContain("windows")
84
+ })
85
+
86
+ it("fails when the manifest is missing, rather than hashing the files itself", () => {
87
+ writeArtifacts(ARCHIVES)
88
+ rmSync(join(tmpDir, "checksums.sha256"))
89
+ const result = spawnSync(process.execPath, [script(), "1.0.0", tmpDir], { encoding: "utf8" })
90
+ expect(result.status).not.toBe(0)
91
+ expect(result.stderr).toContain("checksums.sha256")
92
+ })
93
+
94
+ it("fails when the manifest omits a platform it needs", () => {
95
+ writeArtifacts(ARCHIVES.filter((n) => n !== "supatype-cli-linux-amd64.tar.gz"))
96
+ const result = spawnSync(process.execPath, [script(), "1.0.0", tmpDir], { encoding: "utf8" })
55
97
  expect(result.status).not.toBe(0)
56
- expect(result.stderr).toContain("Missing artifact")
98
+ expect(result.stderr).toContain("No checksum for supatype-cli-linux-amd64.tar.gz")
57
99
  })
58
100
  })
@@ -86,7 +86,7 @@ describe("readHookUpload", () => {
86
86
  })
87
87
 
88
88
  it("refuses a hook with a second file rather than dropping it", () => {
89
- // Silent truncation would deploy successfully and fail at import which reads to the caller as
89
+ // Silent truncation would deploy successfully and fail at import, which reads to the caller as
90
90
  // that table's writes being broken for no visible reason.
91
91
  const { cwd, hooks } = project()
92
92
  writeHook(hooks, "moderate-post", HANDLER, { "helpers.ts": "export const x = 1\n" })
@@ -71,7 +71,7 @@ export type Post = Model<{ id: UUID }, { tableName: "posts" }>
71
71
  describe("the generated module compiles", () => {
72
72
  /**
73
73
  * The generator emits TypeScript, so the only test that really proves it works is a compiler.
74
- * A missing brace or a type that does not resolve would otherwise reach a user's editor and this
74
+ * A missing brace or a type that does not resolve would otherwise reach a user's editor, and this
75
75
  * file is imported by their hook, so a broken emit breaks their function rather than our build.
76
76
  */
77
77
  it("typechecks under strict mode, together with a handler that uses it", () => {
@@ -329,7 +329,7 @@ describe("scaffold()", () => {
329
329
  expect(config).toContain('provider: "local"')
330
330
  expect(config).toContain("Production storage: external S3")
331
331
  const env = readFileSync(join(tmpRoot, ".env"), "utf8")
332
- expect(env).toContain("local development MinIO")
333
- expect(env).toContain("production external bucket")
332
+ expect(env).toContain("local development, MinIO")
333
+ expect(env).toContain("production, external bucket")
334
334
  })
335
335
  })
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tests for `supatype keys` JWT generation command.
2
+ * Tests for `supatype keys`, JWT generation command.
3
3
  * Uses subprocess tests (requires built dist/) for the CLI integration,
4
4
  * plus direct module tests for the signing logic.
5
5
  */
@@ -20,10 +20,16 @@ function runCli(
20
20
  ): { stdout: string; stderr: string; exitCode: number } {
21
21
  const result = spawnSync(process.execPath, [CLI_BIN, ...args], {
22
22
  encoding: "utf8",
23
- timeout: 10_000,
23
+ timeout: 60_000,
24
24
  cwd: opts.cwd,
25
25
  env: { ...process.env, ...opts.env },
26
26
  })
27
+ if (result.signal) {
28
+ throw new Error(
29
+ `CLI subprocess killed by ${result.signal} after the spawn timeout. `
30
+ + `Args: ${args.join(" ")}. This is usually machine contention, not a CLI fault.`,
31
+ )
32
+ }
27
33
  return {
28
34
  stdout: String(result.stdout ?? ""),
29
35
  stderr: String(result.stderr ?? ""),
@@ -14,7 +14,7 @@ import {
14
14
  import { upsertEnvFile } from "../src/env-file.js"
15
15
 
16
16
  // The bug these exist to prevent: `supatype dev` used to pin POSTGRES_PASSWORD and JWT_SECRET
17
- // to published constants in `.env` on every run the same `.env` a self-host deployment reads.
17
+ // to published constants in `.env` on every run, the same `.env` a self-host deployment reads.
18
18
  // A generated secret survived until the developer's next `dev`, then reverted silently, and the
19
19
  // deployment went out with a secret anyone can look up.
20
20
 
@@ -32,7 +32,7 @@ describe("resolving local secrets", () => {
32
32
  expect(devAuthenticatorPassword(dir)).toBe("auth-mine")
33
33
  })
34
34
 
35
- // A project with no `.env` still has to start, so the constants remain as fallbacks only.
35
+ // A project with no `.env` still has to start, so the constants remain, as fallbacks only.
36
36
  it("falls back when the project has none", () => {
37
37
  const dir = project()
38
38
  expect(devJwtSecret(dir)).toBe(FALLBACK_JWT_SECRET)
@@ -43,7 +43,7 @@ describe("resolving local secrets", () => {
43
43
 
44
44
  describe("the dev env write does not clobber secrets", () => {
45
45
  // This is the regression. `upsertEnvFile` replaces any key handed to it, so the guarantee has
46
- // to be that the dev path never hands it these asserted here at the level that matters:
46
+ // to be that the dev path never hands it these, asserted here at the level that matters:
47
47
  // write what dev writes, then check the secrets are byte-identical.
48
48
  it("leaves generated secrets untouched across repeated writes", () => {
49
49
  const dir = project(