@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
@@ -1,54 +1,51 @@
1
1
  /**
2
2
  * `supatype dev` when `provider: docker` — full self-host Compose stack (Kong gateway).
3
3
  */
4
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
5
  import { homedir } from "node:os";
6
6
  import { dirname, join, resolve } from "node:path";
7
7
  import { spawnSync } from "node:child_process";
8
8
  import { startProxyDevApp } from "./app/proxy-dev-app.js";
9
9
  import { loadSchemaAst } from "./config.js";
10
- import { COMPOSE_DEV_KONG_PORT, projectRootFromConfig, resolveRuntimeProvider, schemaPathFromProject, } from "./project-config.js";
10
+ import { connectionString, projectRootFromConfig, resolveRuntimeProvider, schemaPathFromProject, } from "./project-config.js";
11
11
  import { signJwt } from "./jwt.js";
12
- import { isPortInUse } from "./postgres-ctl.js";
13
- import { composeProjectName, runDockerCompose, writeSelfHostCompose } from "./self-host-compose.js";
12
+ import { ensureDevDbPort, ensureKongPort } from "./dev-ports.js";
13
+ import { handleComposeProjectRename } from "./compose-rename.js";
14
+ import { recoverStaleDevSession, writeDevSessionLock } from "./dev-session-lock.js";
15
+ import { readEnvValue, upsertEnvFile } from "./env-file.js";
16
+ import { COMPOSE_PINNED_IMAGE_ENV_KEYS, composeDockerImageEnv, composeProjectName, exitComposeFailed, runDockerCompose, schemaEngineImageForPush, writeSelfHostCompose, } from "./self-host-compose.js";
14
17
  import { hasEngineOverride } from "./binary-cache.js";
15
18
  import { startStudioViteDevServer } from "./studio-dev-server.js";
16
19
  import { ensureEngine, engineRequest } from "./engine-client.js";
20
+ import { writeSchemaSourcePushArtifacts } from "./schema-sources.js";
21
+ import { endDevSession } from "./dev-session.js";
22
+ import { writeLocalEnvironment } from "./link.js";
23
+ import { registerDevShutdown } from "./dev-shutdown.js";
24
+ import { filterComposeNoise, formatEnginePushMessage, parseEngineJsonOutput, parseEnginePushOutput, } from "./engine-push-output.js";
17
25
  import { withAdminRoles } from "./studio-admin-roles.js";
26
+ import { restoreSystemRelationTargets } from "./restore-system-relation-targets.js";
27
+ import { provisionBucketsFromAst } from "./storage-provision.js";
28
+ import { ensureFirstAdminUserForProject } from "./commands/admin.js";
18
29
  const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long";
19
30
  /** Default host port for compose Postgres when `overrides.engine` is set (devLocal). */
20
31
  const COMPOSE_DEV_DB_PORT = 54329;
32
+ /** Sync optional Docker image pins from config into `.env` (no JWT rotation). */
33
+ export function syncComposeImagePins(cwd, config) {
34
+ const imagePins = composeDockerImageEnv(config);
35
+ const removeImageKeys = COMPOSE_PINNED_IMAGE_ENV_KEYS.filter((key) => !(key in imagePins));
36
+ upsertEnvFile(cwd, imagePins, removeImageKeys);
37
+ }
21
38
  /** In-compose Postgres URL (SCRAM; not published to the host). */
22
39
  export function composeDbUrl() {
23
40
  return "postgresql://supatype_admin:postgres@db:5432/supatype?sslmode=disable";
24
41
  }
25
42
  /**
26
43
  * Resolve the host Kong port for this project. Persisted in `.env` as
27
- * SUPATYPE_KONG_PORT so re-runs are stable; on first run it picks the default
28
- * (18473) or the next free port, so multiple projects can run concurrently.
44
+ * SUPATYPE_KONG_PORT; prompts when the configured port is already taken.
29
45
  */
