@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,5 +1,6 @@
1
1
  import { type DockerBrandOptions } from "./docker-runtime.js";
2
2
  import { type SupatypeProjectConfig } from "./project-config.js";
3
+ import { type FieldMaskingTier } from "./field-masking-tier.js";
3
4
  /** Env keys written when `versions` pins exist in supatype.config.ts. */
4
5
  export declare const COMPOSE_PINNED_IMAGE_ENV_KEYS: readonly ["SUPATYPE_ENGINE_IMAGE", "SUPATYPE_SERVER_IMAGE", "SUPATYPE_POSTGRES_IMAGE"];
5
6
  /** Compose image env vars that may be overridden manually in `.env`. */
@@ -23,7 +24,7 @@ export declare function composePullNeedsIgnoreFailures(config: SupatypeProjectCo
23
24
  /**
24
25
  * Schema-engine image for a one-off `docker compose run` when pushing schema.
25
26
  * Uses config pin when set; otherwise CDN engine semver (Docker Hub `:latest` can lag).
26
- * Does not touch `.env` server/postgres still use compose `:latest` defaults.
27
+ * Does not touch `.env`, server/postgres still use compose `:latest` defaults.
27
28
  */
28
29
  export declare function schemaEngineImageForPush(config: SupatypeProjectConfig): Promise<string | undefined>;
29
30
  export interface SelfHostComposePaths {
@@ -40,8 +41,31 @@ export declare const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002
40
41
  export interface SelfHostComposeOptions {
41
42
  /** `supatype dev` with provider docker: internal-only db/server; Kong on host :18473. */
42
43
  devLocal?: boolean;
44
+ /**
45
+ * Which mechanism enforces per-column rules, when the caller knows.
46
+ *
47
+ * Only the call sites that have loaded the schema can say, see `field-masking-tier.ts`. Left
48
+ * unset, the exposed schema list is today's, which is correct for every project without field
49
+ * rules and for every project on `supatype/postgres`.
50
+ */
51
+ fieldMaskingTier?: FieldMaskingTier;
43
52
  }
44
53
  export declare function renderSelfHostCompose(config: SupatypeProjectConfig, cwd?: string, options?: SelfHostComposeOptions): string;
54
+ /**
55
+ * A loopback host in the external URL cannot work from inside a container.
56
+ *
57
+ * `127.0.0.1` means "this container" to every service in the stack, so an external database on the
58
+ * host machine is unreachable, while the *CLI* reaches it fine, because the CLI runs on the host.
59
+ * That asymmetry is the trap: `supatype db check` passes, `push` applies the schema, and then
60
+ * storage, realtime and the server all die with ECONNREFUSED against their own loopback. Found by
61
+ * rehearsing exactly that.
62
+ *
63
+ * Refused rather than rewritten. The compose file interpolates one `${DATABASE_URL}` for every
64
+ * service, so silently substituting a different host would mean the CLI and the stack no longer
65
+ * agree about which database they are talking to, the thing every other check here exists to
66
+ * prevent.
67
+ */
68
+ export declare function loopbackExternalHost(config: SupatypeProjectConfig): string | undefined;
45
69
  export declare function writeSelfHostCompose(cwd: string, config: SupatypeProjectConfig, options?: SelfHostComposeOptions): SelfHostComposePaths;
46
70
  export interface RunDockerComposeOptions {
47
71
  /** Suppress docker compose progress UI (container status lines). */
@@ -52,7 +76,7 @@ export interface RunDockerComposeOptions {
52
76
  /** Exit with a friendly compose failure message. */
53
77
  export declare function exitComposeFailed(status: number, context: string, brand?: DockerBrandOptions): never;
54
78
  export declare function runDockerCompose(composePath: string, args: string[], projectRoot?: string, composeProject?: string, options?: RunDockerComposeOptions): number;
55
- /** Compose project name for a Supatype project isolates docker state per project. */
79
+ /** Compose project name for a Supatype project, isolates docker state per project. */
56
80
  export declare function composeProjectName(projectName: string): string;
57
81
  export {};
58
82
  //# sourceMappingURL=self-host-compose.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self-host-compose.d.ts","sourceRoot":"","sources":["../src/self-host-compose.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,EAAyD,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAIvH,yEAAyE;AACzE,eAAO,MAAM,6BAA6B,wFAIhC,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,qOAOzB,CAAA;AAEV,KAAK,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;AAE1D,gEAAgE;AAChE,wBAAgB,cAAc,CAC5B,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,qBAAqB,GAC7B,MAAM,CAeR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAe3F;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAS1E;AAcD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAGT;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM7B;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAQtE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIvF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIrF;AAwBD,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,qCAAqC,CAAA;AAwCzE,MAAM,WAAW,sBAAsB;IACrC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,EAC3B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAqRR;AAqBD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,oBAAoB,CAyBtB;AAED,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,4DAA4D;IAC5D,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,kBAAkB,GACzB,KAAK,CAMP;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,GAAE,MAAsB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,CAsCR;AAED,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG9D"}
1
+ {"version":3,"file":"self-host-compose.d.ts","sourceRoot":"","sources":["../src/self-host-compose.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,EASL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAA;AAI5B,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE5F,yEAAyE;AACzE,eAAO,MAAM,6BAA6B,wFAIhC,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,qOAOzB,CAAA;AAEV,KAAK,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;AAE1D,gEAAgE;AAChE,wBAAgB,cAAc,CAC5B,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,qBAAqB,GAC7B,MAAM,CAeR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAe3F;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAS1E;AAcD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAGT;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM7B;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAQtE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIvF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIrF;AAiED,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,qCAAqC,CAAA;AAwCzE,MAAM,WAAW,sBAAsB;IACrC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,EAC3B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CA+UR;AAoGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAiBtF;AAwCD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,oBAAoB,CAgCtB;AAED,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,4DAA4D;IAC5D,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,kBAAkB,GACzB,KAAK,CAMP;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,GAAE,MAAsB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,CAsCR;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG9D"}
@@ -3,9 +3,11 @@ import { dirname, join, relative, resolve } from "node:path";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import { requireDockerDaemon } from "./docker-runtime.js";
5
5
  import { fatalError } from "./ui/fatal.js";
6
- import { preferredFunctionsPathFromProject, selfHostTlsEnabled } from "./project-config.js";
6
+ import { apiSchemaList, externalDatabaseUrl, hooksPathFromProject, preferredFunctionsPathFromProject, realtimeEnabled, serviceRoleRoutes, selfHostTlsEnabled, usesExternalDatabase, } from "./project-config.js";
7
7
  import { hasEngineOverride, hasStudioOverride, pinnedVersion, fetchLatestVersion, VERSION_PIN_LOCAL } from "./binary-cache.js";
8
8
  import { buildKongDeclarative } from "./kong-config.js";
9
+ import { readEnvFile } from "./env-file.js";
10
+ import { fieldMaskingTierFromProject } from "./field-masking-tier.js";
9
11
  /** Env keys written when `versions` pins exist in supatype.config.ts. */
10
12
  export const COMPOSE_PINNED_IMAGE_ENV_KEYS = [
11
13
  "SUPATYPE_ENGINE_IMAGE",
@@ -108,7 +110,7 @@ export function composePullNeedsIgnoreFailures(config, cwd = process.cwd()) {
108
110
  /**
109
111
  * Schema-engine image for a one-off `docker compose run` when pushing schema.
110
112
  * Uses config pin when set; otherwise CDN engine semver (Docker Hub `:latest` can lag).
111
- * Does not touch `.env` server/postgres still use compose `:latest` defaults.
113
+ * Does not touch `.env`, server/postgres still use compose `:latest` defaults.
112
114
  */
113
115
  export async function schemaEngineImageForPush(config) {
114
116
  const pinned = pinnedVersion("engine", config);
@@ -143,7 +145,7 @@ export function staticDirForCompose(config) {
143
145
  /**
144
146
  * Bind-mount source for `/project` in generated compose files.
145
147
  * Paths are resolved from `--project-directory` (always the project root in `runDockerCompose`),
146
- * not from the compose file directory use `.` not `../..`.
148
+ * not from the compose file directory, use `.` not `../..`.
147
149
  */
148
150
  function projectMountPath(_cwd) {
149
151
  return ".";
@@ -159,9 +161,45 @@ function relativeFromProjectRoot(cwd, target) {
159
161
  function kongMountPath(_cwd) {
160
162
  return ".supatype/self-host/kong.yml";
161
163
  }
164
+ /**
165
+ * The DSN every service uses for the schema-owning role.
166
+ *
167
+ * One expression instead of six identical constructions of `@db:5432`. With an external database it
168
+ * becomes `${DATABASE_URL:?…}`: the URL is the operator's, so there is nothing for the generator to
169
+ * build: and interpolating the value into the compose file would write a password into a generated
170
+ * file. Compose resolves the variable from `.env` at up-time, the same place the config's
171
+ * `process.env.DATABASE_URL` read it from.
172
+ */
173
+ function ownerDatabaseUrl(config, scheme = "postgresql") {
174
+ if (usesExternalDatabase(config)) {
175
+ return "${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}";
176
+ }
177
+ return (`${scheme}://\${POSTGRES_USER:-supatype_admin}:` +
178
+ "\${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is missing from .env}" +
179
+ "@db:5432/\${POSTGRES_DB:-supatype}");
180
+ }
181
+ /**
182
+ * PostgREST's DSN, which connects as `authenticator` rather than the owner.
183
+ *
184
+ * For an external database the host, port, database and query string are taken from the operator's
185
+ * URL and only the password stays a variable. The alternative, a second full URL in `.env`, is one
186
+ * more thing to keep in step with the first, and two URLs that disagree about *which database* is a
187
+ * split-brain nobody notices until the API is serving one and migrations are landing in the other.
188
+ * A hostname is not the secret here; the password is, and it stays out of the generated file.
189
+ */
190
+ function postgrestDatabaseUrl(config) {
191
+ const password = "${AUTHENTICATOR_PASSWORD:?AUTHENTICATOR_PASSWORD is missing from .env}";
192
+ const externalUrl = externalDatabaseUrl(config);
193
+ if (externalUrl === undefined) {
194
+ return `postgresql://authenticator:${password}@db:5432/\${POSTGRES_DB:-supatype}`;
195
+ }
196
+ const parsed = new URL(externalUrl);
197
+ const port = parsed.port ? `:${parsed.port}` : "";
198
+ return `postgresql://authenticator:${password}@${parsed.hostname}${port}${parsed.pathname}${parsed.search}`;
199
+ }
162
200
  /** Host Vite dev server as seen from Kong inside Docker Compose. */
163
201
  export const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002";
164
- /** Studio container always Docker Hub unless SUPATYPE_STUDIO_IMAGE is set in .env. */
202
+ /** Studio container: always Docker Hub unless SUPATYPE_STUDIO_IMAGE is set in .env. */
165
203
  function studioServiceBlock() {
166
204
  return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`;
167
205
  }
@@ -200,6 +238,14 @@ function serverAppEnvForCompose(config, devLocal) {
200
238
  export function renderSelfHostCompose(config, cwd = process.cwd(), options) {
201
239
  const projectMount = projectMountPath(cwd);
202
240
  const kongMount = kongMountPath(cwd);
241
+ const external = usesExternalDatabase(config);
242
+ const ownerUrl = ownerDatabaseUrl(config);
243
+ // GoTrue's driver wants the `postgres://` spelling; an external URL is used as given.
244
+ const gotrueUrl = external ? ownerUrl : ownerDatabaseUrl(config, "postgres");
245
+ // An external URL may already carry query parameters (`?sslmode=require` is common on managed
246
+ // providers), and appending a second `?` produces a DSN that fails to parse.
247
+ const gotrueSearchPathSeparator = externalDatabaseUrl(config)?.includes("?") ? "&" : "?";
248
+ const postgrestUrl = postgrestDatabaseUrl(config);
203
249
  const devLocal = options?.devLocal === true;
204
250
  const tlsEnabled = selfHostTlsEnabled(config, devLocal);
205
251
  const domain = config.server.domain?.trim() ?? "";
@@ -274,60 +320,122 @@ ${studioService}
274
320
  # server: { mode: "standalone", domain: "your.domain", tls: { email: "you@example.com" } }
275
321
  # then re-run \`supatype self-host compose up -d\`. Kong publishes :80/:443 and provisions certs automatically.
276
322
  `;
323
+ // An external database is not ours to declare a volume for.
277
324
  const volumesBlock = `volumes:
278
- db-data:
279
- minio-data:
325
+ ${external ? "" : " db-data:\n"} minio-data:
280
326
  valkey-data:
281
327
  `;
282
- return `# Generated by supatype self-host compose
283
- # Kong supatype-server (unified gateway) internal PostgREST / storage / etc.
284
- services:
285
- db:
328
+ // `depends_on` for the services that talk to Postgres. With an external database there is no
329
+ // container to wait on, so the clause disappears entirely and each service retries on connect
330
+ // instead: which is also what covers a database that restarts *after* boot, something no
331
+ // healthcheck ever did.
332
+ const dbDependencyClause = external
333
+ ? ""
334
+ : ` db:
335
+ condition: service_healthy
336
+ `;
337
+ const dbDependency = external ? "" : ` depends_on:\n${dbDependencyClause}`;
338
+ // Realtime, omitted entirely when the project has turned it off.
339
+ //
340
+ // Not started-and-disabled: the service degrades gracefully on its own (it reports the reason on
341
+ // /health/ready rather than crash-looping), so this switch is for the operator who has read
342
+ // `supatype db check`, knows their database cannot do logical decoding, and would rather not run a
343
+ // container that can only report that. The server then has no realtime URL, which is what makes
344
+ // subscription requests fail with a clear route error instead of hanging against a dead upstream.
345
+ const realtime = realtimeEnabled(config);
346
+ const realtimeBlock = realtime
347
+ ? ` realtime:
348
+ image: \${SUPATYPE_REALTIME_IMAGE:-supatype/realtime:latest}
349
+ expose:
350
+ - "4000"
351
+ environment:
352
+ PORT: "4000"
353
+ DATABASE_URL: "${ownerUrl}"
354
+ JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
355
+ SLOT_NAME: supatype_realtime
356
+ # Matches the publication the supatype/postgres image creates. Read by nothing today,
357
+ # wal2json decodes from the slot, and kept for a future pgoutput decoder.
358
+ PUBLICATION_NAME: supatype_realtime
359
+ ${dbDependency}`
360
+ : ` # No \`realtime\` service: database.external.realtime is false. Subscriptions are
361
+ # unavailable; REST, storage, auth and functions are unaffected.
362
+ `;
363
+ const realtimeDependency = realtime
364
+ ? ` realtime:
365
+ condition: service_started
366
+ `
367
+ : "";
368
+ const realtimeServerEnv = realtime ? " SUPATYPE_REALTIME_URL: http://realtime:4000" : "";
369
+ const dbServiceBlock = external
370
+ ? ` # No \`db\` service: database.external points this stack at a Postgres it does not manage.
371
+ # Every service reads \${DATABASE_URL} from .env, and \`supatype db check\` reports what that
372
+ # database still needs (roles, extensions, wal_level for realtime).
373
+ `
374
+ : ` db:
286
375
  image: \${SUPATYPE_POSTGRES_IMAGE:-supatype/postgres:latest}
287
376
  environment:
288
377
  POSTGRES_USER: \${POSTGRES_USER:-supatype_admin}
289
- POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-postgres}
378
+ POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is missing from .env}
290
379
  POSTGRES_DB: \${POSTGRES_DB:-supatype}
380
+ # Read by the image's init to password the \`authenticator\` role PostgREST connects as.
381
+ AUTHENTICATOR_PASSWORD: \${AUTHENTICATOR_PASSWORD:?AUTHENTICATOR_PASSWORD is missing from .env}
291
382
  ${dbPorts} volumes:
292
383
  - db-data:/var/lib/postgresql/data
293
384
  healthcheck:
294
- test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-supatype_admin}"]
385
+ # -h 127.0.0.1 forces TCP. Without it \`pg_isready\` uses the Unix socket, which the
386
+ # entrypoint's temporary init server is already listening on while TCP is still refused,
387
+ # so the container reported healthy, \`depends_on: service_healthy\` released, and every
388
+ # service that connects over the network died with ECONNREFUSED on first boot. PostgREST
389
+ # survived only because it retries. Observed on a clean stack: server, storage and
390
+ # realtime all exited 1 while db said "healthy".
391
+ test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U \${POSTGRES_USER:-supatype_admin} -d \${POSTGRES_DB:-supatype}"]
295
392
  interval: 5s
296
393
  timeout: 5s
394
+ # First boot runs initdb plus every bootstrap migration. Failures inside the start period
395
+ # do not count against retries, so a slow init waits rather than being declared unhealthy.
396
+ start_period: 90s
297
397
  retries: 20
298
398
 
299
- postgrest:
399
+ `;
400
+ return `# Generated by supatype self-host compose
401
+ # Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
402
+ services:
403
+ ${dbServiceBlock} postgrest:
300
404
  image: postgrest/postgrest:v12.2.8
301
405
  expose:
302
406
  - "3000"
303
407
  environment:
304
- PGRST_DB_URI: postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}
305
- PGRST_DB_SCHEMA: "public, supatype, graphql_public, auth"
408
+ # Connects as \`authenticator\`, not \${POSTGRES_USER}, which is a superuser, and a
409
+ # superuser session may SET ROLE to any role in the cluster, so a request whose JWT
410
+ # named one got it. \`authenticator\` is NOINHERIT with membership in only
411
+ # anon/authenticated/service_role, so the same SET ROLE is refused.
412
+ #
413
+ # Its own credential, not POSTGRES_PASSWORD: yours is for direct SQL access and
414
+ # rotating it must not take the REST API down. \`supatype init\` generates this.
415
+ PGRST_DB_URI: ${postgrestUrl}
416
+ # Derived from schema.pg_schema (or schema.api_schemas). Hardcoding this is why choosing a
417
+ # non-public pg_schema used to give a correct push and an API that answered PGRST106 for
418
+ # everything: the engine moved and PostgREST was never told.
419
+ PGRST_DB_SCHEMA: "${apiSchemaList(config, options?.fieldMaskingTier)}"
306
420
  PGRST_DB_ANON_ROLE: anon
307
- PGRST_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
421
+ PGRST_JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
308
422
  PGRST_DB_EXTRA_SEARCH_PATH: public,extensions
309
423
  PGRST_DB_POOL: 3
310
- depends_on:
311
- db:
312
- condition: service_healthy
313
-
424
+ ${dbDependency}
314
425
  storage:
315
426
  image: \${SUPATYPE_STORAGE_IMAGE:-supatype/storage:latest}
316
427
  expose:
317
428
  - "5000"
318
429
  environment:
319
430
  PORT: 5000
320
- DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
321
- JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
431
+ DATABASE_URL: "${ownerUrl}"
432
+ JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
322
433
  S3_ENDPOINT: http://minio:9000
323
434
  S3_REGION: us-east-1
324
435
  S3_ACCESS_KEY: supatype
325
436
  S3_SECRET_KEY: supatype-secret
326
437
  S3_FORCE_PATH_STYLE: "true"
327
- depends_on:
328
- db:
329
- condition: service_healthy
330
-
438
+ ${dbDependency}
331
439
  functions-worker:
332
440
  image: \${SUPATYPE_FUNCTIONS_WORKER_IMAGE:-supatype/functions-worker:latest}
333
441
  expose:
@@ -337,31 +445,26 @@ ${dbPorts} volumes:
337
445
  environment:
338
446
  SUPATYPE_FUNCTIONS_ROOT: /project/functions
339
447
  SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
448
+ # Model hooks, served by this same worker under a hooks/ route the gateway refuses from
449
+ # outside. One worker rather than two: a second container would cost a pod per project on
450
+ # cloud, for isolation the route boundary already provides.
451
+ SUPATYPE_HOOKS_ROOT: /project/hooks
340
452
  PORT: "8001"
341
- SUPATYPE_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
453
+ # In-compose loopback to Kong (not API_EXTERNAL_URL / localhost, unreachable from this container).
454
+ SUPATYPE_URL: http://kong:8000
455
+ SUPATYPE_INTERNAL_URL: http://kong:8000
342
456
  SUPATYPE_ANON_KEY: \${ANON_KEY:-}
457
+ # Present so the worker can hand it to hooks, which are procedural and unreachable from
458
+ # outside: and to the public functions named below. Withheld from every other handler before
459
+ # any of them is imported: a function is a public endpoint, and an ambient admin credential made
460
+ # each one able to read past every access rule in the schema.
343
461
  SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
462
+ SUPATYPE_SERVICE_ROLE_ROUTES: "${serviceRoleRoutes(config).join(",")}"
344
463
  STRIPE_SECRET_KEY: \${STRIPE_SECRET_KEY:-}
345
464
  STRIPE_WEBHOOK_SECRET: \${STRIPE_WEBHOOK_SECRET:-}
346
465
  SITE_URL: \${SITE_URL:-\${API_EXTERNAL_URL:-${externalUrlFallback}}}
347
- depends_on:
348
- db:
349
- condition: service_healthy
350
-
351
- realtime:
352
- image: \${SUPATYPE_REALTIME_IMAGE:-supatype/realtime:latest}
353
- expose:
354
- - "4000"
355
- environment:
356
- PORT: "4000"
357
- DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
358
- JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
359
- SLOT_NAME: supatype_realtime
360
- PUBLICATION_NAME: supatype_realtime_pub
361
- depends_on:
362
- db:
363
- condition: service_healthy
364
-
466
+ ${dbDependency}
467
+ ${realtimeBlock}
365
468
  control-plane:
366
469
  image: \${SUPATYPE_CONTROL_PLANE_IMAGE:-supatype/control-plane:latest}
367
470
  expose:
@@ -373,16 +476,13 @@ ${dbPorts} volumes:
373
476
  PORT: "8080"
374
477
  SUPATYPE_PROJECT_REF: ${JSON.stringify(config.project.name)}
375
478
  SUPATYPE_PROJECT_ROOT: /project
376
- DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
479
+ DATABASE_URL: "${ownerUrl}"
377
480
  SUPATYPE_FUNCTIONS_ROOT: /project/functions
378
481
  SUPATYPE_STATIC_ROOT: /project/${staticDir.replace(/^\.\//, "")}
379
482
  SUPATYPE_DEPLOYMENTS_DIR: /project/.supatype/deployments
380
483
  COMPOSE_PROJECT_NAME: ${composeProject}
381
484
  SUPATYPE_ENGINE_BIN: supatype-engine
382
- depends_on:
383
- db:
384
- condition: service_healthy
385
-
485
+ ${dbDependency}
386
486
  server:
387
487
  image: \${SUPATYPE_SERVER_IMAGE:-\${SUPATYPE_AUTH_IMAGE:-supatype/server:latest}}
388
488
  ${serverPorts} volumes:
@@ -399,10 +499,10 @@ ${serverPorts} volumes:
399
499
  SUPATYPE_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
400
500
  SUPATYPE_ANON_KEY: \${ANON_KEY:-}
401
501
  SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
402
- SUPATYPE_SQL_DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
502
+ SUPATYPE_SQL_DATABASE_URL: "${ownerUrl}"
403
503
  SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
404
504
  SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
405
- SUPATYPE_REALTIME_URL: http://realtime:4000
505
+ ${realtimeServerEnv}
406
506
  SUPATYPE_CONTROL_PLANE_URL: http://control-plane:8080
407
507
  SUPATYPE_VALKEY_ADDR: valkey:6379
408
508
  ${appEnv}
@@ -411,9 +511,9 @@ ${appEnv}
411
511
  API_EXTERNAL_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
412
512
  GOTRUE_API_EXTERNAL_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
413
513
  GOTRUE_DB_DRIVER: postgres
414
- GOTRUE_DB_DATABASE_URL: "postgres://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}?search_path=auth"
514
+ GOTRUE_DB_DATABASE_URL: "${gotrueUrl}${gotrueSearchPathSeparator}search_path=auth"
415
515
  GOTRUE_SITE_URL: \${SITE_URL:-${siteUrlFallback}}
416
- GOTRUE_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
516
+ GOTRUE_JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
417
517
  GOTRUE_JWT_EXP: 3600
418
518
  GOTRUE_JWT_AUD: authenticated
419
519
  GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
@@ -422,9 +522,7 @@ ${appEnv}
422
522
  GOTRUE_DISABLE_SIGNUP: \${DISABLE_SIGNUP:-false}
423
523
  ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
424
524
  depends_on:
425
- db:
426
- condition: service_healthy
427
- valkey:
525
+ ${dbDependencyClause} valkey:
428
526
  condition: service_started
429
527
  postgrest:
430
528
  condition: service_started
@@ -432,9 +530,7 @@ ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
432
530
  condition: service_started
433
531
  functions-worker:
434
532
  condition: service_started
435
- realtime:
436
- condition: service_started
437
- control-plane:
533
+ ${realtimeDependency} control-plane:
438
534
  condition: service_started
439
535
 
440
536
  minio:
@@ -453,10 +549,7 @@ ${minioPorts} volumes:
453
549
  volumes:
454
550
  - ${projectMount}:/project
455
551
  working_dir: /project
456
- depends_on:
457
- db:
458
- condition: service_healthy
459
- ${studioBlock}${valkeyBlock}${tlsHintComment} kong:
552
+ ${dbDependency}${studioBlock}${valkeyBlock}${tlsHintComment} kong:
460
553
  image: kong:3.6
461
554
  environment:
462
555
  KONG_DATABASE: "off"
@@ -474,30 +567,169 @@ ${kongDependsOn}${kongValkeyDepends}
474
567
 
475
568
  ${volumesBlock}`;
476
569
  }
477
- function ensureComposeManifest(cwd) {
570
+ /** In-compose worker address: matches the `functions-worker` service this file always generates. */
571
+ const COMPOSE_FUNCTIONS_WORKER_URL = "http://functions-worker:8001";
572
+ function ensureComposeManifest(cwd, config) {
478
573
  const manifestPath = join(cwd, ".supatype", "manifest.json");
479
- if (existsSync(manifestPath))
480
- return;
481
574
  mkdirSync(dirname(manifestPath), { recursive: true });
575
+ // The manifest is generated, not operator-authored, but `push` writes real values into it (the
576
+ // schema, for one), so an existing file is repaired rather than replaced.
577
+ if (existsSync(manifestPath)) {
578
+ repairComposeFunctionsFlag(manifestPath);
579
+ return;
580
+ }
482
581
  const manifest = {
483
582
  schema: "public",
484
583
  postgrest_url: "http://postgrest:3000",
485
584
  storage_url: "http://storage:5000",
486
- realtime_enabled: true,
487
- realtime_url: "http://realtime:4000",
488
- functions_enabled: false,
585
+ // Matches the compose file: a manifest advertising a service that was not generated is how
586
+ // the server ends up proxying subscriptions to a host that does not resolve.
587
+ realtime_enabled: realtimeEnabled(config),
588
+ ...(realtimeEnabled(config) && { realtime_url: "http://realtime:4000" }),
589
+ // True because this file *always* generates a `functions-worker` service and hands the server
590
+ // `SUPATYPE_FUNCTIONS_WORKER_URL`. It said false, so the server answered 404 for every function
591
+ // in a stack that was running a worker for them, provisioned, then switched off.
592
+ functions_enabled: true,
593
+ functions_worker_url: COMPOSE_FUNCTIONS_WORKER_URL,
489
594
  };
490
595
  writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
491
596
  }
597
+ /**
598
+ * Turn functions on in a manifest written by an older CLI, leaving every other key alone.
599
+ *
600
+ * Without this, only new projects get working functions: a stack generated before the flag was
601
+ * corrected keeps `functions_enabled: false` on disk, and regenerating the compose file, the
602
+ * obvious thing to try, does not fix it.
603
+ */
604
+ function repairComposeFunctionsFlag(manifestPath) {
605
+ let parsed;
606
+ try {
607
+ parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
608
+ }
609
+ catch {
610
+ return; // Malformed: leave it for the server to complain about rather than overwrite it here.
611
+ }
612
+ if (typeof parsed !== "object" || parsed === null)
613
+ return;
614
+ if (parsed["functions_enabled"] === true && parsed["functions_worker_url"] !== undefined)
615
+ return;
616
+ parsed["functions_enabled"] = true;
617
+ if (parsed["functions_worker_url"] === undefined) {
618
+ parsed["functions_worker_url"] = COMPOSE_FUNCTIONS_WORKER_URL;
619
+ }
620
+ writeFileSync(manifestPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
621
+ }
492
622
  function ensureProjectFunctionsDir(cwd, config) {
493
623
  mkdirSync(preferredFunctionsPathFromProject(config, cwd), { recursive: true });
624
+ // Both roots must exist before compose mounts the project read-only: a missing directory becomes
625
+ // a bind mount of a file that is not there, and the worker fails to start rather than serving the
626
+ // half it does have.
627
+ mkdirSync(hooksPathFromProject(config, cwd), { recursive: true });
628
+ }
629
+ /**
630
+ * The config's external URL and `.env`'s `DATABASE_URL` must be the same string.
631
+ *
632
+ * The CLI resolves the URL from config; Compose substitutes `.env` at up-time. If the two disagree,
633
+ * `push` migrates one database while the services serve another, which reads as data loss and
634
+ * isn't. It also makes the generated GoTrue DSN wrong, since whether to append `search_path` with
635
+ * `?` or `&` is decided from the config URL's query string.
636
+ */
637
+ function assertExternalUrlMatchesEnv(cwd, config) {
638
+ const configured = externalDatabaseUrl(config);
639
+ if (configured === undefined)
640
+ return;
641
+ const fromEnv = readEnvFile(cwd)["DATABASE_URL"];
642
+ if (fromEnv === undefined) {
643
+ // Nothing to disagree with. Compose's own `:?` guard reports this at up-time, and the operator
644
+ // may be exporting the variable in their shell rather than keeping a file.
645
+ return;
646
+ }
647
+ if (fromEnv.trim() === configured)
648
+ return;
649
+ fatalError("DATABASE_URL in .env does not match database.external.url", [
650
+ `.env: ${fromEnv.trim()}`,
651
+ `config: ${configured}`,
652
+ "",
653
+ "The CLI connects using the config value and the stack connects using .env, so a push would",
654
+ "land in one database while the services serve the other.",
655
+ "Point the config at the same variable to keep them in step:",
656
+ " database: { external: { url: process.env.DATABASE_URL! } }",
657
+ ], { brand: { intro: "Self-host compose" } });
658
+ }
659
+ /**
660
+ * A loopback host in the external URL cannot work from inside a container.
661
+ *
662
+ * `127.0.0.1` means "this container" to every service in the stack, so an external database on the
663
+ * host machine is unreachable, while the *CLI* reaches it fine, because the CLI runs on the host.
664
+ * That asymmetry is the trap: `supatype db check` passes, `push` applies the schema, and then
665
+ * storage, realtime and the server all die with ECONNREFUSED against their own loopback. Found by
666
+ * rehearsing exactly that.
667
+ *
668
+ * Refused rather than rewritten. The compose file interpolates one `${DATABASE_URL}` for every
669
+ * service, so silently substituting a different host would mean the CLI and the stack no longer
670
+ * agree about which database they are talking to, the thing every other check here exists to
671
+ * prevent.
672
+ */
673
+ export function loopbackExternalHost(config) {
674
+ const url = externalDatabaseUrl(config);
675
+ if (url === undefined)
676
+ return undefined;
677
+ let host;
678
+ try {
679
+ host = new URL(url).hostname.toLowerCase();
680
+ }
681
+ catch {
682
+ return undefined; // Shape is validated at config load; nothing useful to add here.
683
+ }
684
+ // Node strips the brackets from an IPv6 hostname, and 127.0.0.0/8 is all loopback.
685
+ const loopback = host === "localhost" ||
686
+ host === "::1" ||
687
+ host === "[::1]" ||
688
+ /^127\.\d+\.\d+\.\d+$/.test(host);
689
+ return loopback ? host : undefined;
690
+ }
691
+ function assertExternalUrlReachableFromContainers(config) {
692
+ const host = loopbackExternalHost(config);
693
+ if (host === undefined)
694
+ return;
695
+ fatalError(`database.external.url points at ${host}, which no container can reach`, [
696
+ "Inside a container, localhost is that container, not the machine running Docker. Every",
697
+ "service in the stack would fail to connect, while the CLI succeeds because it runs on the host.",
698
+ "",
699
+ "Use a host the containers can resolve:",
700
+ " host.docker.internal (Docker Desktop on macOS and Windows)",
701
+ " 172.17.0.1 (the docker0 bridge on Linux, or add an extra_hosts entry)",
702
+ " the database's LAN address or hostname",
703
+ "",
704
+ "The CLI reaches the same address, so one value keeps working for both.",
705
+ ], { brand: { intro: "Self-host compose" } });
706
+ }
707
+ /**
708
+ * The tier to write into the compose file.
709
+ *
710
+ * Resolved here so every caller gets it, rather than threaded through four call sites that load the
711
+ * schema a moment later anyway. A schema that fails to load falls back to the default list: compose
712
+ * generation is the wrong place to report a syntax error, and `push`/`dev` do it properly seconds
713
+ * later with the file and line.
714
+ */
715
+ function resolveFieldMaskingTier(cwd, config, options) {
716
+ if (options?.fieldMaskingTier !== undefined)
717
+ return options.fieldMaskingTier;
718
+ return fieldMaskingTierFromProject(cwd, config);
494
719
  }
495
720
  export function writeSelfHostCompose(cwd, config, options) {
721
+ assertExternalUrlMatchesEnv(cwd, config);
722
+ const tier = resolveFieldMaskingTier(cwd, config, options);
723
+ const resolved = {
724
+ ...options,
725
+ ...(tier !== undefined && { fieldMaskingTier: tier }),
726
+ };
727
+ assertExternalUrlReachableFromContainers(config);
496
728
  const paths = selfHostComposePaths(cwd);
497
729
  mkdirSync(paths.dir, { recursive: true });
498
730
  ensureProjectFunctionsDir(cwd, config);
499
- ensureComposeManifest(cwd);
500
- writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd, options), "utf8");
731
+ ensureComposeManifest(cwd, config);
732
+ writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd, resolved), "utf8");
501
733
  const studioHostDev = options?.devLocal === true && hasStudioOverride(config);
502
734
  const tlsEnabled = selfHostTlsEnabled(config, options?.devLocal === true);
503
735
  const domain = config.server.domain?.trim();
@@ -558,7 +790,7 @@ export function runDockerCompose(composePath, args, projectRoot = process.cwd(),
558
790
  }
559
791
  return result.status ?? 1;
560
792
  }
561
- /** Compose project name for a Supatype project isolates docker state per project. */
793
+ /** Compose project name for a Supatype project, isolates docker state per project. */
562
794
  export function composeProjectName(projectName) {
563
795
  const slug = projectName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
564
796
  return `supatype-${slug || "project"}`;