@supatype/cli 0.1.6 → 0.1.9

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 (477) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +152 -102
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/LICENSE +202 -0
  5. package/deno.d.ts +52 -0
  6. package/dist/app/framework.js +1 -1
  7. package/dist/app/framework.js.map +1 -1
  8. package/dist/augmentation-generator.d.ts +22 -0
  9. package/dist/augmentation-generator.d.ts.map +1 -1
  10. package/dist/augmentation-generator.js +19 -5
  11. package/dist/augmentation-generator.js.map +1 -1
  12. package/dist/binary-cache.d.ts +42 -6
  13. package/dist/binary-cache.d.ts.map +1 -1
  14. package/dist/binary-cache.js +76 -44
  15. package/dist/binary-cache.js.map +1 -1
  16. package/dist/cache-clean.d.ts +15 -0
  17. package/dist/cache-clean.d.ts.map +1 -0
  18. package/dist/cache-clean.js +76 -0
  19. package/dist/cache-clean.js.map +1 -0
  20. package/dist/cache-pins.d.ts +51 -0
  21. package/dist/cache-pins.d.ts.map +1 -0
  22. package/dist/cache-pins.js +184 -0
  23. package/dist/cache-pins.js.map +1 -0
  24. package/dist/cli-artifacts.d.ts +32 -0
  25. package/dist/cli-artifacts.d.ts.map +1 -0
  26. package/dist/cli-artifacts.js +49 -0
  27. package/dist/cli-artifacts.js.map +1 -0
  28. package/dist/cli-install-method.d.ts +27 -0
  29. package/dist/cli-install-method.d.ts.map +1 -0
  30. package/dist/cli-install-method.js +78 -0
  31. package/dist/cli-install-method.js.map +1 -0
  32. package/dist/cli-package-version.d.ts +1 -1
  33. package/dist/cli-package-version.d.ts.map +1 -1
  34. package/dist/cli-package-version.js +6 -1
  35. package/dist/cli-package-version.js.map +1 -1
  36. package/dist/cli-standalone.d.ts +13 -4
  37. package/dist/cli-standalone.d.ts.map +1 -1
  38. package/dist/cli-standalone.js +86 -31
  39. package/dist/cli-standalone.js.map +1 -1
  40. package/dist/cli-version-embedded.d.ts +10 -0
  41. package/dist/cli-version-embedded.d.ts.map +1 -0
  42. package/dist/cli-version-embedded.js +13 -0
  43. package/dist/cli-version-embedded.js.map +1 -0
  44. package/dist/cli.d.ts.map +1 -1
  45. package/dist/cli.js +7 -1
  46. package/dist/cli.js.map +1 -1
  47. package/dist/cloud-credentials.d.ts +34 -0
  48. package/dist/cloud-credentials.d.ts.map +1 -0
  49. package/dist/cloud-credentials.js +139 -0
  50. package/dist/cloud-credentials.js.map +1 -0
  51. package/dist/commands/add.js +1 -1
  52. package/dist/commands/add.js.map +1 -1
  53. package/dist/commands/admin.d.ts +11 -0
  54. package/dist/commands/admin.d.ts.map +1 -1
  55. package/dist/commands/admin.js +123 -21
  56. package/dist/commands/admin.js.map +1 -1
  57. package/dist/commands/adopt.js +1 -1
  58. package/dist/commands/adopt.js.map +1 -1
  59. package/dist/commands/app.js +2 -2
  60. package/dist/commands/app.js.map +1 -1
  61. package/dist/commands/cache.d.ts +1 -1
  62. package/dist/commands/cache.d.ts.map +1 -1
  63. package/dist/commands/cache.js +69 -73
  64. package/dist/commands/cache.js.map +1 -1
  65. package/dist/commands/cloud.d.ts.map +1 -1
  66. package/dist/commands/cloud.js +32 -8
  67. package/dist/commands/cloud.js.map +1 -1
  68. package/dist/commands/db.d.ts +3 -2
  69. package/dist/commands/db.d.ts.map +1 -1
  70. package/dist/commands/db.js +149 -3
  71. package/dist/commands/db.js.map +1 -1
  72. package/dist/commands/deploy.d.ts +9 -9
  73. package/dist/commands/deploy.js +12 -12
  74. package/dist/commands/deploy.js.map +1 -1
  75. package/dist/commands/dev.d.ts +3 -3
  76. package/dist/commands/dev.d.ts.map +1 -1
  77. package/dist/commands/dev.js +63 -23
  78. package/dist/commands/dev.js.map +1 -1
  79. package/dist/commands/doctor.d.ts +28 -0
  80. package/dist/commands/doctor.d.ts.map +1 -1
  81. package/dist/commands/doctor.js +60 -3
  82. package/dist/commands/doctor.js.map +1 -1
  83. package/dist/commands/engine.d.ts +1 -1
  84. package/dist/commands/engine.js +1 -1
  85. package/dist/commands/functions.d.ts +7 -0
  86. package/dist/commands/functions.d.ts.map +1 -1
  87. package/dist/commands/functions.js +45 -11
  88. package/dist/commands/functions.js.map +1 -1
  89. package/dist/commands/generate.d.ts.map +1 -1
  90. package/dist/commands/generate.js +5 -1
  91. package/dist/commands/generate.js.map +1 -1
  92. package/dist/commands/hooks.d.ts +12 -0
  93. package/dist/commands/hooks.d.ts.map +1 -0
  94. package/dist/commands/hooks.js +118 -0
  95. package/dist/commands/hooks.js.map +1 -0
  96. package/dist/commands/init.d.ts.map +1 -1
  97. package/dist/commands/init.js +64 -30
  98. package/dist/commands/init.js.map +1 -1
  99. package/dist/commands/internal.d.ts +6 -0
  100. package/dist/commands/internal.d.ts.map +1 -0
  101. package/dist/commands/internal.js +22 -0
  102. package/dist/commands/internal.js.map +1 -0
  103. package/dist/commands/link-helpers.d.ts.map +1 -1
  104. package/dist/commands/link-helpers.js +8 -2
  105. package/dist/commands/link-helpers.js.map +1 -1
  106. package/dist/commands/login.d.ts +7 -0
  107. package/dist/commands/login.d.ts.map +1 -0
  108. package/dist/commands/login.js +110 -0
  109. package/dist/commands/login.js.map +1 -0
  110. package/dist/commands/logs.d.ts +1 -1
  111. package/dist/commands/migrate.js +5 -5
  112. package/dist/commands/migrate.js.map +1 -1
  113. package/dist/commands/pg.d.ts +1 -1
  114. package/dist/commands/pg.js +1 -1
  115. package/dist/commands/plugins.js +1 -1
  116. package/dist/commands/plugins.js.map +1 -1
  117. package/dist/commands/pull.js +2 -2
  118. package/dist/commands/pull.js.map +1 -1
  119. package/dist/commands/push.d.ts.map +1 -1
  120. package/dist/commands/push.js +110 -7
  121. package/dist/commands/push.js.map +1 -1
  122. package/dist/commands/self-host.d.ts +1 -1
  123. package/dist/commands/self-host.js +1 -1
  124. package/dist/commands/self-update.d.ts +3 -2
  125. package/dist/commands/self-update.d.ts.map +1 -1
  126. package/dist/commands/self-update.js +31 -16
  127. package/dist/commands/self-update.js.map +1 -1
  128. package/dist/commands/status.d.ts +1 -1
  129. package/dist/commands/update.d.ts +1 -1
  130. package/dist/commands/update.js +1 -1
  131. package/dist/config.d.ts +1 -1
  132. package/dist/config.d.ts.map +1 -1
  133. package/dist/config.js +19 -4
  134. package/dist/config.js.map +1 -1
  135. package/dist/db-preflight.d.ts +78 -0
  136. package/dist/db-preflight.d.ts.map +1 -0
  137. package/dist/db-preflight.js +452 -0
  138. package/dist/db-preflight.js.map +1 -0
  139. package/dist/dev-compose.d.ts +4 -4
  140. package/dist/dev-compose.d.ts.map +1 -1
  141. package/dist/dev-compose.js +143 -88
  142. package/dist/dev-compose.js.map +1 -1
  143. package/dist/dev-log-filter.d.ts +1 -1
  144. package/dist/dev-log-filter.d.ts.map +1 -1
  145. package/dist/dev-log-filter.js +1 -1
  146. package/dist/dev-log-filter.js.map +1 -1
  147. package/dist/dev-ports.d.ts +2 -2
  148. package/dist/dev-ports.d.ts.map +1 -1
  149. package/dist/dev-ports.js +2 -2
  150. package/dist/dev-ports.js.map +1 -1
  151. package/dist/dev-session.d.ts +5 -5
  152. package/dist/dev-session.d.ts.map +1 -1
  153. package/dist/dev-session.js +6 -6
  154. package/dist/dev-session.js.map +1 -1
  155. package/dist/dev-shutdown.d.ts +5 -5
  156. package/dist/dev-shutdown.d.ts.map +1 -1
  157. package/dist/dev-shutdown.js +7 -7
  158. package/dist/dev-shutdown.js.map +1 -1
  159. package/dist/dev-task-colors.d.ts +1 -1
  160. package/dist/dev-task-colors.d.ts.map +1 -1
  161. package/dist/dev-task-colors.js +1 -1
  162. package/dist/dev-task-colors.js.map +1 -1
  163. package/dist/docker-postgres.d.ts +5 -5
  164. package/dist/docker-postgres.d.ts.map +1 -1
  165. package/dist/docker-postgres.js +5 -5
  166. package/dist/docker-postgres.js.map +1 -1
  167. package/dist/docker-runtime.d.ts +2 -2
  168. package/dist/docker-runtime.d.ts.map +1 -1
  169. package/dist/docker-runtime.js +5 -5
  170. package/dist/docker-runtime.js.map +1 -1
  171. package/dist/engine-client.d.ts +1 -1
  172. package/dist/engine-client.js +3 -3
  173. package/dist/engine-client.js.map +1 -1
  174. package/dist/engine-push-output.js +1 -1
  175. package/dist/engine-push-output.js.map +1 -1
  176. package/dist/ensure-binary.d.ts.map +1 -1
  177. package/dist/ensure-binary.js +17 -0
  178. package/dist/ensure-binary.js.map +1 -1
  179. package/dist/ensure-component-binaries.js +1 -1
  180. package/dist/ensure-component-binaries.js.map +1 -1
  181. package/dist/env-file.d.ts +40 -2
  182. package/dist/env-file.d.ts.map +1 -1
  183. package/dist/env-file.js +132 -11
  184. package/dist/env-file.js.map +1 -1
  185. package/dist/field-masking-tier.d.ts +50 -0
  186. package/dist/field-masking-tier.d.ts.map +1 -0
  187. package/dist/field-masking-tier.js +91 -0
  188. package/dist/field-masking-tier.js.map +1 -0
  189. package/dist/functions-deno-types.d.ts +24 -0
  190. package/dist/functions-deno-types.d.ts.map +1 -0
  191. package/dist/functions-deno-types.js +155 -0
  192. package/dist/functions-deno-types.js.map +1 -0
  193. package/dist/functions-router-gen.js +1 -1
  194. package/dist/gitignore.d.ts +2 -2
  195. package/dist/gitignore.d.ts.map +1 -1
  196. package/dist/gitignore.js +3 -3
  197. package/dist/gitignore.js.map +1 -1
  198. package/dist/hook-upload.d.ts +30 -0
  199. package/dist/hook-upload.d.ts.map +1 -0
  200. package/dist/hook-upload.js +86 -0
  201. package/dist/hook-upload.js.map +1 -0
  202. package/dist/hooks-generator.d.ts +8 -0
  203. package/dist/hooks-generator.d.ts.map +1 -0
  204. package/dist/hooks-generator.js +332 -0
  205. package/dist/hooks-generator.js.map +1 -0
  206. package/dist/index.d.ts +1 -1
  207. package/dist/index.js +1 -1
  208. package/dist/init-project-detect.d.ts +1 -1
  209. package/dist/init-project-detect.d.ts.map +1 -1
  210. package/dist/init-project-detect.js +1 -1
  211. package/dist/init-project-detect.js.map +1 -1
  212. package/dist/link.d.ts +4 -0
  213. package/dist/link.d.ts.map +1 -1
  214. package/dist/link.js +2 -0
  215. package/dist/link.js.map +1 -1
  216. package/dist/local-secrets.d.ts +71 -0
  217. package/dist/local-secrets.d.ts.map +1 -0
  218. package/dist/local-secrets.js +100 -0
  219. package/dist/local-secrets.js.map +1 -0
  220. package/dist/main.d.ts +2 -0
  221. package/dist/main.d.ts.map +1 -0
  222. package/dist/main.js +20 -0
  223. package/dist/main.js.map +1 -0
  224. package/dist/model-hooks.d.ts +73 -0
  225. package/dist/model-hooks.d.ts.map +1 -0
  226. package/dist/model-hooks.js +211 -0
  227. package/dist/model-hooks.js.map +1 -0
  228. package/dist/pgbouncer-userlist.d.ts +1 -1
  229. package/dist/pgbouncer-userlist.d.ts.map +1 -1
  230. package/dist/pgbouncer-userlist.js +2 -2
  231. package/dist/pgbouncer-userlist.js.map +1 -1
  232. package/dist/postgres-ctl.d.ts +12 -1
  233. package/dist/postgres-ctl.d.ts.map +1 -1
  234. package/dist/postgres-ctl.js +28 -5
  235. package/dist/postgres-ctl.js.map +1 -1
  236. package/dist/process-manager.d.ts +2 -2
  237. package/dist/process-manager.d.ts.map +1 -1
  238. package/dist/process-manager.js +4 -4
  239. package/dist/process-manager.js.map +1 -1
  240. package/dist/project-config.d.ts +122 -2
  241. package/dist/project-config.d.ts.map +1 -1
  242. package/dist/project-config.js +150 -1
  243. package/dist/project-config.js.map +1 -1
  244. package/dist/pull-utils.d.ts +2 -2
  245. package/dist/pull-utils.d.ts.map +1 -1
  246. package/dist/pull-utils.js +4 -4
  247. package/dist/pull-utils.js.map +1 -1
  248. package/dist/realtime-launch.js +1 -1
  249. package/dist/realtime-launch.js.map +1 -1
  250. package/dist/release-pins.d.ts +1 -1
  251. package/dist/release-pins.js +2 -2
  252. package/dist/release-pins.js.map +1 -1
  253. package/dist/resolve-api-url.js +1 -1
  254. package/dist/resolve-api-url.js.map +1 -1
  255. package/dist/resolve-target.d.ts +4 -0
  256. package/dist/resolve-target.d.ts.map +1 -1
  257. package/dist/resolve-target.js +69 -73
  258. package/dist/resolve-target.js.map +1 -1
  259. package/dist/rest-cache-admin.js +2 -2
  260. package/dist/rest-cache-admin.js.map +1 -1
  261. package/dist/runtime-routes.d.ts +1 -1
  262. package/dist/runtime-routes.js +1 -1
  263. package/dist/schema-ast-v2.d.ts +5 -4
  264. package/dist/schema-ast-v2.d.ts.map +1 -1
  265. package/dist/schema-ast-v2.js +5 -3
  266. package/dist/schema-ast-v2.js.map +1 -1
  267. package/dist/schema-push-lock.d.ts.map +1 -1
  268. package/dist/schema-push-lock.js +43 -16
  269. package/dist/schema-push-lock.js.map +1 -1
  270. package/dist/scripts/postinstall.d.ts +1 -1
  271. package/dist/scripts/postinstall.js +1 -1
  272. package/dist/self-host-compose.d.ts +26 -2
  273. package/dist/self-host-compose.d.ts.map +1 -1
  274. package/dist/self-host-compose.js +305 -73
  275. package/dist/self-host-compose.js.map +1 -1
  276. package/dist/service-role-check.d.ts +21 -0
  277. package/dist/service-role-check.d.ts.map +1 -0
  278. package/dist/service-role-check.js +85 -0
  279. package/dist/service-role-check.js.map +1 -0
  280. package/dist/storage-provision.d.ts +1 -1
  281. package/dist/storage-provision.js +3 -3
  282. package/dist/storage-provision.js.map +1 -1
  283. package/dist/studio-dev-server.d.ts +1 -1
  284. package/dist/studio-dev-server.d.ts.map +1 -1
  285. package/dist/systemd.d.ts +1 -1
  286. package/dist/systemd.js +1 -1
  287. package/dist/target-client.d.ts +17 -0
  288. package/dist/target-client.d.ts.map +1 -1
  289. package/dist/target-client.js +69 -17
  290. package/dist/target-client.js.map +1 -1
  291. package/dist/tsx-runner.js +1 -1
  292. package/dist/tsx-runner.js.map +1 -1
  293. package/dist/type-extractor.d.ts.map +1 -1
  294. package/dist/type-extractor.js +738 -34
  295. package/dist/type-extractor.js.map +1 -1
  296. package/dist/type-resolver.js +1 -1
  297. package/dist/type-resolver.js.map +1 -1
  298. package/dist/ui/brand.d.ts +1 -1
  299. package/dist/ui/brand.js +1 -1
  300. package/dist/ui/components/LogoWordmark.d.ts +1 -1
  301. package/dist/ui/components/LogoWordmark.d.ts.map +1 -1
  302. package/dist/ui/components/LogoWordmark.js +1 -1
  303. package/dist/ui/components/LogoWordmark.js.map +1 -1
  304. package/dist/ui/components/SelectField.js +1 -1
  305. package/dist/ui/components/SelectField.js.map +1 -1
  306. package/dist/ui/confirm.d.ts +1 -1
  307. package/dist/ui/confirm.js +1 -1
  308. package/dist/ui/fatal.d.ts +1 -1
  309. package/dist/ui/fatal.d.ts.map +1 -1
  310. package/dist/ui/fatal.js +1 -1
  311. package/dist/ui/fatal.js.map +1 -1
  312. package/dist/ui/flows/prompt-fields.js +1 -1
  313. package/dist/ui/flows/prompt-fields.js.map +1 -1
  314. package/dist/ui/interactive.d.ts +1 -1
  315. package/dist/ui/interactive.d.ts.map +1 -1
  316. package/dist/ui/interactive.js +1 -1
  317. package/dist/ui/interactive.js.map +1 -1
  318. package/dist/ui/progress.d.ts +1 -1
  319. package/dist/ui/progress.js +1 -1
  320. package/dist/ui/runtime/command-chrome.js +2 -2
  321. package/dist/ui/runtime/command-chrome.js.map +1 -1
  322. package/dist/ui/runtime/run-clack-flow.js +1 -1
  323. package/dist/ui/runtime/run-clack-flow.js.map +1 -1
  324. package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -1
  325. package/dist/ui/runtime/stdin-after-ink.js +4 -2
  326. package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
  327. package/dist/ui/theme.d.ts +1 -1
  328. package/dist/ui/theme.js +1 -1
  329. package/dist/valkey-sidecar.d.ts +1 -1
  330. package/dist/valkey-sidecar.d.ts.map +1 -1
  331. package/dist/valkey-sidecar.js +2 -2
  332. package/dist/valkey-sidecar.js.map +1 -1
  333. package/package.json +6 -2
  334. package/scripts/build-release-artifacts.sh +112 -0
  335. package/scripts/generate-homebrew-formula.mjs +123 -0
  336. package/scripts/mirror-deno-release.sh +1 -1
  337. package/src/TYPE-RESOLUTION.md +31 -31
  338. package/src/app/framework.ts +1 -1
  339. package/src/augmentation-generator.ts +19 -6
  340. package/src/binary-cache.ts +94 -47
  341. package/src/cache-clean.ts +81 -0
  342. package/src/cache-pins.ts +243 -0
  343. package/src/cli-artifacts.ts +65 -0
  344. package/src/cli-install-method.ts +87 -0
  345. package/src/cli-package-version.ts +5 -1
  346. package/src/cli-standalone.ts +116 -34
  347. package/src/cli-version-embedded.ts +12 -0
  348. package/src/cli.ts +7 -1
  349. package/src/cloud-credentials.ts +183 -0
  350. package/src/commands/add.ts +1 -1
  351. package/src/commands/admin.ts +142 -27
  352. package/src/commands/adopt.ts +1 -1
  353. package/src/commands/app.ts +2 -2
  354. package/src/commands/cache.ts +92 -77
  355. package/src/commands/cloud.ts +32 -8
  356. package/src/commands/db.ts +164 -3
  357. package/src/commands/deploy.ts +12 -12
  358. package/src/commands/dev.ts +72 -23
  359. package/src/commands/doctor.ts +69 -3
  360. package/src/commands/engine.ts +1 -1
  361. package/src/commands/functions.ts +47 -10
  362. package/src/commands/generate.ts +5 -1
  363. package/src/commands/hooks.ts +138 -0
  364. package/src/commands/init.ts +65 -31
  365. package/src/commands/internal.ts +23 -0
  366. package/src/commands/link-helpers.ts +9 -2
  367. package/src/commands/login.ts +127 -0
  368. package/src/commands/logs.ts +1 -1
  369. package/src/commands/migrate.ts +5 -5
  370. package/src/commands/pg.ts +1 -1
  371. package/src/commands/plugins.ts +1 -1
  372. package/src/commands/pull.ts +2 -2
  373. package/src/commands/push.ts +124 -7
  374. package/src/commands/self-host.ts +1 -1
  375. package/src/commands/self-update.ts +41 -19
  376. package/src/commands/status.ts +1 -1
  377. package/src/commands/update.ts +1 -1
  378. package/src/config.ts +23 -4
  379. package/src/db-preflight.ts +575 -0
  380. package/src/dev-compose.ts +158 -89
  381. package/src/dev-log-filter.ts +1 -1
  382. package/src/dev-ports.ts +3 -3
  383. package/src/dev-session.ts +6 -6
  384. package/src/dev-shutdown.ts +8 -8
  385. package/src/dev-task-colors.ts +1 -1
  386. package/src/docker-postgres.ts +6 -6
  387. package/src/docker-runtime.ts +5 -5
  388. package/src/engine-client.ts +3 -3
  389. package/src/engine-push-output.ts +1 -1
  390. package/src/ensure-binary.ts +20 -0
  391. package/src/ensure-component-binaries.ts +1 -1
  392. package/src/env-file.ts +157 -11
  393. package/src/field-masking-tier.ts +107 -0
  394. package/src/functions-deno-types.ts +188 -0
  395. package/src/functions-router-gen.ts +1 -1
  396. package/src/gitignore.ts +3 -3
  397. package/src/hook-upload.ts +107 -0
  398. package/src/hooks-generator.ts +352 -0
  399. package/src/index.ts +1 -1
  400. package/src/init-project-detect.ts +1 -1
  401. package/src/link.ts +7 -0
  402. package/src/local-secrets.ts +104 -0
  403. package/src/main.ts +20 -0
  404. package/src/model-hooks.ts +260 -0
  405. package/src/pgbouncer-userlist.ts +2 -2
  406. package/src/postgres-ctl.ts +32 -5
  407. package/src/process-manager.ts +4 -4
  408. package/src/project-config.ts +237 -3
  409. package/src/pull-utils.ts +4 -4
  410. package/src/realtime-launch.ts +1 -1
  411. package/src/release-pins.ts +2 -2
  412. package/src/resolve-api-url.ts +1 -1
  413. package/src/resolve-target.ts +113 -68
  414. package/src/rest-cache-admin.ts +2 -2
  415. package/src/runtime-routes.ts +2 -2
  416. package/src/schema-ast-v2.ts +8 -5
  417. package/src/schema-push-lock.ts +56 -17
  418. package/src/scripts/postinstall.ts +1 -1
  419. package/src/self-host-compose.ts +348 -72
  420. package/src/service-role-check.ts +111 -0
  421. package/src/storage-provision.ts +3 -3
  422. package/src/studio-dev-server.ts +1 -1
  423. package/src/systemd.ts +1 -1
  424. package/src/target-client.ts +105 -18
  425. package/src/tsx-runner.ts +1 -1
  426. package/src/type-extractor.ts +885 -30
  427. package/src/type-resolver.ts +1 -1
  428. package/src/ui/README.md +1 -1
  429. package/src/ui/brand.ts +1 -1
  430. package/src/ui/components/LogoWordmark.tsx +1 -1
  431. package/src/ui/components/SelectField.tsx +1 -1
  432. package/src/ui/confirm.ts +1 -1
  433. package/src/ui/fatal.ts +1 -1
  434. package/src/ui/flows/prompt-fields.tsx +1 -1
  435. package/src/ui/interactive.ts +1 -1
  436. package/src/ui/progress.ts +1 -1
  437. package/src/ui/runtime/command-chrome.ts +2 -2
  438. package/src/ui/runtime/run-clack-flow.tsx +1 -1
  439. package/src/ui/runtime/stdin-after-ink.ts +4 -2
  440. package/src/ui/theme.ts +1 -1
  441. package/src/valkey-sidecar.ts +2 -2
  442. package/tests/access-composition.test.ts +667 -0
  443. package/tests/admin-studio-membership.test.ts +121 -0
  444. package/tests/api-schemas.test.ts +83 -0
  445. package/tests/archive-name-alias.test.ts +42 -0
  446. package/tests/augmentation-generator.test.ts +28 -0
  447. package/tests/cache-clean.test.ts +206 -0
  448. package/tests/cli-help.test.ts +11 -2
  449. package/tests/cli-install-method.test.ts +66 -0
  450. package/tests/command-chrome-coverage.test.ts +31 -26
  451. package/tests/command-chrome-wrap.test.ts +1 -0
  452. package/tests/db-preflight.test.ts +72 -0
  453. package/tests/doctor-render.test.ts +62 -0
  454. package/tests/doctor-service-role.test.ts +55 -0
  455. package/tests/engine-push-output.test.ts +1 -1
  456. package/tests/env-file.test.ts +121 -0
  457. package/tests/external-database-compose.test.ts +184 -0
  458. package/tests/external-database-config.test.ts +154 -0
  459. package/tests/field-masking-tier.test.ts +184 -0
  460. package/tests/functions-deno-types.test.ts +197 -0
  461. package/tests/homebrew-formula.test.ts +100 -0
  462. package/tests/hook-upload.test.ts +125 -0
  463. package/tests/hooks-generator.test.ts +212 -0
  464. package/tests/init.test.ts +5 -2
  465. package/tests/keys.test.ts +8 -2
  466. package/tests/local-secrets.test.ts +92 -0
  467. package/tests/model-hooks.test.ts +322 -0
  468. package/tests/runtime-contract.test.ts +113 -1
  469. package/tests/service-role-check.test.ts +109 -0
  470. package/tests/service-role-routes.test.ts +51 -0
  471. package/tests/storage-provision.test.ts +1 -1
  472. package/tests/target-client-refresh.test.ts +94 -0
  473. package/tests/type-extractor.test.ts +187 -0
  474. package/tsconfig.tsbuildinfo +1 -1
  475. package/vitest.config.ts +7 -1
  476. package/scripts/build-release-bundle.mjs +0 -27
  477. package/tests/engine-distribution.test.ts +0 -418