30
46
  async function resolveDevDbPort(cwd) {
31
- const envPath = join(cwd, ".env");
32
- if (existsSync(envPath)) {
33
- const m = readFileSync(envPath, "utf8").match(/^SUPATYPE_DEV_DB_PORT=(\d+)/m);
34
- if (m && m[1])
35
- return Number(m[1]);
36
- }
37
- let port = COMPOSE_DEV_DB_PORT;
38
- while (await isPortInUse(port))
39
- port++;
40
- return port;
41
- }
42
- function readEnvValue(cwd, key, fallback) {
43
- const envPath = join(cwd, ".env");
44
- if (existsSync(envPath)) {
45
- const m = readFileSync(envPath, "utf8").match(new RegExp(`^${key}=(.+)$`, "m"));
46
- if (m?.[1])
47
- return m[1].trim();
48
- }
49
- return fallback;
47
+ return ensureDevDbPort(cwd);
50
48
  }
51
- /** Postgres DSN for compose db when published to the host (local engine push). */
52
49
  function hostComposeDbUrl(cwd) {
53
50
  const port = readEnvValue(cwd, "SUPATYPE_DEV_DB_PORT", String(COMPOSE_DEV_DB_PORT));
54
51
  const user = readEnvValue(cwd, "POSTGRES_USER", "supatype_admin");
@@ -56,34 +53,69 @@ function hostComposeDbUrl(cwd) {
56
53
  const db = readEnvValue(cwd, "POSTGRES_DB", "supatype");
57
54
  return `postgresql://${user}:${pass}@127.0.0.1:${port}/${db}?sslmode=disable`;
58
55
  }
59
- async function resolveKongPort(cwd) {
60
- const envPath = join(cwd, ".env");
61
- if (existsSync(envPath)) {
62
- const m = readFileSync(envPath, "utf8").match(/^SUPATYPE_KONG_PORT=(\d+)/m);
63
- if (m && m[1])
64
- return Number(m[1]);
65
- }
66
- let port = COMPOSE_DEV_KONG_PORT;
67
- while (await isPortInUse(port))
68
- port++;
69
- return port;
70
- }
71
- function upsertEnvFile(cwd, updates) {
72
- const envPath = join(cwd, ".env");
73
- const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
74
- const keys = new Set(Object.keys(updates));
75
- const kept = existing
76
- .split("\n")
77
- .filter((line) => {
78
- const key = line.split("=")[0]?.trim();
79
- return key && line.includes("=") && !keys.has(key);
56
+ /**
57
+ * When `provider: docker` and `overrides.engine` is set, ensure Postgres is published
58
+ * on the host (SUPATYPE_DEV_DB_PORT) so the local engine binary can connect.
59
+ */
60
+ export async function ensureDockerDbPublishedForHostEngine(cwd, config, brand) {
61
+ if (resolveRuntimeProvider(config) !== "docker") {
62
+ throw new Error("ensureDockerDbPublishedForHostEngine requires provider: docker");
63
+ }
64
+ if (!hasEngineOverride(config)) {
65
+ throw new Error("Docker Postgres is not published to the host without overrides.engine. " +
66
+ "Set overrides.engine in supatype.local.config.ts or pass --connection.");
67
+ }
68
+ const project = composeProjectName(config.project.name);
69
+ const kongPort = await resolveKongPort(cwd);
70
+ const devDbPort = await resolveDevDbPort(cwd);
71
+ const now = Math.floor(Date.now() / 1000);
72
+ const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 };
73
+ const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET);
74
+ const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET);
75
+ ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort);
76
+ const paths = writeSelfHostCompose(cwd, config, { devLocal: true });
77
+ const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
78
+ quiet: true,
79
+ ...(brand !== undefined && { brand }),
80
80
  });
