@supatype/cli 0.1.0-alpha.9 → 0.1.1

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 (407) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/.turbo/turbo-test.log +285 -69
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/assets/supatype-logo-wordmark.ascii.txt +6 -0
  5. package/bin/dev-entry.ts +2 -1
  6. package/dist/app/framework.js +1 -3
  7. package/dist/app/framework.js.map +1 -1
  8. package/dist/app/proxy-dev-app.d.ts +14 -0
  9. package/dist/app/proxy-dev-app.d.ts.map +1 -1
  10. package/dist/app/proxy-dev-app.js +110 -6
  11. package/dist/app/proxy-dev-app.js.map +1 -1
  12. package/dist/app-config.d.ts +10 -0
  13. package/dist/app-config.d.ts.map +1 -1
  14. package/dist/app-config.js +72 -0
  15. package/dist/app-config.js.map +1 -1
  16. package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
  17. package/dist/binary-cache.d.ts +19 -7
  18. package/dist/binary-cache.d.ts.map +1 -1
  19. package/dist/binary-cache.js +92 -46
  20. package/dist/binary-cache.js.map +1 -1
  21. package/dist/cli.d.ts +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +17 -2
  24. package/dist/cli.js.map +1 -1
  25. package/dist/commands/add.d.ts +3 -0
  26. package/dist/commands/add.d.ts.map +1 -0
  27. package/dist/commands/add.js +86 -0
  28. package/dist/commands/add.js.map +1 -0
  29. package/dist/commands/admin.d.ts +28 -1
  30. package/dist/commands/admin.d.ts.map +1 -1
  31. package/dist/commands/admin.js +297 -149
  32. package/dist/commands/admin.js.map +1 -1
  33. package/dist/commands/adopt.d.ts +3 -0
  34. package/dist/commands/adopt.d.ts.map +1 -0
  35. package/dist/commands/adopt.js +55 -0
  36. package/dist/commands/adopt.js.map +1 -0
  37. package/dist/commands/app.d.ts.map +1 -1
  38. package/dist/commands/app.js +20 -17
  39. package/dist/commands/app.js.map +1 -1
  40. package/dist/commands/cache.d.ts.map +1 -1
  41. package/dist/commands/cache.js +11 -10
  42. package/dist/commands/cache.js.map +1 -1
  43. package/dist/commands/cloud.d.ts +4 -9
  44. package/dist/commands/cloud.d.ts.map +1 -1
  45. package/dist/commands/cloud.js +75 -125
  46. package/dist/commands/cloud.js.map +1 -1
  47. package/dist/commands/db.d.ts.map +1 -1
  48. package/dist/commands/db.js +37 -58
  49. package/dist/commands/db.js.map +1 -1
  50. package/dist/commands/deploy.d.ts.map +1 -1
  51. package/dist/commands/deploy.js +140 -96
  52. package/dist/commands/deploy.js.map +1 -1
  53. package/dist/commands/dev.d.ts.map +1 -1
  54. package/dist/commands/dev.js +74 -39
  55. package/dist/commands/dev.js.map +1 -1
  56. package/dist/commands/diff.d.ts.map +1 -1
  57. package/dist/commands/diff.js +39 -39
  58. package/dist/commands/diff.js.map +1 -1
  59. package/dist/commands/doctor.d.ts +3 -0
  60. package/dist/commands/doctor.d.ts.map +1 -0
  61. package/dist/commands/doctor.js +78 -0
  62. package/dist/commands/doctor.js.map +1 -0
  63. package/dist/commands/engine.d.ts.map +1 -1
  64. package/dist/commands/engine.js +5 -4
  65. package/dist/commands/engine.js.map +1 -1
  66. package/dist/commands/functions.d.ts.map +1 -1
  67. package/dist/commands/functions.js +172 -119
  68. package/dist/commands/functions.js.map +1 -1
  69. package/dist/commands/generate.d.ts.map +1 -1
  70. package/dist/commands/generate.js +5 -4
  71. package/dist/commands/generate.js.map +1 -1
  72. package/dist/commands/init.d.ts +35 -1
  73. package/dist/commands/init.d.ts.map +1 -1
  74. package/dist/commands/init.js +883 -107
  75. package/dist/commands/init.js.map +1 -1
  76. package/dist/commands/introspect.d.ts +3 -0
  77. package/dist/commands/introspect.d.ts.map +1 -0
  78. package/dist/commands/introspect.js +35 -0
  79. package/dist/commands/introspect.js.map +1 -0
  80. package/dist/commands/keys.d.ts +15 -1
  81. package/dist/commands/keys.d.ts.map +1 -1
  82. package/dist/commands/keys.js +46 -10
  83. package/dist/commands/keys.js.map +1 -1
  84. package/dist/commands/link-helpers.d.ts +15 -0
  85. package/dist/commands/link-helpers.d.ts.map +1 -0
  86. package/dist/commands/link-helpers.js +225 -0
  87. package/dist/commands/link-helpers.js.map +1 -0
  88. package/dist/commands/logs.d.ts.map +1 -1
  89. package/dist/commands/logs.js +5 -4
  90. package/dist/commands/logs.js.map +1 -1
  91. package/dist/commands/migrate-from-v1.d.ts.map +1 -1
  92. package/dist/commands/migrate-from-v1.js +3 -2
  93. package/dist/commands/migrate-from-v1.js.map +1 -1
  94. package/dist/commands/migrate.d.ts.map +1 -1
  95. package/dist/commands/migrate.js +119 -26
  96. package/dist/commands/migrate.js.map +1 -1
  97. package/dist/commands/pg.d.ts.map +1 -1
  98. package/dist/commands/pg.js +11 -12
  99. package/dist/commands/pg.js.map +1 -1
  100. package/dist/commands/plugins.d.ts.map +1 -1
  101. package/dist/commands/plugins.js +55 -46
  102. package/dist/commands/plugins.js.map +1 -1
  103. package/dist/commands/pull.d.ts.map +1 -1
  104. package/dist/commands/pull.js +33 -5
  105. package/dist/commands/pull.js.map +1 -1
  106. package/dist/commands/push.d.ts.map +1 -1
  107. package/dist/commands/push.js +111 -138
  108. package/dist/commands/push.js.map +1 -1
  109. package/dist/commands/seed.d.ts.map +1 -1
  110. package/dist/commands/seed.js +4 -3
  111. package/dist/commands/seed.js.map +1 -1
  112. package/dist/commands/self-host.d.ts +2 -2
  113. package/dist/commands/self-host.d.ts.map +1 -1
  114. package/dist/commands/self-host.js +65 -50
  115. package/dist/commands/self-host.js.map +1 -1
  116. package/dist/commands/self-update.d.ts.map +1 -1
  117. package/dist/commands/self-update.js +3 -2
  118. package/dist/commands/self-update.js.map +1 -1
  119. package/dist/commands/status.d.ts +1 -1
  120. package/dist/commands/status.d.ts.map +1 -1
  121. package/dist/commands/status.js +95 -29
  122. package/dist/commands/status.js.map +1 -1
  123. package/dist/commands/types.d.ts.map +1 -1
  124. package/dist/commands/types.js +3 -2
  125. package/dist/commands/types.js.map +1 -1
  126. package/dist/commands/update.d.ts.map +1 -1
  127. package/dist/commands/update.js +54 -21
  128. package/dist/commands/update.js.map +1 -1
  129. package/dist/compose-rename.d.ts +10 -0
  130. package/dist/compose-rename.d.ts.map +1 -0
  131. package/dist/compose-rename.js +67 -0
  132. package/dist/compose-rename.js.map +1 -0
  133. package/dist/config.d.ts +2 -1
  134. package/dist/config.d.ts.map +1 -1
  135. package/dist/config.js.map +1 -1
  136. package/dist/dev-compose.d.ts +26 -0
  137. package/dist/dev-compose.d.ts.map +1 -1
  138. package/dist/dev-compose.js +357 -79
  139. package/dist/dev-compose.js.map +1 -1
  140. package/dist/dev-log-bus.d.ts +30 -0
  141. package/dist/dev-log-bus.d.ts.map +1 -0
  142. package/dist/dev-log-bus.js +87 -0
  143. package/dist/dev-log-bus.js.map +1 -0
  144. package/dist/dev-log-filter.d.ts +10 -0
  145. package/dist/dev-log-filter.d.ts.map +1 -0
  146. package/dist/dev-log-filter.js +36 -0
  147. package/dist/dev-log-filter.js.map +1 -0
  148. package/dist/dev-logo.d.ts +12 -0
  149. package/dist/dev-logo.d.ts.map +1 -0
  150. package/dist/dev-logo.js +56 -0
  151. package/dist/dev-logo.js.map +1 -0
  152. package/dist/dev-ports.d.ts +27 -0
  153. package/dist/dev-ports.d.ts.map +1 -0
  154. package/dist/dev-ports.js +171 -0
  155. package/dist/dev-ports.js.map +1 -0
  156. package/dist/dev-session-lock.d.ts +25 -0
  157. package/dist/dev-session-lock.d.ts.map +1 -0
  158. package/dist/dev-session-lock.js +81 -0
  159. package/dist/dev-session-lock.js.map +1 -0
  160. package/dist/dev-session.d.ts +26 -0
  161. package/dist/dev-session.d.ts.map +1 -0
  162. package/dist/dev-session.js +106 -0
  163. package/dist/dev-session.js.map +1 -0
  164. package/dist/dev-shutdown.d.ts +25 -0
  165. package/dist/dev-shutdown.d.ts.map +1 -0
  166. package/dist/dev-shutdown.js +114 -0
  167. package/dist/dev-shutdown.js.map +1 -0
  168. package/dist/dev-task-colors.d.ts +13 -0
  169. package/dist/dev-task-colors.d.ts.map +1 -0
  170. package/dist/dev-task-colors.js +43 -0
  171. package/dist/dev-task-colors.js.map +1 -0
  172. package/dist/dev-tui.d.ts +24 -0
  173. package/dist/dev-tui.d.ts.map +1 -0
  174. package/dist/dev-tui.js +188 -0
  175. package/dist/dev-tui.js.map +1 -0
  176. package/dist/diff-output.d.ts +5 -1
  177. package/dist/diff-output.d.ts.map +1 -1
  178. package/dist/diff-output.js +69 -0
  179. package/dist/diff-output.js.map +1 -1
  180. package/dist/docker-runtime.d.ts +30 -0
  181. package/dist/docker-runtime.d.ts.map +1 -0
  182. package/dist/docker-runtime.js +118 -0
  183. package/dist/docker-runtime.js.map +1 -0
  184. package/dist/engine-client.d.ts +10 -1
  185. package/dist/engine-client.d.ts.map +1 -1
  186. package/dist/engine-client.js +76 -17
  187. package/dist/engine-client.js.map +1 -1
  188. package/dist/engine-push-output.d.ts +17 -0
  189. package/dist/engine-push-output.d.ts.map +1 -0
  190. package/dist/engine-push-output.js +64 -0
  191. package/dist/engine-push-output.js.map +1 -0
  192. package/dist/ensure-binary.js +2 -2
  193. package/dist/ensure-binary.js.map +1 -1
  194. package/dist/env-file.d.ts +5 -0
  195. package/dist/env-file.d.ts.map +1 -0
  196. package/dist/env-file.js +33 -0
  197. package/dist/env-file.js.map +1 -0
  198. package/dist/gitignore.d.ts +8 -0
  199. package/dist/gitignore.d.ts.map +1 -0
  200. package/dist/gitignore.js +41 -0
  201. package/dist/gitignore.js.map +1 -0
  202. package/dist/kong-config.d.ts +9 -0
  203. package/dist/kong-config.d.ts.map +1 -1
  204. package/dist/kong-config.js +18 -1
  205. package/dist/kong-config.js.map +1 -1
  206. package/dist/link.d.ts +66 -0
  207. package/dist/link.d.ts.map +1 -0
  208. package/dist/link.js +160 -0
  209. package/dist/link.js.map +1 -0
  210. package/dist/process-manager.d.ts +8 -0
  211. package/dist/process-manager.d.ts.map +1 -1
  212. package/dist/process-manager.js +53 -9
  213. package/dist/process-manager.js.map +1 -1
  214. package/dist/project-config.d.ts +30 -3
  215. package/dist/project-config.d.ts.map +1 -1
  216. package/dist/project-config.js +37 -4
  217. package/dist/project-config.js.map +1 -1
  218. package/dist/prompts.d.ts +3 -0
  219. package/dist/prompts.d.ts.map +1 -0
  220. package/dist/prompts.js +3 -0
  221. package/dist/prompts.js.map +1 -0
  222. package/dist/pull-utils.d.ts +50 -14
  223. package/dist/pull-utils.d.ts.map +1 -1
  224. package/dist/pull-utils.js +152 -12
  225. package/dist/pull-utils.js.map +1 -1
  226. package/dist/resolve-target.d.ts +86 -0
  227. package/dist/resolve-target.d.ts.map +1 -0
  228. package/dist/resolve-target.js +291 -0
  229. package/dist/resolve-target.js.map +1 -0
  230. package/dist/restore-system-relation-targets.d.ts +3 -0
  231. package/dist/restore-system-relation-targets.d.ts.map +1 -0
  232. package/dist/restore-system-relation-targets.js +45 -0
  233. package/dist/restore-system-relation-targets.js.map +1 -0
  234. package/dist/runtime-routes.d.ts.map +1 -1
  235. package/dist/runtime-routes.js +7 -0
  236. package/dist/runtime-routes.js.map +1 -1
  237. package/dist/schema-ast-v2.d.ts +1 -1
  238. package/dist/schema-ast-v2.d.ts.map +1 -1
  239. package/dist/schema-ast-v2.js +2 -2
  240. package/dist/schema-ast-v2.js.map +1 -1
  241. package/dist/schema-sources.d.ts +40 -0
  242. package/dist/schema-sources.d.ts.map +1 -0
  243. package/dist/schema-sources.js +183 -0
  244. package/dist/schema-sources.js.map +1 -0
  245. package/dist/scripts/postinstall.js +5 -1
  246. package/dist/scripts/postinstall.js.map +1 -1
  247. package/dist/self-host-compose.d.ts +37 -1
  248. package/dist/self-host-compose.d.ts.map +1 -1
  249. package/dist/self-host-compose.js +234 -43
  250. package/dist/self-host-compose.js.map +1 -1
  251. package/dist/storage-provision.d.ts +4 -0
  252. package/dist/storage-provision.d.ts.map +1 -1
  253. package/dist/storage-provision.js +24 -2
  254. package/dist/storage-provision.js.map +1 -1
  255. package/dist/supatype-eval-1781522769253.d.mts +2 -0
  256. package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
  257. package/dist/supatype-eval-1781522769253.mjs +3 -0
  258. package/dist/supatype-eval-1781522769253.mjs.map +1 -0
  259. package/dist/systemd.js +2 -2
  260. package/dist/systemd.js.map +1 -1
  261. package/dist/target-client.d.ts +10 -0
  262. package/dist/target-client.d.ts.map +1 -0
  263. package/dist/target-client.js +22 -0
  264. package/dist/target-client.js.map +1 -0
  265. package/dist/type-extractor.d.ts +11 -0
  266. package/dist/type-extractor.d.ts.map +1 -1
  267. package/dist/type-extractor.js +95 -8
  268. package/dist/type-extractor.js.map +1 -1
  269. package/dist/ui/brand.d.ts +9 -0
  270. package/dist/ui/brand.d.ts.map +1 -0
  271. package/dist/ui/brand.js +11 -0
  272. package/dist/ui/brand.js.map +1 -0
  273. package/dist/ui/confirm.d.ts +12 -0
  274. package/dist/ui/confirm.d.ts.map +1 -0
  275. package/dist/ui/confirm.js +28 -0
  276. package/dist/ui/confirm.js.map +1 -0
  277. package/dist/ui/fatal.d.ts +10 -0
  278. package/dist/ui/fatal.d.ts.map +1 -0
  279. package/dist/ui/fatal.js +34 -0
  280. package/dist/ui/fatal.js.map +1 -0
  281. package/dist/ui/index.d.ts +9 -0
  282. package/dist/ui/index.d.ts.map +1 -0
  283. package/dist/ui/index.js +9 -0
  284. package/dist/ui/index.js.map +1 -0
  285. package/dist/ui/interactive.d.ts +3 -0
  286. package/dist/ui/interactive.d.ts.map +1 -0
  287. package/dist/ui/interactive.js +5 -0
  288. package/dist/ui/interactive.js.map +1 -0
  289. package/dist/ui/messages.d.ts +10 -0
  290. package/dist/ui/messages.d.ts.map +1 -0
  291. package/dist/ui/messages.js +35 -0
  292. package/dist/ui/messages.js.map +1 -0
  293. package/dist/ui/next-steps.d.ts +3 -0
  294. package/dist/ui/next-steps.d.ts.map +1 -0
  295. package/dist/ui/next-steps.js +10 -0
  296. package/dist/ui/next-steps.js.map +1 -0
  297. package/dist/ui/progress.d.ts +5 -0
  298. package/dist/ui/progress.d.ts.map +1 -0
  299. package/dist/ui/progress.js +24 -0
  300. package/dist/ui/progress.js.map +1 -0
  301. package/dist/ui/prompts.d.ts +14 -0
  302. package/dist/ui/prompts.d.ts.map +1 -0
  303. package/dist/ui/prompts.js +34 -0
  304. package/dist/ui/prompts.js.map +1 -0
  305. package/package.json +5 -2
  306. package/src/app/framework.ts +1 -3
  307. package/src/app/proxy-dev-app.ts +114 -6
  308. package/src/app-config.ts +80 -0
  309. package/src/binary-cache.ts +102 -52
  310. package/src/cli.ts +16 -2
  311. package/src/commands/add.ts +97 -0
  312. package/src/commands/admin.ts +381 -190
  313. package/src/commands/adopt.ts +82 -0
  314. package/src/commands/app.ts +20 -17
  315. package/src/commands/cache.ts +11 -10
  316. package/src/commands/cloud.ts +91 -142
  317. package/src/commands/db.ts +40 -63
  318. package/src/commands/deploy.ts +186 -126
  319. package/src/commands/dev.ts +98 -55
  320. package/src/commands/diff.ts +52 -43
  321. package/src/commands/doctor.ts +103 -0
  322. package/src/commands/engine.ts +5 -4
  323. package/src/commands/functions.ts +187 -123
  324. package/src/commands/generate.ts +5 -4
  325. package/src/commands/init.ts +1087 -104
  326. package/src/commands/introspect.ts +48 -0
  327. package/src/commands/keys.ts +56 -14
  328. package/src/commands/link-helpers.ts +273 -0
  329. package/src/commands/logs.ts +5 -4
  330. package/src/commands/migrate-from-v1.ts +3 -2
  331. package/src/commands/migrate.ts +167 -27
  332. package/src/commands/pg.ts +13 -18
  333. package/src/commands/plugins.ts +55 -46
  334. package/src/commands/pull.ts +38 -9
  335. package/src/commands/push.ts +148 -175
  336. package/src/commands/seed.ts +5 -4
  337. package/src/commands/self-host.ts +85 -54
  338. package/src/commands/self-update.ts +3 -2
  339. package/src/commands/status.ts +102 -33
  340. package/src/commands/types.ts +3 -2
  341. package/src/commands/update.ts +59 -23
  342. package/src/compose-rename.ts +76 -0
  343. package/src/config.ts +2 -1
  344. package/src/dev-compose.ts +462 -76
  345. package/src/dev-log-bus.ts +101 -0
  346. package/src/dev-log-filter.ts +32 -0
  347. package/src/dev-logo.ts +61 -0
  348. package/src/dev-ports.ts +212 -0
  349. package/src/dev-session-lock.ts +101 -0
  350. package/src/dev-session.ts +130 -0
  351. package/src/dev-shutdown.ts +147 -0
  352. package/src/dev-task-colors.ts +47 -0
  353. package/src/dev-tui.ts +232 -0
  354. package/src/diff-output.ts +79 -1
  355. package/src/docker-runtime.ts +151 -0
  356. package/src/engine-client.ts +81 -17
  357. package/src/engine-push-output.ts +75 -0
  358. package/src/ensure-binary.ts +2 -2
  359. package/src/env-file.ts +37 -0
  360. package/src/gitignore.ts +48 -0
  361. package/src/kong-config.ts +24 -1
  362. package/src/link.ts +243 -0
  363. package/src/process-manager.ts +66 -10
  364. package/src/project-config.ts +62 -7
  365. package/src/prompts.ts +2 -0
  366. package/src/pull-utils.ts +217 -23
  367. package/src/resolve-target.ts +419 -0
  368. package/src/restore-system-relation-targets.ts +45 -0
  369. package/src/runtime-routes.ts +7 -0
  370. package/src/schema-ast-v2.ts +2 -1
  371. package/src/schema-sources.ts +248 -0
  372. package/src/scripts/postinstall.ts +7 -1
  373. package/src/self-host-compose.ts +262 -46
  374. package/src/storage-provision.ts +33 -1
  375. package/src/supatype-eval-1781522769253.mts +1 -0
  376. package/src/systemd.ts +2 -2
  377. package/src/target-client.ts +40 -0
  378. package/src/type-extractor.ts +124 -11
  379. package/src/ui/README.md +17 -0
  380. package/src/ui/brand.ts +12 -0
  381. package/src/ui/confirm.ts +38 -0
  382. package/src/ui/fatal.ts +43 -0
  383. package/src/ui/index.ts +8 -0
  384. package/src/ui/interactive.ts +4 -0
  385. package/src/ui/messages.ts +43 -0
  386. package/src/ui/next-steps.ts +10 -0
  387. package/src/ui/progress.ts +28 -0
  388. package/src/ui/prompts.ts +40 -0
  389. package/tests/admin-ensure.test.ts +59 -0
  390. package/tests/cli-help.test.ts +27 -2
  391. package/tests/config.test.ts +29 -2
  392. package/tests/dev-ports.test.ts +41 -0
  393. package/tests/dev-session-lock.test.ts +54 -0
  394. package/tests/dev-ui.test.ts +162 -0
  395. package/tests/docker-runtime.test.ts +236 -0
  396. package/tests/engine-push-output.test.ts +67 -0
  397. package/tests/init.test.ts +197 -18
  398. package/tests/link.test.ts +148 -0
  399. package/tests/minisign.test.ts +102 -0
  400. package/tests/proxy-dev-app.test.ts +45 -1
  401. package/tests/pull-utils.test.ts +5 -4
  402. package/tests/runtime-contract.test.ts +186 -2
  403. package/tests/schema-sources.test.ts +119 -0
  404. package/tests/storage-provision.test.ts +100 -0
  405. package/tests/ui-confirm.test.ts +41 -0
  406. package/tests/ui-messages.test.ts +66 -0
  407. package/tsconfig.tsbuildinfo +1 -1