@@ -1,4 +1,4 @@
1
- interface AstModel {
1
+ export interface AstModel {
2
2
  name?: string
3
3
  tableName?: string
4
4
  fields: Record<string, Record<string, unknown>>
@@ -11,7 +11,14 @@ interface AstShape {
11
11
  models?: AstModel[]
12
12
  }
13
13
 
14
- function resolveTableName(model: AstModel): string {
14
+ /**
15
+ * Shared with the hooks generator on purpose.
16
+ *
17
+ * A hook's `row` must be the same shape the client sees for that table, and two copies of this logic
18
+ * would drift: the client would gain a column type the hook handler did not, which is the failure
19
+ * mode this codebase has already paid for once.
20
+ */
21
+ export function resolveTableName(model: AstModel): string {
15
22
  const fromAnnotations = model.annotations?.db?.tableName
16
23
  if (typeof fromAnnotations === "string" && fromAnnotations.length > 0) return fromAnnotations
17
24
  if (typeof model.tableName === "string" && model.tableName.length > 0) return model.tableName
@@ -36,7 +43,7 @@ export function generateClientAugmentation(ast: unknown): string {
36
43
  .sort((a, b) => a.tableName.localeCompare(b.tableName))
37
44
 
38
45
  const lines: string[] = []
39
- lines.push("// Generated by supatype CLI do not edit manually.")
46
+ lines.push("// Generated by supatype CLI, do not edit manually.")
40
47
  lines.push("")
41
48
  lines.push("declare module \"@supatype/client\" {")
42
49
  lines.push(" interface SupatypeModels {")
@@ -58,7 +65,7 @@ export function generateClientAugmentation(ast: unknown): string {
58
65
  return lines.join("\n")
59
66
  }
60
67
 
61
- function generateRowType(fields: Record<string, Record<string, unknown>>): string {
68
+ export function generateRowType(fields: Record<string, Record<string, unknown>>): string {
62
69
  const entries = Object.entries(fields).sort(([a], [b]) => a.localeCompare(b))
63
70
  if (entries.length === 0) return "Record<string, unknown>"
64
71
  const body = entries
@@ -71,7 +78,7 @@ function insertColumnOptionalOnInsert(meta: Record<string, unknown>): boolean {
71
78
  return meta["default"] !== undefined || fieldServerGenerated(meta)
72
79
  }
73
80
 
74
- function generateInsertType(fields: Record<string, Record<string, unknown>>): string {
81
+ export function generateInsertType(fields: Record<string, Record<string, unknown>>): string {
75
82
  const entries = Object.entries(fields).sort(([a], [b]) => a.localeCompare(b))
76
83
  if (entries.length === 0) return "Record<string, unknown>"
77
84
  const body = entries
@@ -83,7 +90,7 @@ function generateInsertType(fields: Record<string, Record<string, unknown>>): st
83
90
  return `{\n${body}\n}`
84
91
  }
85
92
 
86
- function generateUpdateType(fields: Record<string, Record<string, unknown>>): string {
93
+ export function generateUpdateType(fields: Record<string, Record<string, unknown>>): string {
87
94
  const entries = Object.entries(fields).sort(([a], [b]) => a.localeCompare(b))
88
95
  if (entries.length === 0) return "Record<string, unknown>"
89
96
  const body = entries
@@ -96,6 +103,12 @@ function toTsType(meta: Record<string, unknown>): string {
96
103
  const kind = typeof meta["kind"] === "string" ? meta["kind"] : "json"
97
104
  const required = meta["required"] === true
98
105
  const base = (() => {
106
+ // A field that knows its own shape says so. Without this, everything stored as JSONB collapses
107
+ // to `Record<string, unknown>` in the generated row, so `Currency` would arrive as an opaque
108
+ // object rather than `{ amount: string; code: "USD" }`, and the schema's precision would be
109
+ // lost exactly where a caller reads it.
110
+ const declared = meta["tsType"]
111
+ if (typeof declared === "string" && declared.length > 0) return declared
99
112
  switch (kind) {
100
113
  case "uuid":
101
114
  case "slug":
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Binary cache manages supatype component binaries.
2
+ * Binary cache: manages supatype component binaries.
3
3
  *
4
4
  * Components: engine, server, postgres, deno, realtime.
5
5
  * Cache root: ~/.supatype/cache/{component}/{version}/
@@ -71,7 +71,7 @@ export function hasMeaningfulOverrides(config: SupatypeProjectConfig): boolean {
71
71
  return false
72
72
  }
73
73
 
74
- /** Lines for a startup banner non-empty override paths only. */
74
+ /** Lines for a startup banner, non-empty override paths only. */
75
75
  export function describeActiveOverrides(config: SupatypeProjectConfig): string[] {
76
76
  const o = config.overrides
77
77
  if (!o) return []
@@ -196,6 +196,26 @@ function binaryName(component: Component, version: string, platform: PlatformId)
196
196
  }
197
197
  }
198
198
 
199
+ /**
200
+ * Names a published archive may carry, most-canonical first.
201
+ *
202
+ * `supatype-postgres` published the Intel macOS archive as `darwin-x86_64` while every other platform
203
+ * used `amd64`, the spelling the CLI derives from `process.arch === "x64"`. Releases already on the CDN
204
+ * carry the old name, so both are accepted and the *signed* checksums manifest decides which exists.
205
+ * Nothing is guessed: the URL and the hash always come from the same manifest entry.
206
+ */
207
+ export function archiveNameCandidates(
208
+ component: Component,
209
+ version: string,
210
+ platform: PlatformId,
211
+ ): string[] {
212
+ const canonical = binaryName(component, version, platform)
213
+ if (component === "postgres" && platform.os === "darwin" && platform.arch === "amd64") {
214
+ return [canonical, canonical.replace("darwin-amd64", "darwin-x86_64")]
215
+ }
216
+ return [canonical]
217
+ }
218
+
199
219
  // ---------------------------------------------------------------------------
200
220
  // Platform detection
201
221
  // ---------------------------------------------------------------------------
@@ -222,9 +242,9 @@ export function currentPlatform(): PlatformId {
222
242
  * Resolve the binary path for a component.
223
243
  *
224
244
  * Resolution order:
225
- * 1. config.overrides?.[component] local build path (must exist)
245
+ * 1. config.overrides?.[component]: local build path (must exist)
226
246
  * 2. Cached binary at ~/.supatype/cache/{component}/{version}/
227
- * 3. Throws caller should call download() first.
247
+ * 3. Throws, so the caller should call download() first.
228
248
  *
229
249
  * Hard error if any meaningful `overrides` entry is set while the project is linked to cloud
230
250
  * (`project.ref`, `.supatype/cloud.json`, or `.supatype/linked.json`).
@@ -332,7 +352,7 @@ async function acquireDownloadSlot(
332
352
 
333
353
  if (isDownloadInProgress(component, version)) {
334
354
  console.log(
335
- `[supatype] ${component} v${version} is downloading in another process waiting...`,
355
+ `[supatype] ${component} v${version} is downloading in another process, waiting...`,
336
356
  )
337
357
  const outcome = await waitForComponentDownload(component, version, isReady, (c) => {
338
358
  console.log(`[supatype] Still waiting for ${c} download...`)
@@ -344,7 +364,7 @@ async function acquireDownloadSlot(
344
364
  )
345
365
  }
346
366
  console.warn(
347
- `[supatype] ${component} v${version} download did not finish in the other process retrying.`,
367
+ `[supatype] ${component} v${version} download did not finish in the other process, retrying.`,
348
368
  )
349
369
  continue
350
370
  }
@@ -364,7 +384,7 @@ export async function download(
364
384
  ): Promise<string> {
365
385
  if (version === VERSION_PIN_LOCAL) {
366
386
  throw new Error(
367
- `cannot download CDN binary when version is "${VERSION_PIN_LOCAL}" set overrides.${component === "postgres" ? "postgres_dir" : component} or pin a semver`,
387
+ `cannot download CDN binary when version is "${VERSION_PIN_LOCAL}": set overrides.${component === "postgres" ? "postgres_dir" : component} or pin a semver`,
368
388
  )
369
389
  }
370
390
 
@@ -380,7 +400,7 @@ export async function download(
380
400
  return destPath
381
401
  }
382
402
  console.warn(
383
- `[supatype] ${component} v${version} cache invalid re-downloading (${destPath}).`,
403
+ `[supatype] ${component} v${version} cache invalid, re-downloading (${destPath}).`,
384
404
  )
385
405
  unlinkSync(destPath)
386
406
  }
@@ -390,7 +410,6 @@ export async function download(
390
410
  return destPath
391
411
  }
392
412
 
393
- const binaryUrl = `${CDN_BASE}${CDN_PATHS[component](version, platform)}`
394
413
  const checksumsUrl = `${CDN_BASE}${checksumsDirPath(component, version)}`
395
414
  const minisigUrl = `${checksumsUrl}.minisig`
396
415
 
@@ -399,15 +418,20 @@ export async function download(
399
418
  const tmpPath = destPath + ".tmp"
400
419
  try {
401
420
  // ── Fetch checksums + optional minisig (retried on transient failures) ───
402
- const expectedChecksum = await withRetry(() =>
403
- fetchChecksums(checksumsUrl, minisigUrl, name),
421
+ const match = await withRetry(() =>
422
+ fetchChecksums(checksumsUrl, minisigUrl, archiveNameCandidates(component, version, platform)),
404
423
  )
405
424
 
425
+ // The directory from the path template, the filename from the manifest: a release published under
426
+ // a legacy name is fetched under that name rather than one the CLI assumed.
427
+ const cdnDir = CDN_PATHS[component](version, platform).replace(/\/[^/]+$/, "")
428
+ const binaryUrl = `${CDN_BASE}${cdnDir}/${match.filename}`
429
+
406
430
  // ── Stream-download binary with progress (retried on transient failures) ─
407
431
  await withRetry(() => streamToFileWithProgress(binaryUrl, tmpPath))
408
432
 
409
433
  // ── Verify SHA256 ────────────────────────────────────────────────────────
410
- await verifyChecksum(tmpPath, expectedChecksum, component)
434
+ await verifyChecksum(tmpPath, match.checksum, component)
411
435
 
412
436
  writeFileSync(destPath, readFileSync(tmpPath))
413
437
 
@@ -437,11 +461,19 @@ export async function download(
437
461
  * Fetch checksums.sha256, optionally verify its minisign signature, and
438
462
  * return the expected SHA256 for `binaryFilename`.
439
463
  */
440
- async function fetchChecksums(
464
+ /**
465
+ * Fetch a checksums manifest and verify its minisign signature, returning the entry for one of
466
+ * `binaryFilenames`.
467
+ *
468
+ * Exported so the standalone CLI download path enforces the same rule as component downloads.
469
+ * It previously verified nothing at all, which made the CLI stricter about a postgres archive
470
+ * than about overwriting its own executable.
471
+ */
472
+ export async function fetchChecksums(
441
473
  checksumsUrl: string,
442
474
  minisigUrl: string,
443
- binaryFilename: string,
444
- ): Promise<string> {
475
+ binaryFilenames: string | string[],
476
+ ): Promise<ChecksumMatch> {
445
477
  const csResp = await fetch(checksumsUrl)
446
478
  if (!csResp.ok) {
447
479
  throw new Error(`Failed to fetch checksums from ${checksumsUrl}: HTTP ${csResp.status}`)
@@ -452,16 +484,16 @@ async function fetchChecksums(
452
484
  if (!pubKey) {
453
485
  // Fail closed: a missing public key means we cannot verify authenticity, only
454
486
  // integrity (SHA256). Published builds always embed the key, so this only
455
- // happens in source/contributor builds never silently downgrade.
487
+ // happens in source/contributor builds. Never silently downgrade.
456
488
  if (process.env["SUPATYPE_ALLOW_UNVERIFIED_DOWNLOADS"] === "1") {
457
489
  console.warn(
458
- "[supatype] \u26a0 SUPATYPE_ALLOW_UNVERIFIED_DOWNLOADS=1 no minisign public " +
490
+ "[supatype] \u26a0 SUPATYPE_ALLOW_UNVERIFIED_DOWNLOADS=1: no minisign public " +
459
491
  "key configured; verifying SHA256 only (authenticity NOT checked).",
460
492
  )
461
- return extractChecksum(checksumsText, binaryFilename)
493
+ return extractChecksum(checksumsText, binaryFilenames)
462
494
  }
463
495
  throw new Error(
464
- "No minisign public key configured cannot verify release authenticity.\n" +
496
+ "No minisign public key configured, so cannot verify release authenticity.\n" +
465
497
  "Published @supatype/cli builds embed the key automatically; if you are building " +
466
498
  "from source, set SUPATYPE_RELEASE_PUBLIC_KEY to the release public key, or set " +
467
499
  "SUPATYPE_ALLOW_UNVERIFIED_DOWNLOADS=1 to download with SHA256-only verification (unsafe).",
@@ -479,7 +511,7 @@ async function fetchChecksums(
479
511
  const sigText = await sigResp.text()
480
512
  verifyMinisign(Buffer.from(checksumsText, "utf8"), sigText, pubKey)
481
513
 
482
- return extractChecksum(checksumsText, binaryFilename)
514
+ return extractChecksum(checksumsText, binaryFilenames)
483
515
  }
484
516
 
485
517
  // ---------------------------------------------------------------------------
@@ -487,7 +519,7 @@ async function fetchChecksums(
487
519
  // ---------------------------------------------------------------------------
488
520
 
489
521
  /**
490
- * Ed25519 SPKI DER prefix wraps a raw 32-byte public key into the
522
+ * Ed25519 SPKI DER prefix, wraps a raw 32-byte public key into the
491
523
  * SubjectPublicKeyInfo structure that Node.js crypto.createPublicKey expects.
492
524
  *
493
525
  * Breakdown:
@@ -515,7 +547,7 @@ export function verifyMinisign(fileBytes: Buffer, sigFileContent: string, pubKey
515
547
 
516
548
  // Parse signature file:
517
549
  // line 0: untrusted comment
518
- // line 1: base64 sig bytes [2 algo][8 keyId][64 Ed25519 sig]
550
+ // line 1: base64 sig bytes: [2 algo][8 keyId][64 Ed25519 sig]
519
551
  // line 2: trusted comment
520
552
  // line 3: base64 global sig (over sig bytes + trusted comment)
521
553
  const sigLines = sigFileContent.trim().split("\n")
@@ -528,12 +560,12 @@ export function verifyMinisign(fileBytes: Buffer, sigFileContent: string, pubKey
528
560
  const signature = sigBytes.subarray(10, 74)
529
561
 
530
562
  // Both Ed25519 modes are supported:
531
- // "Ed" (0x45, 0x64) legacy: signature is over the raw file bytes.
532
- // "ED" (0x45, 0x44) prehashed: signature is over BLAKE2b-512(file).
563
+ // "Ed" (0x45, 0x64) legacy: signature is over the raw file bytes.
564
+ // "ED" (0x45, 0x44) prehashed: signature is over BLAKE2b-512(file).
533
565
  // Modern minisign (and our release pipeline) default to prehashed mode.
534
566
  if (algo[0] !== 0x45 || (algo[1] !== 0x64 && algo[1] !== 0x44)) {
535
567
  throw new Error(
536
- "Unsupported minisign algorithm expected Ed25519 ('Ed' legacy or 'ED' prehashed).\n" +
568
+ "Unsupported minisign algorithm, expected Ed25519 ('Ed' legacy or 'ED' prehashed).\n" +
537
569
  `Got: 0x${algo[0]?.toString(16)}${algo[1]?.toString(16)}`,
538
570
  )
539
571
  }
@@ -541,7 +573,7 @@ export function verifyMinisign(fileBytes: Buffer, sigFileContent: string, pubKey
541
573
 
542
574
  if (!sigKeyId.equals(pkKeyId)) {
543
575
  throw new Error(
544
- "Minisign key ID mismatch signature was produced with a different key.\n" +
576
+ "Minisign key ID mismatch: the signature was produced with a different key.\n" +
545
577
  "This could indicate a compromised release. Do not proceed.",
546
578
  )
547
579
  }
@@ -558,7 +590,7 @@ export function verifyMinisign(fileBytes: Buffer, sigFileContent: string, pubKey
558
590
  const valid = cryptoVerify(null, signedData, keyObject, signature)
559
591
  if (!valid) {
560
592
  throw new Error(
561
- "Minisign signature verification FAILED the checksum file may have been tampered with.\n" +
593
+ "Minisign signature verification FAILED: the checksum file may have been tampered with.\n" +
562
594
  "This could indicate a supply chain attack. Aborting download.",
563
595
  )
564
596
  }
@@ -566,22 +598,37 @@ export function verifyMinisign(fileBytes: Buffer, sigFileContent: string, pubKey
566
598
 
567
599
  /**
568
600
  * Extract the SHA256 hash for `filename` from a checksums.sha256 file.
569
- * Format: `<hash> <filename>` (sha256sum output, two spaces).
601
+ * Format: `<hash> <filename>` (sha256sum output, two spaces), or `<hash> *<filename>` when
602
+ * the publisher used binary mode.
603
+ *
604
+ * Exported so the standalone CLI download path parses the manifest the same way rather than
605
+ * carrying a second implementation.
570
606
  */
571
- function extractChecksum(checksumsText: string, filename: string): string {
572
- const target = basename(filename)
573
- for (const line of checksumsText.split("\n")) {
574
- const parts = line.trim().split(/\s+/)
575
- if (parts.length >= 2 && parts[1] === target) {
576
- return parts[0]!
607
+ export function extractChecksum(
608
+ checksumsText: string,
609
+ filenames: string | string[],
610
+ ): ChecksumMatch {
611
+ const targets = (Array.isArray(filenames) ? filenames : [filenames]).map((f) => basename(f))
612
+ for (const target of targets) {
613
+ for (const line of checksumsText.split("\n")) {
614
+ const parts = line.trim().split(/\s+/)
615
+ if (parts.length >= 2 && parts[1]?.replace(/^\*/, "") === target) {
616
+ return { filename: target, checksum: parts[0]! }
617
+ }
577
618
  }
578
619
  }
579
620
  throw new Error(
580
- `Checksum not found for "${target}" in checksums.sha256.\n` +
621
+ `Checksum not found for ${targets.map((t) => `"${t}"`).join(" or ")} in checksums.sha256.\n` +
581
622
  "The checksums file may be from a different release.",
582
623
  )
583
624
  }
584
625
 
626
+ /** Which published name matched, and its hash, both from the same signed manifest entry. */
627
+ export interface ChecksumMatch {
628
+ filename: string
629
+ checksum: string
630
+ }
631
+
585
632
  // ---------------------------------------------------------------------------
586
633
  // Streaming download with progress bar
587
634
  // ---------------------------------------------------------------------------
@@ -658,9 +705,9 @@ export function validateArtifactFormat(
658
705
 
659
706
  /**
660
707
  * Per-component CDN artifact shapes:
661
- * engine, server, deno, realtime native executable (ELF / Mach-O / PE)
662
- * postgres (unix) .tar.gz (gzip)
663
- * postgres (windows) .zip
708
+ * engine, server, deno, realtime: native executable (ELF / Mach-O / PE)
709
+ * postgres (unix) .tar.gz (gzip)
710
+ * postgres (windows) .zip
664
711
  */
665
712
  function assertArtifactFormat(
666
713
  component: Component,
@@ -687,7 +734,7 @@ function assertGzipArchive(filePath: string): void {
687
734
  if (magic[0] !== 0x1f || magic[1] !== 0x8b) {
688
735
  throw new Error(
689
736
  "Downloaded postgres file is not a gzip archive (bad magic bytes). " +
690
- "The CDN object may be corrupt or cached HTML delete ~/.supatype/cache and retry.",
737
+ "The CDN object may be corrupt or cached HTML, so delete ~/.supatype/cache and retry.",
691
738
  )
692
739
  }
693
740
  } finally {
@@ -704,7 +751,7 @@ function assertZipArchive(filePath: string): void {
704
751
  if (magic[0] !== 0x50 || magic[1] !== 0x4b) {
705
752
  throw new Error(
706
753
  "Downloaded postgres file is not a zip archive (bad magic bytes). " +
707
- "The CDN object may be corrupt or cached HTML delete ~/.supatype/cache and retry.",
754
+ "The CDN object may be corrupt or cached HTML, so delete ~/.supatype/cache and retry.",
708
755
  )
709
756
  }
710
757
  } finally {
@@ -727,14 +774,14 @@ function assertNativeExecutable(
727
774
  if (goCArchive) {
728
775
  throw new Error(
729
776
  `Downloaded ${component} file is a Go static archive (c-archive), not an executable. ` +
730
- "The CDN object may be from a bad release build delete ~/.supatype/cache and retry.",
777
+ "The CDN object may be from a bad release build, so delete ~/.supatype/cache and retry.",
731
778
  )
732
779
  }
733
780
  if (platform.os === "windows") {
734
781
  if (magic[0] !== 0x4d || magic[1] !== 0x5a) {
735
782
  throw new Error(
736
783
  `Downloaded ${component} file is not a Windows PE executable (bad magic bytes). ` +
737
- "The CDN object may be corrupt or cached HTML delete ~/.supatype/cache and retry.",
784
+ "The CDN object may be corrupt or cached HTML, so delete ~/.supatype/cache and retry.",
738
785
  )
739
786
  }
740
787
  return
@@ -745,7 +792,7 @@ function assertNativeExecutable(
745
792
  if (!elf) {
746
793
  throw new Error(
747
794
  `Downloaded ${component} file is not an ELF executable (bad magic bytes). ` +
748
- "The CDN object may be corrupt or cached HTML delete ~/.supatype/cache and retry.",
795
+ "The CDN object may be corrupt or cached HTML, so delete ~/.supatype/cache and retry.",
749
796
  )
750
797
  }
751
798
  return
@@ -759,7 +806,7 @@ function assertNativeExecutable(
759
806
  if (!macho) {
760
807
  throw new Error(
761
808
  `Downloaded ${component} file is not a Mach-O executable (bad magic bytes). ` +
762
- "The CDN object may be corrupt or cached HTML delete ~/.supatype/cache and retry.",
809
+ "The CDN object may be corrupt or cached HTML, so delete ~/.supatype/cache and retry.",
763
810
  )
764
811
  }
765
812
  } finally {
@@ -805,7 +852,7 @@ async function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
805
852
  // ---------------------------------------------------------------------------
806
853
 
807
854
  /**
808
- * On Windows, Git Bash represents paths as /c/Users/... convert to C:\Users\...
855
+ * On Windows, Git Bash represents paths as /c/Users/..., convert to C:\Users\...
809
856
  */
810
857
  export function normalisePlatformPath(p: string): string {
811
858
  let result = p
@@ -899,7 +946,7 @@ export async function fetchAllLatestVersions(): Promise<Partial<Record<Component
899
946
  */
900
947
  /**
901
948
  * Verify cached binaries for the current platform (used by integration CI).
902
- * Only checks components present in `versions` unpublished CDN components
949
+ * Only checks components present in `versions`; unpublished CDN components
903
950
  * (no latest.json yet) are skipped with a log so CI can land before first release.
904
951
  * Throws if a pinned component is missing from cache or fails format checks.
905
952
  */
@@ -912,7 +959,7 @@ export function verifyCachedBinaries(versions: Partial<ComponentVersions> | unde
912
959
  const version = versions[component]
913
960
  if (typeof version !== "string" || version.trim() === "") {
914
961
  console.log(
915
- `[supatype] skipping verify for ${component} (no version CDN latest.json not published yet)`,
962
+ `[supatype] skipping verify for ${component} (no version, CDN latest.json not published yet)`,
916
963
  )
917
964
  continue
918
965
  }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Helpers for `supatype cache list` / `cache clean` (shared sizing + formatting).
3
+ */
4
+
5
+ import { readdirSync, statSync } from "node:fs"
6
+ import { join } from "node:path"
7
+ import { BINARY_COMPONENTS, type Component } from "./components.js"
8
+ import { cacheRoot } from "./binary-cache.js"
9
+ import { isVersionPinned, loadPinnedVersionsForProjects, resolveCacheProjectDirs } from "./cache-pins.js"
10
+
11
+ export function dirSize(dir: string): number {
12
+ let total = 0
13
+ try {
14
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
15
+ const full = join(dir, entry.name)
16
+ if (entry.isDirectory()) {
17
+ total += dirSize(full)
18
+ } else {
19
+ total += statSync(full).size
20
+ }
21
+ }
22
+ } catch {
23
+ // skip unreadable
24
+ }
25
+ return total
26
+ }
27
+
28
+ export function formatBytes(bytes: number): string {
29
+ if (bytes < 1024) return `${bytes} B`
30
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
31
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
32
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`
33
+ }
34
+
35
+ export function listCacheEntries(projectDirs: string[]): Array<{
36
+ component: Component
37
+ version: string
38
+ bytes: number
39
+ pinned: boolean
40
+ }> {
41
+ const root = cacheRoot()
42
+ const { protectedVersions } = loadPinnedVersionsForProjects(projectDirs)
43
+ const entries: Array<{ component: Component; version: string; bytes: number; pinned: boolean }> = []
44
+
45
+ for (const component of BINARY_COMPONENTS) {
46
+ const compDir = join(root, component)
47
+ if (!statExists(compDir)) continue
48
+
49
+ for (const version of readdirSync(compDir)) {
50
+ const vDir = join(compDir, version)
51
+ if (!statIsDir(vDir)) continue
52
+ entries.push({
53
+ component,
54
+ version,
55
+ bytes: dirSize(vDir),
56
+ pinned: protectedVersions.get(component)?.has(version) ?? false,
57
+ })
58
+ }
59
+ }
60
+
61
+ return entries
62
+ }
63
+
64
+ function statExists(path: string): boolean {
65
+ try {
66
+ statSync(path)
67
+ return true
68
+ } catch {
69
+ return false
70
+ }
71
+ }
72
+
73
+ function statIsDir(path: string): boolean {
74
+ try {
75
+ return statSync(path).isDirectory()
76
+ } catch {
77
+ return false
78
+ }
79
+ }
80
+
81
+ export { BINARY_COMPONENTS, resolveCacheProjectDirs }