81
- const merged = [...kept, ...Object.entries(updates).map(([key, value]) => `${key}=${value}`)];
82
- writeFileSync(envPath, `${merged.join("\n").trimEnd()}\n`, "utf8");
81
+ if (up !== 0) {
82
+ exitComposeFailed(up, "Could not start Postgres (compose db service).", brand);
83
+ }
84
+ await waitComposeHealthy(paths, cwd, 120_000, project);
85
+ }
86
+ /**
87
+ * True when CLI should publish local Compose Postgres for the host-side engine
88
+ * (local dev with overrides.engine). False for remote DB URLs via config or --connection.
89
+ */
90
+ export function usesLocalDockerEngineDb(config, explicitConnection) {
91
+ if (explicitConnection?.trim())
92
+ return false;
93
+ if (config.connection?.trim())
94
+ return false;
95
+ return resolveRuntimeProvider(config) === "docker" && hasEngineOverride(config);
96
+ }
97
+ /**
98
+ * Resolve a Postgres URL reachable from the host-side engine binary.
99
+ * Local docker + overrides.engine → SUPATYPE_DEV_DB_PORT on localhost.
100
+ * Remote self-host → set `connection` in config or pass `--connection`.
101
+ */
102
+ export async function resolveHostEngineDatabaseUrl(cwd, config, explicit) {
103
+ if (explicit?.trim())
104
+ return explicit;
105
+ if (config.connection?.trim())
106
+ return config.connection;
107
+ if (usesLocalDockerEngineDb(config)) {
108
+ await ensureDockerDbPublishedForHostEngine(cwd, config);
109
+ return hostComposeDbUrl(cwd);
110
+ }
111
+ return connectionString(config);
83
112
  }
84
- /** Keep compose + Studio + Astro on the same freshly signed dev JWTs every `dev` / `push`. */
85
- function ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort) {
113
+ async function resolveKongPort(cwd) {
114
+ return ensureKongPort(cwd, { context: "dev" });
115
+ }
116
+ function upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort) {
86
117
  const apiUrl = `http://localhost:${kongPort}`;
118
+ const imagePins = composeDockerImageEnv(config);
87
119
  const updates = {
88
120
  POSTGRES_USER: "supatype_admin",
89
121
  POSTGRES_PASSWORD: "postgres",
@@ -92,16 +124,25 @@ function ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort)
92
124
  ANON_KEY: anonKey,
93
125
  SERVICE_ROLE_KEY: serviceRoleKey,
94
126
  PUBLIC_SUPATYPE_ANON_KEY: anonKey,
127
+ VITE_SUPATYPE_ANON_KEY: anonKey,
95
128
  PUBLIC_SUPATYPE_URL: apiUrl,
96
129
  SUPATYPE_KONG_PORT: String(kongPort),
97
130
  API_EXTERNAL_URL: apiUrl,
98
131
  SITE_URL: apiUrl,
99
132
  GOTRUE_MAILER_AUTOCONFIRM: "true",
133
+ ...imagePins,
100
134
  };
101
135
  if (devDbPort !== undefined) {
102
136
  updates.SUPATYPE_DEV_DB_PORT = String(devDbPort);
137
+ updates.DATABASE_URL =
138
+ `postgresql://supatype_admin:postgres@localhost:${devDbPort}/supatype?sslmode=disable`;
103
139
  }
104
- upsertEnvFile(cwd, updates);
140
+ const removeImageKeys = COMPOSE_PINNED_IMAGE_ENV_KEYS.filter((key) => !(key in imagePins));
141
+ upsertEnvFile(cwd, updates, removeImageKeys);
142
+ }
143
+ /** Keep compose + Studio on the same freshly signed dev JWTs; sync optional image pins from config. */
144
+ function ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort) {
145
+ upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort);
105
146
  }
106
147
  async function waitComposeHealthy(paths, cwd, maxMs, composeProject) {
107
148
  const composeDir = dirname(paths.composePath);
@@ -133,8 +174,13 @@ async function waitKongReady(kongPort, maxSec) {
133
174
  }
134
175
  throw new Error(`Kong gateway at ${base} did not become ready within ${maxSec}s`);
135
176
  }