@@ -3,10 +3,11 @@
3
3
  * colored prefix, and restart on crash with exponential backoff.
4
4
  */
5
5
 
6
- import { type ChildProcess, spawn } from "node:child_process"
6
+ import { type ChildProcess, spawn, spawnSync } from "node:child_process"
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
8
8
  import { unlink } from "node:fs/promises"
9
9
  import { join } from "node:path"
10
+ import { enhanceProcessOptions } from "./dev-session.js"
10
11
 
11
12
  export interface ProcessOptions {
12
13
  /** Human-readable label (used in log prefix and PID filename). */
@@ -27,6 +28,12 @@ export interface ProcessOptions {
27
28
  onExit?: () => void
28
29
  /** Use shell to spawn (required for pnpm/npm/yarn .cmd shims on Windows). */
29
30
  shell?: boolean
31
+ /** When set (TUI mode), receive log lines instead of writing to stdout/stderr. */
32
+ onLine?: (line: string, stream: "stdout" | "stderr") => void
33
+ /** Return false to drop a line before logging. */
34
+ shouldLogLine?: (line: string) => boolean
35
+ /** Called before auto-restart after a non-zero exit (e.g. free a stale port). */
36
+ beforeRestart?: () => void
30
37
  }
31
38
 
32
39
  const RESET = "\x1b[0m"
@@ -35,13 +42,24 @@ export class ProcessManager {
35
42
  private child: ChildProcess | null = null
36
43
  private stopped = false
37
44
  private backoffMs: number
38
- private opts: Required<ProcessOptions>
45
+ private opts: ProcessOptions & {
46
+ colour: string
47
+ cwd: string
48
+ env: Record<string, string>
49
+ initialBackoffMs: number
50
+ maxBackoffMs: number
51
+ onExit: () => void
52
+ shell: boolean
53
+ }
54
+ /** Skip immediate duplicate lines (npm prints script banners to both streams). */
55
+ private lastLoggedLine = ""
39
56
 
40
57
  constructor(
41
58
  private readonly bin: string,
42
59
  private readonly args: string[],
43
60
  opts: ProcessOptions,
44
61
  ) {
62
+ const merged = enhanceProcessOptions(opts.label, opts)
45
63
  this.opts = {
46
64
  colour: "\x1b[36m",
47
65
  cwd: process.cwd(),
@@ -50,7 +68,7 @@ export class ProcessManager {
50
68
  maxBackoffMs: 30_000,
51
69
  onExit: () => {},
52
70
  shell: false,
53
- ...opts,
71
+ ...merged,
54
72
  }
55
73
  this.backoffMs = this.opts.initialBackoffMs
56
74
  }
@@ -64,7 +82,20 @@ export class ProcessManager {
64
82
  /** Stop the process and clear the PID file. */
65
83
  async stop(): Promise<void> {
66
84
  this.stopped = true
67
- if (this.child && !this.child.killed) {
85
+ if (!this.child || this.child.killed) {
86
+ await this.clearPid()
87
+ return
88
+ }
89
+
90
+ const pid = this.child.pid
91
+ if (process.platform === "win32" && this.opts.shell && pid) {
92
+ spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" })
93
+ this.child = null
94
+ await this.clearPid()
95
+ return
96
+ }
97
+
98
+ if (!this.child.killed) {
68
99
  this.child.kill("SIGTERM")
69
100
  // Give it 5s to exit gracefully, then SIGKILL.
70
101
  await new Promise<void>((resolve) => {
@@ -99,22 +130,43 @@ export class ProcessManager {
99
130
  ? `${this.opts.colour}[${this.opts.label}]${RESET} `
100
131
  : `[${this.opts.label}] `
101
132
 
133
+ const logLine = (line: string, stream: NodeJS.WriteStream): void => {
134
+ if (!line) return
135
+ if (this.opts.shouldLogLine && !this.opts.shouldLogLine(line)) return
136
+ if (this.opts.onLine) {
137
+ if (line !== this.lastLoggedLine) {
138
+ this.lastLoggedLine = line
139
+ this.opts.onLine(line, stream === process.stderr ? "stderr" : "stdout")
140
+ }
141
+ return
142
+ }
143
+ if (line === this.lastLoggedLine) return
144
+ this.lastLoggedLine = line
145
+ stream.write(prefix + line + "\n")
146
+ }
147
+
102
148
  this.child.stdout?.on("data", (chunk: Buffer) => {
103
149
  for (const line of chunk.toString().split("\n")) {
104
- if (line) process.stdout.write(prefix + line + "\n")
150
+ logLine(line, process.stdout)
105
151
  }
106
152
  })
107
153
 
108
154
  this.child.stderr?.on("data", (chunk: Buffer) => {
109
155
  for (const line of chunk.toString().split("\n")) {
110
- if (line) process.stderr.write(prefix + line + "\n")
156
+ logLine(line, process.stderr)
111
157
  }
112
158
  })
113
159
 
114
160
  this.child.once("error", (err) => {
115
161
  if (this.stopped) return
116
- process.stderr.write(`${prefix}failed to start: ${err.message}\n`)
162
+ const message = `${prefix}failed to start: ${err.message}\n`
163
+ if (this.opts.onLine) {
164
+ this.opts.onLine(`failed to start: ${err.message}`, "stderr")
165
+ } else {
166
+ process.stderr.write(message)
167
+ }
117
168
  setTimeout(() => {
169
+ this.opts.beforeRestart?.()
118
170
  this.backoffMs = Math.min(this.backoffMs * 2, this.opts.maxBackoffMs)
119
171
  this.spawn()
120
172
  }, this.backoffMs)
@@ -129,11 +181,15 @@ export class ProcessManager {
129
181
  }
130
182
 
131
183
  const reason = signal ? `signal ${signal}` : `code ${code}`
132
- process.stderr.write(
133
- `${prefix}process exited (${reason}), restarting in ${this.backoffMs}ms\n`,
134
- )
184
+ const restartMsg = `${prefix}process exited (${reason}), restarting in ${this.backoffMs}ms\n`
185
+ if (this.opts.onLine) {
186
+ this.opts.onLine(`process exited (${reason}), restarting in ${this.backoffMs}ms`, "stderr")
187
+ } else {
188
+ process.stderr.write(restartMsg)
189
+ }
135
190
 
136
191
  setTimeout(() => {
192
+ this.opts.beforeRestart?.()
137
193
  this.backoffMs = Math.min(this.backoffMs * 2, this.opts.maxBackoffMs)
138
194
  this.spawn()
139
195
  }, this.backoffMs)
@@ -59,6 +59,16 @@ export interface SupatypeProjectConfig {
59
59
  postgrestPort?: number
60
60
  /** Domain for ACME TLS certificate (mode=standalone). */
61
61
  domain?: string
62
+ /**
63
+ * TLS for self-host HTTPS (Kong ACME / Let's Encrypt).
64
+ * Requires `mode: "standalone"` and a non-empty `domain`.
65
+ */
66
+ tls?: {
67
+ /** ACME contact email for Let's Encrypt (required to enable HTTPS). */
68
+ email?: string
69
+ /** "kong" (default) = Kong acme plugin; "none" = stay HTTP even with a domain. */
70
+ provider?: "kong" | "none"
71
+ }
62
72
  }
63
73
  app: {
64
74
  /**
@@ -85,10 +95,13 @@ export interface SupatypeProjectConfig {
85
95
  start?: string
86
96
  }
87
97
  /**
88
- * Pinned binary versions per component. Use **`"local"`** with the matching **`overrides.*`**
89
- * entry when testing a local build (Phase 10.7).
98
+ * Optional pins for engine, server, postgres, and deno.
99
+ * Omitted = resolve latest from CDN at runtime (native) or use Docker :latest.
100
+ * When set, native binaries cache under ~/.supatype/cache/{component}/{version}/
101
+ * and Docker image tags are synced to `.env` on `supatype dev` / `supatype push`.
102
+ * Use **`"local"`** with the matching **`overrides.*`** entry for contributor builds.
90
103
  */
91
- versions: ComponentVersions
104
+ versions?: Partial<ComponentVersions>
92
105
  /**
93
106
  * Override component binaries with local build paths.
94
107
  * Intended for supatype contributors testing local changes.
@@ -198,6 +211,14 @@ export interface SupatypeProjectConfig {
198
211
  /** Custom response headers for the deployed static site. */
199
212
  headers?: Record<string, string>
200
213
  }
214
+ /**
215
+ * Persistent environment defaults for `resolveTarget()` when `--env` is omitted.
216
+ * Ephemeral schema branches (Phase 22) use `.supatype/branch.json`, not this block.
217
+ */
218
+ environments?: {
219
+ default?: string
220
+ branchDefaults?: Record<string, string>
221
+ }
201
222
  /**
202
223
  * Optional Postgres URL for CLI commands that talk to the DB (`push`, `migrate`, …).
203
224
  * When omitted, `DATABASE_URL` from the environment is used, then a local default DSN.
@@ -233,7 +254,9 @@ export function mergeProjectConfig(
233
254
  database: { ...base.database, ...override.database },
234
255
  server: { ...base.server, ...override.server },
235
256
  app: { ...base.app, ...override.app },
236
- versions: { ...base.versions, ...override.versions },
257
+ ...(base.versions !== undefined || override.versions !== undefined
258
+ ? { versions: { ...base.versions, ...override.versions } }
259
+ : {}),
237
260
  ...(base.overrides !== undefined || override.overrides !== undefined
238
261
  ? {
239
262
  overrides: {
@@ -285,6 +308,23 @@ export function mergeProjectConfig(
285
308
  ...(base.admin !== undefined || override.admin !== undefined
286
309
  ? { admin: { ...base.admin, ...override.admin } as NonNullable<SupatypeProjectConfig["admin"]> }
287
310
  : {}),
311
+ ...(base.environments !== undefined || override.environments !== undefined
312
+ ? (() => {
313
+ const b = base.environments
314
+ const o = override.environments
315
+ const mergedBranchDefaults =
316
+ b?.branchDefaults !== undefined || o?.branchDefaults !== undefined
317
+ ? { ...(b?.branchDefaults ?? {}), ...(o?.branchDefaults ?? {}) }
318
+ : undefined
319
+ return {
320
+ environments: {
321
+ ...b,
322
+ ...o,
323
+ ...(mergedBranchDefaults !== undefined ? { branchDefaults: mergedBranchDefaults } : {}),
324
+ } as NonNullable<SupatypeProjectConfig["environments"]>,
325
+ }
326
+ })()
327
+ : {}),
288
328
  }
289
329
  }
290
330
 
@@ -307,9 +347,6 @@ export function validateProjectConfig(raw: unknown, filename: string): SupatypeP
307
347
  if (!cfg["app"]) {
308
348
  throw new Error(`${filename}: app section is required`)
309
349
  }
310
- if (!cfg["versions"]) {
311
- throw new Error(`${filename}: versions section is required`)
312
- }
313
350
 
314
351
  return raw as SupatypeProjectConfig
315
352
  }
@@ -363,6 +400,24 @@ export function serverBaseUrl(cfg: SupatypeProjectConfig): string | undefined {
363
400
  }
364
401
  }
365
402
 
403
+ /**
404
+ * True when `supatype self-host compose` should render Kong ACME TLS (Let's Encrypt).
405
+ * Gated on a real self-host render (not `supatype dev`), standalone mode, a non-empty
406
+ * domain, an ACME contact email, and `tls.provider !== "none"`.
407
+ */
408
+ export function selfHostTlsEnabled(
409
+ cfg: SupatypeProjectConfig,
410
+ devLocal = false,
411
+ ): boolean {
412
+ if (devLocal) return false
413
+ if (cfg.server.mode !== "standalone") return false
414
+ const domain = cfg.server.domain?.trim()
415
+ if (!domain) return false
416
+ const tls = cfg.server.tls
417
+ if (!tls || tls.provider === "none") return false
418
+ return Boolean(tls.email?.trim())
419
+ }
420
+
366
421
  /** Resolved runtime provider (`config.provider` ?? `database.provider` ?? native). */
367
422
  export function resolveRuntimeProvider(cfg: SupatypeProjectConfig): "native" | "docker" {
368
423
  return cfg.provider ?? cfg.database.provider ?? "native"
package/src/prompts.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** @deprecated Import from `./ui/prompts.js` or `./ui/index.js`. */
2
+ export { printLogo, ensureNotCancelled, clack } from "./ui/prompts.js"
package/src/pull-utils.ts CHANGED
@@ -1,41 +1,237 @@
1
1
  /**
2
- * Utilities for the `pull` commandextracted for unit testability.
2
+ * Utilities for `pull` and `introspect` map engine DatabaseState to Model<> scaffold.
3
3
  */
4
4
 
5
- export interface ColumnInfo {
5
+ export interface DbColumnState {
6
6
  name: string
7
- pgType: string
7
+ dataType: string
8
+ udtName: string
8
9
  nullable: boolean
10
+ default?: string | null
11
+ ordinalPosition?: number
12
+ }
13
+
14
+ export interface DbTableState {
15
+ schema?: string
16
+ name: string
17
+ columns: DbColumnState[]
18
+ }
19
+
20
+ export interface DbConstraintState {
21
+ table: string
22
+ name: string
23
+ constraintType: string
24
+ columns: string[]
25
+ foreignTable?: string | null
26
+ foreignColumns?: string[] | null
27
+ comment?: string | null
28
+ }
29
+
30
+ export interface DbIndexState {
31
+ table: string
32
+ name: string
33
+ columns: string[]
34
+ unique: boolean
35
+ method: string
9
36
  isPrimary: boolean
10
- isUnique: boolean
11
- hasDefault: boolean
37
+ comment?: string | null
12
38
  }
13
39
 
14
- /** Engine `/introspect` column shape (see {@link IntrospectResult} in engine-client). */
15
- export interface IntrospectColumn {
40
+ export interface DatabaseStateJson {
41
+ schema?: string
42
+ tables: DbTableState[]
43
+ constraints?: DbConstraintState[]
44
+ indexes?: DbIndexState[]
45
+ }
46
+
47
+ export interface ColumnInfo {
16
48
  name: string
17
- type: string
49
+ pgType: string
18
50
  nullable: boolean
19
- default?: string
20
- primaryKey?: boolean
21
- unique?: boolean
51
+ isPrimary: boolean
52
+ isUnique: boolean
53
+ hasDefault: boolean
22
54
  references?: { table: string; column: string }
23
55
  }
24
56
 
25
- /** Map engine introspection JSON to {@link ColumnInfo} for {@link pgTypeToField}. */
26
- export function introspectColumnToColumnInfo(col: IntrospectColumn): ColumnInfo {
27
- const def = col.default
57
+ /** Map engine introspection column to {@link ColumnInfo}. */
58
+ export function introspectColumnToColumnInfo(col: DbColumnState): ColumnInfo {
28
59
  return {
29
60
  name: col.name,
30
- pgType: col.type,
61
+ pgType: col.udtName || col.dataType,
31
62
  nullable: col.nullable,
32
- isPrimary: col.primaryKey ?? false,
33
- isUnique: col.unique ?? false,
34
- hasDefault: def !== undefined && def !== "",
63
+ isPrimary: col.name === "id" && (col.udtName === "uuid" || col.dataType.includes("uuid")),
64
+ isUnique: false,
65
+ hasDefault: col.default != null && col.default !== "",
66
+ }
67
+ }
68
+
69
+ function singleColumnUniques(
70
+ table: string,
71
+ constraints: DbConstraintState[] | undefined,
72
+ ): Map<string, boolean> {
73
+ const out = new Map<string, boolean>()
74
+ for (const c of constraints ?? []) {
75
+ if (c.table !== table || c.constraintType !== "unique" || c.columns.length !== 1) continue
76
+ out.set(c.columns[0]!, true)
35
77
  }
78
+ return out
36
79
  }
37
80
 
38
- /** Map a Postgres column type to the corresponding field.X() call string. */
81
+ function compositeIndexes(
82
+ table: string,
83
+ indexes: DbIndexState[] | undefined,
84
+ ): Array<{ fields: string[]; unique: boolean }> {
85
+ const out: Array<{ fields: string[]; unique: boolean }> = []
86
+ for (const idx of indexes ?? []) {
87
+ if (idx.table !== table || idx.isPrimary || idx.columns.length < 2) continue
88
+ out.push({ fields: idx.columns, unique: idx.unique })
89
+ }
90
+ return out
91
+ }
92
+
93
+ /** Map a Postgres column to a Model<> field type string (draft). */
94
+ export function pgTypeToModelField(col: ColumnInfo): string {
95
+ const name = col.name
96
+ const type = col.pgType.toLowerCase()
97
+ const optional = col.nullable ? "Optional<" : ""
98
+ const optionalClose = col.nullable ? ">" : ""
99
+
100
+ if (name === "id" && type.includes("uuid")) {
101
+ return `id: SupatypeAuthUserId`
102
+ }
103
+ if (name.endsWith("_id") && type.includes("uuid")) {
104
+ const base = name.replace(/_id$/, "")
105
+ const rel = base.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase())
106
+ const relName = rel.charAt(0).toUpperCase() + rel.slice(1)
107
+ return `${name}: UUID\n // TODO: relation — RelatedTo<"${relName}">`
108
+ }
109
+ if (name === "created_at" || name === "updated_at") {
110
+ return `${name}: Timestamp`
111
+ }
112
+ if (name === "deleted_at") {
113
+ return `${name}: Optional<Timestamp>`
114
+ }
115
+ if (type.includes("timestamptz") || type.includes("timestamp with time zone")) {
116
+ return `${name}: ${optional}Timestamp${optionalClose}`
117
+ }
118
+ if (type.includes("uuid")) {
119
+ const inner = col.isUnique ? "Unique<UUID>" : "UUID"
120
+ return `${name}: ${optional}${inner}${optionalClose}`
121
+ }
122
+ if (name.includes("email") && (type.includes("text") || type.includes("varchar"))) {
123
+ const inner = col.isUnique ? "Unique<Email>" : "Email"
124
+ return `${name}: ${optional}${inner}${optionalClose}`
125
+ }
126
+ if (name === "slug" || name.endsWith("_slug")) {
127
+ return `${name}: Slug<"title">`
128
+ }
129
+ if (type.includes("jsonb")) {
130
+ return `${name}: ${optional}JSON${optionalClose}`
131
+ }
132
+ if (type.includes("bool")) {
133
+ return `${name}: ${optional}boolean${optionalClose}`
134
+ }
135
+ if (type.includes("int8") || type.includes("bigint")) {
136
+ return `${name}: ${optional}BigInt${optionalClose}`
137
+ }
138
+ if (type.includes("int")) {
139
+ return `${name}: ${optional}Int${optionalClose}`
140
+ }
141
+ if (type.includes("text") || type.includes("varchar")) {
142
+ const inner = col.isUnique ? "Unique<string>" : "string"
143
+ return `${name}: ${optional}${inner}${optionalClose}`
144
+ }
145
+
146
+ return `${name}: string /* TODO: ${col.pgType} */`
147
+ }
148
+
149
+ /** Convert snake_case table name to PascalCase model export name. */
150
+ export function toModelName(s: string): string {
151
+ return s
152
+ .replace(/_([a-z])/g, (_, c: string) => c.toUpperCase())
153
+ .replace(/^([a-z])/, (c: string) => c.toUpperCase())
154
+ }
155
+
156
+ /** Generate draft schema/index.ts content from introspected DatabaseState. */
157
+ export function databaseStateToSchemaScaffold(state: DatabaseStateJson): string {
158
+ const constraints = state.constraints ?? []
159
+ const indexes = state.indexes ?? []
160
+ const skipTables = new Set(["spatial_ref_sys", "schema_migrations"])
161
+
162
+ const lines: string[] = [
163
+ "// DRAFT — generated by `supatype pull`. Review access rules, relations, and indexes before push.",
164
+ 'import type { Model, Public, UUID, Timestamp, Optional, Unique, Email, Slug, SupatypeAuthUserId, JSON, Int, BigInt } from "@supatype/types"',
165
+ "",
166
+ ]
167
+
168
+ for (const table of state.tables) {
169
+ if (skipTables.has(table.name) || table.name.startsWith("_")) continue
170
+
171
+ const modelName = toModelName(table.name)
172
+ const uniques = singleColumnUniques(table.name, constraints)
173
+ const modelIndexes = compositeIndexes(table.name, indexes)
174
+
175
+ const fieldLines: string[] = []
176
+ for (const col of table.columns) {
177
+ if (col.name === "created_at" || col.name === "updated_at") continue
178
+ const info = introspectColumnToColumnInfo(col)
179
+ info.isPrimary = col.name === "id"
180
+ info.isUnique = uniques.get(col.name) ?? false
181
+ fieldLines.push(` ${pgTypeToModelField(info)}`)
182
+ }
183
+
184
+ const hasTimestamps = table.columns.some((c) => c.name === "created_at")
185
+ if (hasTimestamps) {
186
+ fieldLines.push(" created_at: Timestamp")
187
+ fieldLines.push(" updated_at: Timestamp")
188
+ }
189
+
190
+ const indexBlock =
191
+ modelIndexes.length > 0
192
+ ? `\n indexes: [\n${modelIndexes
193
+ .map(
194
+ (idx) =>
195
+ ` { fields: [${idx.fields.map((f) => `"${f}"`).join(", ")}]${idx.unique ? ", unique: true" : ""} },`,
196
+ )
197
+ .join("\n")}\n ],`
198
+ : ""
199
+
200
+ lines.push(`export type ${modelName} = Model<{`)
201
+ lines.push(fieldLines.join("\n"))
202
+ lines.push(`}, {`)
203
+ lines.push(` access: {`)
204
+ lines.push(` read: Public`)
205
+ lines.push(` create: Public`)
206
+ lines.push(` update: Public`)
207
+ lines.push(` delete: Public`)
208
+ lines.push(` },${indexBlock}`)
209
+ lines.push(`}>`)
210
+ lines.push("")
211
+ }
212
+
213
+ return lines.join("\n")
214
+ }
215
+
216
+ /** Human-readable introspection summary for `supatype introspect`. */
217
+ export function printIntrospectSummary(state: DatabaseStateJson): void {
218
+ console.log(`Schema: ${state.schema ?? "public"}`)
219
+ console.log(`Tables: ${state.tables.length}`)
220
+ for (const table of state.tables) {
221
+ console.log(`\n ${table.name} (${table.columns.length} columns)`)
222
+ for (const col of table.columns) {
223
+ const nullMark = col.nullable ? "?" : ""
224
+ console.log(` ${col.name}${nullMark}: ${col.udtName || col.dataType}`)
225
+ }
226
+ }
227
+ const constraintCount = state.constraints?.length ?? 0
228
+ const indexCount = state.indexes?.length ?? 0
229
+ if (constraintCount + indexCount > 0) {
230
+ console.log(`\nConstraints: ${constraintCount}, Indexes: ${indexCount}`)
231
+ }
232
+ }
233
+
234
+ /** @deprecated Legacy pull helper — use {@link pgTypeToModelField}. */
39
235
  export function pgTypeToField(col: ColumnInfo): string {
40
236
  const opts: Record<string, unknown> = { required: !col.nullable }
41
237
  if (col.isPrimary) opts["primaryKey"] = true
@@ -73,9 +269,7 @@ export function pgTypeToField(col: ColumnInfo): string {
73
269
  return `field.text({ ...${optsStr} }) /* TODO: ${col.pgType} */`
74
270
  }
75
271
 
76
- /** Convert snake_case table name to PascalCase model export name. */
272
+ /** @deprecated Use {@link toModelName}. */
77
273
  export function toCamelCase(s: string): string {
78
- return s
79
- .replace(/_([a-z])/g, (_, c: string) => c.toUpperCase())
80
- .replace(/^([a-z])/, (c: string) => c.toUpperCase())
274
+ return toModelName(s)
81
275
  }