177
+ async function provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey) {
178
+ await provisionBucketsFromAst(ast, `http://localhost:${kongPort}/storage/v1`, serviceRoleKey);
179
+ }
136
180
  let _lastPushedAst = null;
137
181
  let _lastFailedAst = null;
182
+ let _composePushInFlight = false;
183
+ let _composePushQueued = false;
138
184
  /**
139
185
  * Regenerate admin-config + TypeScript types from the AST using the **host** engine.
140
186
  * Only schema push/migrate runs in compose (Postgres is not on the host).
@@ -175,6 +221,7 @@ async function refreshSchemaArtifacts(cwd, config, ast) {
175
221
  }
176
222
  try {
177
223
  const admin = withAdminRoles(await engineRequest("/admin", { ast }), config);
224
+ restoreSystemRelationTargets(admin, ast);
178
225
  writeFileSync(adminConfigPath, `${JSON.stringify(admin, null, 2)}\n`);
179
226
  console.log("[supatype] Admin config written to .supatype/admin-config.json");
180
227
  }
@@ -202,12 +249,19 @@ async function runComposeSchemaPush(cwd, config, paths, schemaPath, composeProje
202
249
  console.log("[supatype] Applying schema via local engine (overrides.engine)...");
203
250
  await ensureEngine();
204
251
  const pgSchema = config.schema?.pg_schema ?? "public";
252
+ const sources = writeSchemaSourcePushArtifacts(cwd);
205
253
  try {
206
254
  await engineRequest("/push", {
207
255
  ast,
208
256
  database_url: hostComposeDbUrl(cwd),
209
257
  schema: pgSchema,
210
258
  force: true,
259
+ ...(sources
260
+ ? {
261
+ schema_sources_gz_base64: sources.payload.dataBase64,
262
+ schema_sources_manifest: sources.payload.manifest,
263
+ }
264
+ : {}),
211
265
  });
212
266
  }
213
267
  catch (err) {
@@ -216,27 +270,51 @@ async function runComposeSchemaPush(cwd, config, paths, schemaPath, composeProje
216
270
  }
217
271
  _lastPushedAst = astJson;
218
272
  _lastFailedAst = null;
273
+ if (astHasSystemAuthRelation(ast)) {
274
+ grantAuthSchemaAccess(paths, cwd, composeProject);
275
+ }
219
276
  console.log("[supatype] Schema applied.");
220
277
  return;
221
278
  }
222
279
  console.log("[supatype] Applying schema via compose schema-engine...");
223
- let push = runComposeEnginePush(paths, cwd, composeProject);
280
+ const sources = writeSchemaSourcePushArtifacts(cwd);
281
+ let push = await runComposeEnginePush(paths, cwd, composeProject, config, sources);
224
282
  // Windows Docker bind mounts can lag briefly after the host write.
225
283
  if (push.status !== 0) {
226
284
  await new Promise((r) => setTimeout(r, 250));
227
- push = runComposeEnginePush(paths, cwd, composeProject);
285
+ push = await runComposeEnginePush(paths, cwd, composeProject, config, sources);
228
286
  }
229
287
  if (push.status !== 0) {
230
288
  _lastFailedAst = astJson;
231
- throw new Error(push.output || `Engine schema push failed (exit ${push.status})`);
289
+ const detail = filterComposeNoise(push.output) || push.output;
290
+ throw new Error(detail || `Engine schema push failed (exit ${push.status})`);
232
291
  }
233
292
  _lastPushedAst = astJson;
234
293
  _lastFailedAst = null;
235
- console.log("[supatype] Schema applied.");
294
+ if (astHasSystemAuthRelation(ast)) {
295
+ grantAuthSchemaAccess(paths, cwd, composeProject);
296
+ }
297
+ }
298
+ /** Serialize watch-triggered pushes so docker output cannot interleave. */
299
+ async function runComposeSchemaPushQueued(cwd, config, paths, schemaPath, composeProject) {
300
+ if (_composePushInFlight) {
301
+ _composePushQueued = true;
302
+ return;
303
+ }
304
+ _composePushInFlight = true;
305
+ try {
306
+ do {
307
+ _composePushQueued = false;
308
+ await runComposeSchemaPush(cwd, config, paths, schemaPath, composeProject);
309
+ } while (_composePushQueued);
310
+ }
311
+ finally {
312
+ _composePushInFlight = false;
313
+ }
236
314
  }
237
- function runComposeEnginePush(paths, cwd, composeProject) {
315
+ async function runComposeEnginePush(paths, cwd, composeProject, config, sources) {
238
316
  const envFile = resolve(cwd, ".env");
239
- const composeArgs = ["compose"];
317
+ const composeArgs = ["compose", "--progress", "quiet"];
240
318
  if (composeProject)
241
319
  composeArgs.push("-p", composeProject);
242
320
  composeArgs.push("--project-directory", cwd);
@@ -245,16 +323,125 @@ function runComposeEnginePush(paths, cwd, composeProject) {
245
323
  composeArgs.push("--env-file", envFile);
246
324
  }
247
325
  composeArgs.push("--profile", "tools", "run", "--rm", "schema-engine", "push", "-i", "/project/.supatype/schema.ast.json", "--database-url", composeDbUrl(), "--force", "--non-interactive");
326
+ if (sources) {
327
+ composeArgs.push("--schema-sources-gz", sources.dockerGzPath, "--schema-sources-manifest", sources.dockerManifestPath);
328
+ }
329
+ const pushEnv = {
330
+ ...process.env,
331
+ COMPOSE_PROGRESS: "quiet",
332
+ };
333
+ const engineImage = await schemaEngineImageForPush(config);
334
+ if (engineImage) {
335
+ pushEnv.SUPATYPE_ENGINE_IMAGE = engineImage;
336
+ }
248
337
  const result = spawnSync("docker", composeArgs, {
249
338
  cwd,
250
339
  encoding: "utf8",
251
340
  maxBuffer: 10 * 1024 * 1024,
341
+ env: pushEnv,
252
342
  });
253
343
  const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
254
- if (output.length > 0) {
255
- console.error(output);
344
+ const exitStatus = result.status ?? 1;
345
+ const pushResult = parseEnginePushOutput(output);
346
+ if (exitStatus === 0) {
347
+ if (pushResult) {
348
+ console.log(`[supatype] ${formatEnginePushMessage(pushResult)}`);
349
+ }
350
+ else {
351
+ console.log("[supatype] Schema applied.");
352
+ }
256
353
  }
257
- return { status: result.status ?? 1, output };
354
+ return { status: exitStatus, output };
355
+ }
356
+ async function runComposeEngineDiff(paths, cwd, composeProject, config, pgSchema) {
357
+ const envFile = resolve(cwd, ".env");
358
+ const composeArgs = ["compose", "--progress", "quiet"];
359
+ if (composeProject)
360
+ composeArgs.push("-p", composeProject);
361
+ composeArgs.push("--project-directory", cwd);
362
+ composeArgs.push("-f", paths.composePath);
363
+ if (existsSync(envFile)) {
364
+ composeArgs.push("--env-file", envFile);
365
+ }
366
+ composeArgs.push("--profile", "tools", "run", "--rm", "schema-engine", "diff", "-i", "/project/.supatype/schema.ast.json", "--database-url", composeDbUrl(), "--schema", pgSchema);
367
+ const diffEnv = {
368
+ ...process.env,
369
+ COMPOSE_PROGRESS: "quiet",
370
+ };
371
+ const engineImage = await schemaEngineImageForPush(config);
372
+ if (engineImage) {
373
+ diffEnv.SUPATYPE_ENGINE_IMAGE = engineImage;
374
+ }
375
+ const result = spawnSync("docker", composeArgs, {
376
+ cwd,
377
+ encoding: "utf8",
378
+ maxBuffer: 10 * 1024 * 1024,
379
+ env: diffEnv,
380
+ });
381
+ const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
382
+ const exitStatus = result.status ?? 1;
383
+ const diff = parseEngineJsonOutput(output);
384
+ return { status: exitStatus, output, diff };
385
+ }
386
+ /**
387
+ * `supatype diff` when `provider: docker`. Uses in-compose schema-engine unless
388
+ * `overrides.engine` is set — then Postgres is published to the host and diff runs
389
+ * through the local engine binary.
390
+ */
391
+ export async function diffSchemaDocker(cwd, config) {
392
+ if (resolveRuntimeProvider(config) !== "docker") {
393
+ throw new Error("diffSchemaDocker requires provider: docker");
394
+ }
395
+ const project = composeProjectName(config.project.name);
396
+ const pgSchema = config.schema?.pg_schema ?? "public";
397
+ if (hasEngineOverride(config)) {
398
+ const brand = { intro: "Schema diff" };
399
+ await ensureDockerDbPublishedForHostEngine(cwd, config, brand);
400
+ const schemaPath = schemaPathFromProject(config, cwd);
401
+ const ast = loadSchemaAst(schemaPath, cwd);
402
+ await ensureEngine();
403
+ return engineRequest("/diff", {
404
+ ast,
405
+ database_url: hostComposeDbUrl(cwd),
406
+ schema: pgSchema,
407
+ });
408
+ }
409
+ const kongPort = await resolveKongPort(cwd);
410
+ const now = Math.floor(Date.now() / 1000);
411
+ const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 };
412
+ const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET);
413
+ const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET);
414
+ ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, undefined);
415
+ const paths = writeSelfHostCompose(cwd, config, { devLocal: true });
416
+ const diffBrand = { intro: "Schema diff" };
417
+ const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
418
+ quiet: true,
419
+ brand: diffBrand,
420
+ });
421
+ if (up !== 0) {
422
+ exitComposeFailed(up, "Could not start Postgres (compose db service).", diffBrand);
423
+ }
424
+ await waitComposeHealthy(paths, cwd, 120_000, project);
425
+ const schemaPath = schemaPathFromProject(config, cwd);
426
+ const ast = loadSchemaAst(schemaPath, cwd);
427
+ const supatypeDir = join(cwd, ".supatype");
428
+ mkdirSync(supatypeDir, { recursive: true });
429
+ const astPath = join(supatypeDir, "schema.ast.json");
430
+ writeFileSync(astPath, JSON.stringify(ast));
431
+ let result = await runComposeEngineDiff(paths, cwd, project, config, pgSchema);
432
+ // Windows Docker bind mounts can lag briefly after the host write.
433
+ if (result.status !== 0) {
434
+ await new Promise((r) => setTimeout(r, 250));
435
+ result = await runComposeEngineDiff(paths, cwd, project, config, pgSchema);
436
+ }
437
+ if (result.status !== 0) {
438
+ const detail = filterComposeNoise(result.output) || result.output;
439
+ throw new Error(detail || `Engine schema diff failed (exit ${result.status})`);
440
+ }
441
+ if (!result.diff) {
442
+ throw new Error("Engine diff returned no result");
443
+ }
444
+ return result.diff;
258
445
  }
259
446
  /**
260
447
  * `supatype push` when `provider: docker`. Uses in-compose schema-engine unless
@@ -272,15 +459,33 @@ export async function pushSchemaDocker(cwd, config) {
272
459
  const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 };
273
460
  const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET);
274
461
  const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET);
275
- ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort);
462
+ ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort);
276
463
  const paths = writeSelfHostCompose(cwd, config, { devLocal: true });
464
+ const pushBrand = { intro: "Push schema" };
277
465
  console.log(`[supatype] provider: docker — applying schema via compose (project ${project})...`);
278
- const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project);
279
- if (up !== 0)
280
- process.exit(up);
466
+ const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
467
+ quiet: true,
468
+ brand: pushBrand,
469
+ });
470
+ if (up !== 0) {
471
+ exitComposeFailed(up, "Could not start Postgres (compose db service).", pushBrand);
472
+ }
281
473
  await waitComposeHealthy(paths, cwd, 120_000, project);
282
474
  const schemaPath = schemaPathFromProject(config, cwd);
475
+ const ast = loadSchemaAst(schemaPath, cwd);
283
476
  await runComposeSchemaPush(cwd, config, paths, schemaPath, project);
477
+ const upGateway = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
478
+ quiet: true,
479
+ brand: pushBrand,
480
+ });
481
+ if (upGateway !== 0) {
482
+ exitComposeFailed(upGateway, "Could not start the Compose gateway stack.", pushBrand);
483
+ }
484
+ await waitKongReady(kongPort, 120);
485
+ await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey);
486
+ await ensureFirstAdminUserForProject(cwd, config, {
487
+ compose: { project, composePath: paths.composePath },
488
+ });
284
489
  console.log("[supatype] Schema pushed.");
285
490
  }
286
491
  export async function runDevCompose(cwd, config, opts) {
@@ -296,18 +501,46 @@ export async function runDevCompose(cwd, config, opts) {
296
501
  const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 };
297
502
  const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET);
298
503
  const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET);
299
- ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort);
504
+ ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort);
300
505
  console.log(`[supatype] provider: docker — starting self-host Compose stack (project ${project}, gateway :${kongPort})...`);
301
506
  const paths = writeSelfHostCompose(cwd, config, { devLocal: true });
302
- const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project);
303
- if (upStatus !== 0)
304
- process.exit(upStatus);
507
+ await recoverStaleDevSession(cwd);
508
+ await handleComposeProjectRename(cwd, config.project.name, paths);
509
+ const devBrand = { intro: "Local development" };
510
+ const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
511
+ quiet: true,
512
+ brand: devBrand,
513
+ });
514
+ if (upStatus !== 0) {
515
+ endDevSession();
516
+ exitComposeFailed(upStatus, "Could not start the local Compose stack.", devBrand);
517
+ }
305
518
  console.log("[supatype] Waiting for Postgres (compose)...");
306
519
  await waitComposeHealthy(paths, cwd, 180_000, project);
307
520
  const schemaPath = schemaPathFromProject(config, cwd);
308
521
  await runComposeSchemaPush(cwd, config, paths, schemaPath, project).catch((e) => console.error("[supatype] Initial schema push failed:", e.message));
522
+ await ensureFirstAdminUserForProject(cwd, config, {
523
+ compose: { project, composePath: paths.composePath },
524
+ });
309
525
  console.log("[supatype] Waiting for API gateway...");
310
526
  await waitKongReady(kongPort, 120);
527
+ writeLocalEnvironment(cwd, {
528
+ target: "local",
529
+ apiUrl: `http://localhost:${kongPort}`,
530
+ databaseUrl: hasEngineOverride(config) ? hostComposeDbUrl(cwd) : composeDbUrl(),
531
+ projectRef: config.project.name,
532
+ kongPort,
533
+ provider: "docker",
534
+ });
535
+ writeDevSessionLock(cwd, {
536
+ composeProject: project,
537
+ projectRef: config.project.name,
538
+ composePath: paths.composePath,
539
+ kongPort,
540
+ startedAt: new Date().toISOString(),
541
+ });
542
+ const ast = loadSchemaAst(schemaPath, cwd);
543
+ await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey);
311
544
  const pidDir = join(homedir(), ".supatype", "projects", config.project.name, "pid");
312
545
  mkdirSync(pidDir, { recursive: true });
313
546
  let studioProc = null;
@@ -343,21 +576,34 @@ export async function runDevCompose(cwd, config, opts) {
343
576
  Press Ctrl+C to stop.
344
577
  `);
345
578
  const appProc = startProxyDevApp(cwd, config, pidDir);
346
- const cleanup = async () => {
347
- console.log("\n[supatype] Shutting down compose...");
579
+ let schemaWatcher = null;
580
+ let debounceTimer = null;
581
+ registerDevShutdown(async () => {
582
+ schemaWatcher?.close();
583
+ schemaWatcher = null;
584
+ if (debounceTimer) {
585
+ clearTimeout(debounceTimer);
586
+ debounceTimer = null;
587
+ }
588
+ console.log("[supatype] Shutting down compose...");
348
589
  await studioProc?.stop();
349
590
  await appProc?.stop();
350
- runDockerCompose(paths.composePath, ["down"], cwd, project);
351
- process.exit(0);
352
- };
353
- process.once("SIGINT", () => void cleanup());
354
- process.once("SIGTERM", () => void cleanup());
591
+ const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true });
592
+ if (downStatus === 0) {
593
+ console.log("[supatype] Compose stack stopped.");
594
+ }
595
+ else {
596
+ console.warn(`[supatype] Compose down exited with status ${downStatus}.`);
597
+ }
598
+ }, {
599
+ cwd,
600
+ compose: { cwd, composePath: paths.composePath, composeProject: project },
601
+ });
355
602
  if (opts.watch) {
356
603
  const schemaDir = join(projectRootFromConfig(config, cwd), config.schema?.path ?? "schema/index.ts", "..");
357
604
  console.log(`[supatype] Watching ${schemaDir} for changes...`);
358
605
  const { watch } = await import("node:fs");
359
- let debounceTimer = null;
360
- watch(schemaDir, { recursive: true }, (_eventType, filename) => {
606
+ schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
361
607
  if (!filename?.endsWith(".ts"))
362
608
  return;
363
609
  if (debounceTimer)
@@ -365,10 +611,42 @@ export async function runDevCompose(cwd, config, opts) {
365
611
  debounceTimer = setTimeout(() => {
366
612
  debounceTimer = null;
367
613
  console.log(`\n[supatype] Change detected in ${filename}, pushing schema...`);
368
- runComposeSchemaPush(cwd, config, paths, schemaPath, project).catch((e) => console.error("[supatype] Schema push failed:", e.message));
614
+ runComposeSchemaPushQueued(cwd, config, paths, schemaPath, project)
615
+ .then(async () => {
616
+ const updatedAst = loadSchemaAst(schemaPath, cwd);
617
+ await provisionDockerStorageBuckets(updatedAst, kongPort, serviceRoleKey);
618
+ })
619
+ .catch((e) => console.error("[supatype] Schema push failed:", e.message));
369
620
  }, 300);
370
621
  });
371
622
  }
372
623
  await new Promise(() => undefined);
373
624
  }
625
+ function astHasSystemAuthRelation(ast) {
626
+ const obj = ast;
627
+ if (!obj?.models)
628
+ return false;
629
+ for (const model of obj.models) {
630
+ if (!model.fields)
631
+ continue;
632
+ for (const field of Object.values(model.fields)) {
633
+ if (field.kind === "relation" && field.target === "supatype:user")
634
+ return true;
635
+ }
636
+ }
637
+ return false;
638
+ }
639
+ function grantAuthSchemaAccess(paths, cwd, composeProject) {
640
+ const composeDir = dirname(paths.composePath);
641
+ const baseArgs = [
642
+ "compose", "-p", composeProject,
643
+ "-f", paths.composePath,
644
+ ];
645
+ const sql = "GRANT USAGE ON SCHEMA auth TO service_role; GRANT SELECT ON auth.users TO service_role;";
646
+ const result = spawnSync("docker", [...baseArgs, "exec", "-T", "-e", "PGPASSWORD=postgres", "db",
647
+ "psql", "-U", "supatype_admin", "-d", "supatype", "-c", sql], { cwd: composeDir, encoding: "utf8", timeout: 10_000 });
648
+ if (result.status !== 0) {
649
+ console.warn("[supatype] Could not grant service_role access to auth.users — Studio relation preview may fail.");
650
+ }
651
+ }
374
652
  //# sourceMappingURL=dev-compose.js.map