@supatype/cli 0.1.1 → 0.1.3

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 (334) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +126 -99
  3. package/.turbo/turbo-typecheck.log +2 -2
  4. package/dist/binary-cache.d.ts +2 -0
  5. package/dist/binary-cache.d.ts.map +1 -1
  6. package/dist/binary-cache.js +36 -0
  7. package/dist/binary-cache.js.map +1 -1
  8. package/dist/binary-download-lock.d.ts +12 -0
  9. package/dist/binary-download-lock.d.ts.map +1 -0
  10. package/dist/binary-download-lock.js +106 -0
  11. package/dist/binary-download-lock.js.map +1 -0
  12. package/dist/cli-package-version.d.ts +3 -0
  13. package/dist/cli-package-version.d.ts.map +1 -0
  14. package/dist/cli-package-version.js +15 -0
  15. package/dist/cli-package-version.js.map +1 -0
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +5 -2
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/add.js +25 -19
  20. package/dist/commands/add.js.map +1 -1
  21. package/dist/commands/admin.d.ts +12 -0
  22. package/dist/commands/admin.d.ts.map +1 -1
  23. package/dist/commands/admin.js +116 -26
  24. package/dist/commands/admin.js.map +1 -1
  25. package/dist/commands/cache.d.ts +1 -1
  26. package/dist/commands/cache.d.ts.map +1 -1
  27. package/dist/commands/cache.js +98 -5
  28. package/dist/commands/cache.js.map +1 -1
  29. package/dist/commands/dev.d.ts.map +1 -1
  30. package/dist/commands/dev.js +26 -22
  31. package/dist/commands/dev.js.map +1 -1
  32. package/dist/commands/init.d.ts +3 -4
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +296 -121
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/link-helpers.d.ts.map +1 -1
  37. package/dist/commands/link-helpers.js +26 -25
  38. package/dist/commands/link-helpers.js.map +1 -1
  39. package/dist/compose-local-server-image.d.ts +13 -0
  40. package/dist/compose-local-server-image.d.ts.map +1 -0
  41. package/dist/compose-local-server-image.js +57 -0
  42. package/dist/compose-local-server-image.js.map +1 -0
  43. package/dist/compose-rename.d.ts.map +1 -1
  44. package/dist/compose-rename.js +5 -8
  45. package/dist/compose-rename.js.map +1 -1
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +12 -1
  48. package/dist/config.js.map +1 -1
  49. package/dist/dev-compose.d.ts.map +1 -1
  50. package/dist/dev-compose.js +113 -56
  51. package/dist/dev-compose.js.map +1 -1
  52. package/dist/dev-log-bus.d.ts +5 -0
  53. package/dist/dev-log-bus.d.ts.map +1 -1
  54. package/dist/dev-log-bus.js +16 -0
  55. package/dist/dev-log-bus.js.map +1 -1
  56. package/dist/dev-log-filter.d.ts +4 -0
  57. package/dist/dev-log-filter.d.ts.map +1 -1
  58. package/dist/dev-log-filter.js +52 -0
  59. package/dist/dev-log-filter.js.map +1 -1
  60. package/dist/dev-ports.d.ts.map +1 -1
  61. package/dist/dev-ports.js +19 -12
  62. package/dist/dev-ports.js.map +1 -1
  63. package/dist/dev-ready-panel.d.ts +21 -0
  64. package/dist/dev-ready-panel.d.ts.map +1 -0
  65. package/dist/dev-ready-panel.js +67 -0
  66. package/dist/dev-ready-panel.js.map +1 -0
  67. package/dist/dev-session-lock.d.ts.map +1 -1
  68. package/dist/dev-session-lock.js +5 -8
  69. package/dist/dev-session-lock.js.map +1 -1
  70. package/dist/dev-session.d.ts +18 -5
  71. package/dist/dev-session.d.ts.map +1 -1
  72. package/dist/dev-session.js +91 -18
  73. package/dist/dev-session.js.map +1 -1
  74. package/dist/dev-shutdown.d.ts +2 -0
  75. package/dist/dev-shutdown.d.ts.map +1 -1
  76. package/dist/dev-shutdown.js +29 -15
  77. package/dist/dev-shutdown.js.map +1 -1
  78. package/dist/dev-task-colors.d.ts +3 -1
  79. package/dist/dev-task-colors.d.ts.map +1 -1
  80. package/dist/dev-task-colors.js +23 -3
  81. package/dist/dev-task-colors.js.map +1 -1
  82. package/dist/docker-runtime.js +1 -1
  83. package/dist/docker-runtime.js.map +1 -1
  84. package/dist/engine-push-output.d.ts +1 -0
  85. package/dist/engine-push-output.d.ts.map +1 -1
  86. package/dist/engine-push-output.js +4 -1
  87. package/dist/engine-push-output.js.map +1 -1
  88. package/dist/ensure-binary.d.ts.map +1 -1
  89. package/dist/ensure-binary.js +14 -2
  90. package/dist/ensure-binary.js.map +1 -1
  91. package/dist/ensure-component-binaries.d.ts +17 -0
  92. package/dist/ensure-component-binaries.d.ts.map +1 -0
  93. package/dist/ensure-component-binaries.js +45 -0
  94. package/dist/ensure-component-binaries.js.map +1 -0
  95. package/dist/ensure-dev-api-config.d.ts +3 -0
  96. package/dist/ensure-dev-api-config.d.ts.map +1 -0
  97. package/dist/ensure-dev-api-config.js +17 -0
  98. package/dist/ensure-dev-api-config.js.map +1 -0
  99. package/dist/init-dependency-versions.d.ts +13 -0
  100. package/dist/init-dependency-versions.d.ts.map +1 -0
  101. package/dist/init-dependency-versions.js +53 -0
  102. package/dist/init-dependency-versions.js.map +1 -0
  103. package/dist/init-package-json.d.ts +21 -0
  104. package/dist/init-package-json.d.ts.map +1 -0
  105. package/dist/init-package-json.js +46 -0
  106. package/dist/init-package-json.js.map +1 -0
  107. package/dist/init-project-detect.d.ts +14 -0
  108. package/dist/init-project-detect.d.ts.map +1 -0
  109. package/dist/init-project-detect.js +89 -0
  110. package/dist/init-project-detect.js.map +1 -0
  111. package/dist/postgres-ctl.d.ts.map +1 -1
  112. package/dist/postgres-ctl.js +2 -1
  113. package/dist/postgres-ctl.js.map +1 -1
  114. package/dist/required-host-components.d.ts +11 -0
  115. package/dist/required-host-components.d.ts.map +1 -0
  116. package/dist/required-host-components.js +25 -0
  117. package/dist/required-host-components.js.map +1 -0
  118. package/dist/resolve-api-url.d.ts +6 -0
  119. package/dist/resolve-api-url.d.ts.map +1 -0
  120. package/dist/resolve-api-url.js +39 -0
  121. package/dist/resolve-api-url.js.map +1 -0
  122. package/dist/rest-cache-admin.d.ts +33 -0
  123. package/dist/rest-cache-admin.d.ts.map +1 -0
  124. package/dist/rest-cache-admin.js +96 -0
  125. package/dist/rest-cache-admin.js.map +1 -0
  126. package/dist/scripts/postinstall.d.ts +4 -6
  127. package/dist/scripts/postinstall.d.ts.map +1 -1
  128. package/dist/scripts/postinstall.js +8 -41
  129. package/dist/scripts/postinstall.js.map +1 -1
  130. package/dist/self-host-compose.d.ts.map +1 -1
  131. package/dist/self-host-compose.js +23 -13
  132. package/dist/self-host-compose.js.map +1 -1
  133. package/dist/studio-dev-server.d.ts +4 -2
  134. package/dist/studio-dev-server.d.ts.map +1 -1
  135. package/dist/studio-dev-server.js +3 -2
  136. package/dist/studio-dev-server.js.map +1 -1
  137. package/dist/ui/brand.d.ts +2 -5
  138. package/dist/ui/brand.d.ts.map +1 -1
  139. package/dist/ui/brand.js +2 -7
  140. package/dist/ui/brand.js.map +1 -1
  141. package/dist/ui/clack-api.d.ts +44 -0
  142. package/dist/ui/clack-api.d.ts.map +1 -0
  143. package/dist/ui/clack-api.js +76 -0
  144. package/dist/ui/clack-api.js.map +1 -0
  145. package/dist/ui/clack.d.ts +14 -0
  146. package/dist/ui/clack.d.ts.map +1 -0
  147. package/dist/ui/clack.js +147 -0
  148. package/dist/ui/clack.js.map +1 -0
  149. package/dist/ui/components/FlowSpinner.d.ts +5 -0
  150. package/dist/ui/components/FlowSpinner.d.ts.map +1 -0
  151. package/dist/ui/components/FlowSpinner.js +8 -0
  152. package/dist/ui/components/FlowSpinner.js.map +1 -0
  153. package/dist/ui/components/LogoWordmark.d.ts +9 -0
  154. package/dist/ui/components/LogoWordmark.d.ts.map +1 -0
  155. package/dist/ui/components/LogoWordmark.js +17 -0
  156. package/dist/ui/components/LogoWordmark.js.map +1 -0
  157. package/dist/ui/components/PromptPanel.d.ts +5 -0
  158. package/dist/ui/components/PromptPanel.d.ts.map +1 -0
  159. package/dist/ui/components/PromptPanel.js +7 -0
  160. package/dist/ui/components/PromptPanel.js.map +1 -0
  161. package/dist/ui/components/SelectField.d.ts +11 -0
  162. package/dist/ui/components/SelectField.d.ts.map +1 -0
  163. package/dist/ui/components/SelectField.js +19 -0
  164. package/dist/ui/components/SelectField.js.map +1 -0
  165. package/dist/ui/confirm.d.ts +2 -1
  166. package/dist/ui/confirm.d.ts.map +1 -1
  167. package/dist/ui/confirm.js +4 -4
  168. package/dist/ui/confirm.js.map +1 -1
  169. package/dist/ui/dev/DevDashboard.d.ts +8 -0
  170. package/dist/ui/dev/DevDashboard.d.ts.map +1 -0
  171. package/dist/ui/dev/DevDashboard.js +158 -0
  172. package/dist/ui/dev/DevDashboard.js.map +1 -0
  173. package/dist/ui/dev/DevReadyPanelView.d.ts +8 -0
  174. package/dist/ui/dev/DevReadyPanelView.d.ts.map +1 -0
  175. package/dist/ui/dev/DevReadyPanelView.js +48 -0
  176. package/dist/ui/dev/DevReadyPanelView.js.map +1 -0
  177. package/dist/ui/fatal.d.ts.map +1 -1
  178. package/dist/ui/fatal.js +5 -11
  179. package/dist/ui/fatal.js.map +1 -1
  180. package/dist/ui/flows/FlowApp.d.ts +8 -0
  181. package/dist/ui/flows/FlowApp.d.ts.map +1 -0
  182. package/dist/ui/flows/FlowApp.js +44 -0
  183. package/dist/ui/flows/FlowApp.js.map +1 -0
  184. package/dist/ui/flows/prompt-fields.d.ts +48 -0
  185. package/dist/ui/flows/prompt-fields.d.ts.map +1 -0
  186. package/dist/ui/flows/prompt-fields.js +92 -0
  187. package/dist/ui/flows/prompt-fields.js.map +1 -0
  188. package/dist/ui/flows/types.d.ts +41 -0
  189. package/dist/ui/flows/types.d.ts.map +1 -0
  190. package/dist/ui/flows/types.js +2 -0
  191. package/dist/ui/flows/types.js.map +1 -0
  192. package/dist/ui/index.d.ts +1 -1
  193. package/dist/ui/index.js +1 -1
  194. package/dist/ui/messages.d.ts +1 -0
  195. package/dist/ui/messages.d.ts.map +1 -1
  196. package/dist/ui/messages.js +48 -8
  197. package/dist/ui/messages.js.map +1 -1
  198. package/dist/ui/progress.d.ts +5 -1
  199. package/dist/ui/progress.d.ts.map +1 -1
  200. package/dist/ui/progress.js +12 -3
  201. package/dist/ui/progress.js.map +1 -1
  202. package/dist/ui/prompts.d.ts +7 -5
  203. package/dist/ui/prompts.d.ts.map +1 -1
  204. package/dist/ui/prompts.js +15 -8
  205. package/dist/ui/prompts.js.map +1 -1
  206. package/dist/ui/runtime/cancel.d.ts +4 -0
  207. package/dist/ui/runtime/cancel.d.ts.map +1 -0
  208. package/dist/ui/runtime/cancel.js +6 -0
  209. package/dist/ui/runtime/cancel.js.map +1 -0
  210. package/dist/ui/runtime/command-chrome.d.ts +17 -0
  211. package/dist/ui/runtime/command-chrome.d.ts.map +1 -0
  212. package/dist/ui/runtime/command-chrome.js +123 -0
  213. package/dist/ui/runtime/command-chrome.js.map +1 -0
  214. package/dist/ui/runtime/dev-prompt-queue.d.ts +30 -0
  215. package/dist/ui/runtime/dev-prompt-queue.d.ts.map +1 -0
  216. package/dist/ui/runtime/dev-prompt-queue.js +57 -0
  217. package/dist/ui/runtime/dev-prompt-queue.js.map +1 -0
  218. package/dist/ui/runtime/flow-session.d.ts +4 -0
  219. package/dist/ui/runtime/flow-session.d.ts.map +1 -0
  220. package/dist/ui/runtime/flow-session.js +8 -0
  221. package/dist/ui/runtime/flow-session.js.map +1 -0
  222. package/dist/ui/runtime/run-clack-flow.d.ts +5 -0
  223. package/dist/ui/runtime/run-clack-flow.d.ts.map +1 -0
  224. package/dist/ui/runtime/run-clack-flow.js +46 -0
  225. package/dist/ui/runtime/run-clack-flow.js.map +1 -0
  226. package/dist/ui/runtime/stdin-after-ink.d.ts +3 -0
  227. package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -0
  228. package/dist/ui/runtime/stdin-after-ink.js +16 -0
  229. package/dist/ui/runtime/stdin-after-ink.js.map +1 -0
  230. package/dist/ui/theme.d.ts +24 -0
  231. package/dist/ui/theme.d.ts.map +1 -0
  232. package/dist/ui/theme.js +34 -0
  233. package/dist/ui/theme.js.map +1 -0
  234. package/dist/valkey-sidecar.d.ts +17 -0
  235. package/dist/valkey-sidecar.d.ts.map +1 -0
  236. package/dist/valkey-sidecar.js +94 -0
  237. package/dist/valkey-sidecar.js.map +1 -0
  238. package/package.json +9 -3
  239. package/src/binary-cache.ts +61 -0
  240. package/src/binary-download-lock.ts +124 -0
  241. package/src/cli-package-version.ts +15 -0
  242. package/src/cli.ts +6 -2
  243. package/src/commands/add.ts +26 -19
  244. package/src/commands/admin.ts +156 -29
  245. package/src/commands/cache.ts +105 -5
  246. package/src/commands/dev.ts +26 -21
  247. package/src/commands/init.ts +473 -247
  248. package/src/commands/link-helpers.ts +30 -29
  249. package/src/compose-local-server-image.ts +68 -0
  250. package/src/compose-rename.ts +5 -8
  251. package/src/config.ts +13 -1
  252. package/src/dev-compose.ts +139 -54
  253. package/src/dev-log-bus.ts +20 -0
  254. package/src/dev-log-filter.ts +42 -0
  255. package/src/dev-ports.ts +22 -11
  256. package/src/dev-ready-panel.ts +80 -0
  257. package/src/dev-session-lock.ts +5 -8
  258. package/src/dev-session.ts +98 -18
  259. package/src/dev-shutdown.ts +29 -17
  260. package/src/dev-task-colors.ts +22 -3
  261. package/src/docker-runtime.ts +1 -1
  262. package/src/engine-push-output.ts +5 -1
  263. package/src/ensure-binary.ts +21 -1
  264. package/src/ensure-component-binaries.ts +71 -0
  265. package/src/ensure-dev-api-config.ts +18 -0
  266. package/src/init-dependency-versions.ts +69 -0
  267. package/src/init-package-json.ts +63 -0
  268. package/src/init-project-detect.ts +99 -0
  269. package/src/postgres-ctl.ts +2 -1
  270. package/src/required-host-components.ts +37 -0
  271. package/src/resolve-api-url.ts +43 -0
  272. package/src/rest-cache-admin.ts +135 -0
  273. package/src/scripts/postinstall.ts +9 -46
  274. package/src/self-host-compose.ts +22 -12
  275. package/src/studio-dev-server.ts +5 -4
  276. package/src/ui/README.md +13 -9
  277. package/src/ui/brand.ts +2 -8
  278. package/src/ui/clack-api.ts +123 -0
  279. package/src/ui/clack.ts +153 -0
  280. package/src/ui/components/FlowSpinner.tsx +15 -0
  281. package/src/ui/components/LogoWordmark.tsx +36 -0
  282. package/src/ui/components/PromptPanel.tsx +17 -0
  283. package/src/ui/components/SelectField.tsx +58 -0
  284. package/src/ui/confirm.ts +5 -4
  285. package/src/ui/dev/DevDashboard.tsx +223 -0
  286. package/src/ui/dev/DevReadyPanelView.tsx +134 -0
  287. package/src/ui/fatal.ts +5 -10
  288. package/src/ui/flows/FlowApp.tsx +69 -0
  289. package/src/ui/flows/prompt-fields.tsx +198 -0
  290. package/src/ui/flows/types.ts +50 -0
  291. package/src/ui/index.ts +1 -1
  292. package/src/ui/messages.ts +50 -8
  293. package/src/ui/progress.ts +14 -3
  294. package/src/ui/prompts.ts +17 -9
  295. package/src/ui/runtime/cancel.ts +6 -0
  296. package/src/ui/runtime/command-chrome.ts +147 -0
  297. package/src/ui/runtime/dev-prompt-queue.ts +84 -0
  298. package/src/ui/runtime/flow-session.ts +11 -0
  299. package/src/ui/runtime/run-clack-flow.tsx +65 -0
  300. package/src/ui/runtime/stdin-after-ink.ts +18 -0
  301. package/src/ui/theme.ts +41 -0
  302. package/src/valkey-sidecar.ts +126 -0
  303. package/tests/admin-ensure.test.ts +80 -0
  304. package/tests/binary-cache-cloud-overrides.test.ts +2 -2
  305. package/tests/binary-download-lock.test.ts +41 -0
  306. package/tests/cli-help.test.ts +7 -4
  307. package/tests/cli-package-version.test.ts +15 -0
  308. package/tests/command-chrome-coverage.test.ts +149 -0
  309. package/tests/command-chrome-wrap.test.ts +51 -0
  310. package/tests/config.test.ts +27 -4
  311. package/tests/dev-ready-panel.test.ts +37 -0
  312. package/tests/dev-ui.test.ts +42 -2
  313. package/tests/docker-runtime.test.ts +9 -20
  314. package/tests/ensure-dev-api-config.test.ts +22 -0
  315. package/tests/init-dependency-versions.test.ts +62 -0
  316. package/tests/init-package-json.test.ts +18 -0
  317. package/tests/init-project-detect.test.ts +53 -0
  318. package/tests/init.test.ts +30 -3
  319. package/tests/required-host-components.test.ts +51 -0
  320. package/tests/resolve-api-url.test.ts +23 -0
  321. package/tests/rest-cache-admin.test.ts +28 -0
  322. package/tests/runtime-contract.test.ts +12 -3
  323. package/tests/stdin-after-ink.test.ts +8 -0
  324. package/tests/tsconfig.json +8 -2
  325. package/tests/ui-confirm.test.ts +13 -9
  326. package/tests/ui-messages.test.ts +4 -18
  327. package/tsconfig.json +1 -0
  328. package/tsconfig.tsbuildinfo +1 -1
  329. package/vitest.config.ts +3 -0
  330. package/dist/dev-tui.d.ts +0 -24
  331. package/dist/dev-tui.d.ts.map +0 -1
  332. package/dist/dev-tui.js +0 -188
  333. package/dist/dev-tui.js.map +0 -1
  334. package/src/dev-tui.ts +0 -232
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valkey-sidecar.js","sourceRoot":"","sources":["../src/valkey-sidecar.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supatype/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Supatype CLI — schema push, introspect, generate",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,12 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@clack/prompts": "^1.6.0",
23
22
  "bcryptjs": "^3.0.2",
23
+ "ink": "^5.2.1",
24
+ "ink-select-input": "^6.2.0",
25
+ "ink-spinner": "^5.0.0",
26
+ "ink-text-input": "^6.0.0",
27
+ "react": "^18.3.1",
24
28
  "commander": "^12.1.0",
25
29
  "pg": "^8.13.0",
26
30
  "ts-morph": "^28.0.0",
@@ -29,6 +33,7 @@
29
33
  },
30
34
  "devDependencies": {
31
35
  "@types/bcryptjs": "^2.4.6",
36
+ "@types/react": "^18.3.18",
32
37
  "@types/node": "^22",
33
38
  "@types/pg": "^8",
34
39
  "vitest": "^4.0.18"
@@ -36,7 +41,8 @@
36
41
  "scripts": {
37
42
  "build": "tsc --project tsconfig.json && node --input-type=module -e \"import{cpSync,mkdirSync}from'node:fs';const a='dist/assets';mkdirSync(a,{recursive:true});cpSync('assets/supatype-logo-wordmark.ascii.txt',a+'/supatype-logo-wordmark.ascii.txt')\"",
38
43
  "dev": "tsc --project tsconfig.json --watch",
39
- "typecheck": "tsc --project tsconfig.json --noEmit",
44
+ "typecheck": "tsc --project tsconfig.json --noEmit && tsc --project tests/tsconfig.json --noEmit",
45
+ "typecheck:tests": "tsc --project tests/tsconfig.json --noEmit",
40
46
  "postinstall": "node --input-type=module --eval \"import{existsSync}from'node:fs';import{resolve}from'node:path';import{pathToFileURL}from'node:url';const f=resolve(process.cwd(),'dist/scripts/postinstall.js');if(existsSync(f))await import(pathToFileURL(f).href)\"",
41
47
  "test": "vitest run",
42
48
  "clean": "rm -rf dist *.tsbuildinfo"
@@ -37,6 +37,12 @@ import { basename, join, resolve, isAbsolute } from "node:path"
37
37
  import type { SupatypeProjectConfig } from "./project-config.js"
38
38
  import { loadProjectLink, migrateLegacyLinkFiles } from "./link.js"
39
39
  import { releasePublicKey } from "./release-public-key.js"
40
+ import {
41
+ isDownloadInProgress,
42
+ releaseDownloadLock,
43
+ tryAcquireDownloadLock,
44
+ waitForComponentDownload,
45
+ } from "./binary-download-lock.js"
40
46
 
41
47
  /**
42
48
  * Set `versions.{engine|server|postgres|deno}: VERSION_PIN_LOCAL` to mean “use `overrides.*` only”
@@ -167,6 +173,16 @@ export function cachedBinaryPath(component: Component, version: string, platform
167
173
  return join(cachePath(component, version), binaryName(component, version, platform))
168
174
  }
169
175
 
176
+ /** True when the platform binary for `version` is present and passes format checks. */
177
+ export function isCachedBinaryReady(
178
+ component: Component,
179
+ version: string,
180
+ platform: PlatformId = currentPlatform(),
181
+ ): boolean {
182
+ const destPath = cachedBinaryPath(component, version, platform)
183
+ return existsSync(destPath) && cachedArtifactLooksValid(component, destPath)
184
+ }
185
+
170
186
  function binaryName(component: Component, version: string, platform: PlatformId): string {
171
187
  const win = platform.os === "windows"
172
188
  switch (component) {
@@ -299,6 +315,45 @@ export async function ensureCachedBinary(
299
315
  return download(component, version, platform)
300
316
  }
301
317
 
318
+ async function acquireDownloadSlot(
319
+ component: Component,
320
+ version: string,
321
+ platform: PlatformId,
322
+ ): Promise<void> {
323
+ const isReady = () => isCachedBinaryReady(component, version, platform)
324
+
325
+ for (let attempt = 0; attempt < 3; attempt++) {
326
+ if (isReady()) return
327
+
328
+ if (tryAcquireDownloadLock(component, version)) return
329
+
330
+ if (isDownloadInProgress(component, version)) {
331
+ console.log(
332
+ `[supatype] ${component} v${version} is downloading in another process — waiting...`,
333
+ )
334
+ const outcome = await waitForComponentDownload(component, version, isReady, (c) => {
335
+ console.log(`[supatype] Still waiting for ${c} download...`)
336
+ })
337
+ if (outcome === "ready") return
338
+ if (outcome === "timeout") {
339
+ throw new Error(
340
+ `Timed out waiting for ${component} v${version} download. Run: supatype update`,
341
+ )
342
+ }
343
+ console.warn(
344
+ `[supatype] ${component} v${version} download did not finish in the other process — retrying.`,
345
+ )
346
+ continue
347
+ }
348
+
349
+ if (tryAcquireDownloadLock(component, version)) return
350
+ }
351
+
352
+ throw new Error(
353
+ `Could not acquire download lock for ${component} v${version}. Run: supatype update`,
354
+ )
355
+ }
356
+
302
357
  export async function download(
303
358
  component: Component,
304
359
  version: string,
@@ -327,6 +382,11 @@ export async function download(
327
382
  unlinkSync(destPath)
328
383
  }
329
384
 
385
+ await acquireDownloadSlot(component, version, platform)
386
+ if (isCachedBinaryReady(component, version, platform)) {
387
+ return destPath
388
+ }
389
+
330
390
  const binaryUrl = `${CDN_BASE}${CDN_PATHS[component](version, platform)}`
331
391
  const checksumsUrl = `${CDN_BASE}${checksumsDirPath(component, version)}`
332
392
  const minisigUrl = `${checksumsUrl}.minisig`
@@ -361,6 +421,7 @@ export async function download(
361
421
  `Failed to download ${component} v${version} from ${CDN_BASE}: ${(err as Error).message}`,
362
422
  )
363
423
  } finally {
424
+ releaseDownloadLock(component, version)
364
425
  if (existsSync(tmpPath)) {
365
426
  try { unlinkSync(tmpPath) } catch { /* ignore */ }
366
427
  }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Coordinates concurrent component-binary downloads (postinstall, init, dev).
3
+ * A second CLI process waits for an in-flight download instead of racing the CDN.
4
+ */
5
+
6
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"
7
+ import { join } from "node:path"
8
+ import { cachePath, type Component } from "./binary-cache.js"
9
+
10
+ const LOCK_VERSION = 1 as const
11
+ const STALE_MS = 30 * 60 * 1000
12
+ const POLL_MS = 500
13
+ const WAIT_NOTICE_MS = 3000
14
+
15
+ interface DownloadLockPayload {
16
+ version: typeof LOCK_VERSION
17
+ pid: number
18
+ component: Component
19
+ semver: string
20
+ startedAt: string
21
+ }
22
+
23
+ function lockPath(component: Component, version: string): string {
24
+ return join(cachePath(component, version), ".downloading")
25
+ }
26
+
27
+ function sleep(ms: number): Promise<void> {
28
+ return new Promise((resolve) => setTimeout(resolve, ms))
29
+ }
30
+
31
+ function isPidAlive(pid: number): boolean {
32
+ try {
33
+ process.kill(pid, 0)
34
+ return true
35
+ } catch {
36
+ return false
37
+ }
38
+ }
39
+
40
+ function readLock(component: Component, version: string): DownloadLockPayload | null {
41
+ const path = lockPath(component, version)
42
+ if (!existsSync(path)) return null
43
+ try {
44
+ const data = JSON.parse(readFileSync(path, "utf8")) as DownloadLockPayload
45
+ if (data.version !== LOCK_VERSION) return null
46
+ return data
47
+ } catch {
48
+ return null
49
+ }
50
+ }
51
+
52
+ function isLockStale(lock: DownloadLockPayload): boolean {
53
+ if (!isPidAlive(lock.pid)) return true
54
+ const age = Date.now() - Date.parse(lock.startedAt)
55
+ return Number.isNaN(age) || age > STALE_MS
56
+ }
57
+
58
+ export function clearDownloadLock(component: Component, version: string): void {
59
+ const path = lockPath(component, version)
60
+ if (existsSync(path)) unlinkSync(path)
61
+ }
62
+
63
+ /** Atomically claim the download lock for this process, or return false if another live holder exists. */
64
+ export function tryAcquireDownloadLock(component: Component, version: string): boolean {
65
+ mkdirSync(cachePath(component, version), { recursive: true })
66
+ const existing = readLock(component, version)
67
+ if (existing && !isLockStale(existing)) return false
68
+ if (existing) clearDownloadLock(component, version)
69
+
70
+ const payload: DownloadLockPayload = {
71
+ version: LOCK_VERSION,
72
+ pid: process.pid,
73
+ component,
74
+ semver: version,
75
+ startedAt: new Date().toISOString(),
76
+ }
77
+ try {
78
+ writeFileSync(lockPath(component, version), JSON.stringify(payload), { flag: "wx" })
79
+ return true
80
+ } catch {
81
+ return false
82
+ }
83
+ }
84
+
85
+ export function releaseDownloadLock(component: Component, version: string): void {
86
+ const lock = readLock(component, version)
87
+ if (!lock || lock.pid !== process.pid) return
88
+ clearDownloadLock(component, version)
89
+ }
90
+
91
+ export function isDownloadInProgress(component: Component, version: string): boolean {
92
+ const lock = readLock(component, version)
93
+ return lock !== null && !isLockStale(lock)
94
+ }
95
+
96
+ export async function waitForComponentDownload(
97
+ component: Component,
98
+ version: string,
99
+ isReady: () => boolean,
100
+ onWait?: (component: Component) => void,
101
+ ): Promise<"ready" | "failed" | "timeout"> {
102
+ const deadline = Date.now() + STALE_MS
103
+ let lastNotice = 0
104
+
105
+ while (Date.now() < deadline) {
106
+ if (isReady()) return "ready"
107
+
108
+ const lock = readLock(component, version)
109
+ if (!lock || isLockStale(lock)) {
110
+ if (isReady()) return "ready"
111
+ return "failed"
112
+ }
113
+
114
+ const now = Date.now()
115
+ if (onWait && now - lastNotice >= WAIT_NOTICE_MS) {
116
+ onWait(component)
117
+ lastNotice = now
118
+ }
119
+
120
+ await sleep(POLL_MS)
121
+ }
122
+
123
+ return isReady() ? "ready" : "timeout"
124
+ }
@@ -0,0 +1,15 @@
1
+ import { readFileSync } from "node:fs"
2
+ import { dirname, join } from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ const CLI_PACKAGE_JSON = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json")
6
+
7
+ /** Installed @supatype/cli version from package.json (used by --version and init scaffolding). */
8
+ export function cliPackageVersion(): string {
9
+ try {
10
+ const pkg = JSON.parse(readFileSync(CLI_PACKAGE_JSON, "utf8")) as { version?: string }
11
+ return pkg.version ?? "0.0.0"
12
+ } catch {
13
+ return "0.0.0"
14
+ }
15
+ }
package/src/cli.ts CHANGED
@@ -29,13 +29,15 @@ import { registerPlugins } from "./commands/plugins.js"
29
29
  import { registerTypes } from "./commands/types.js"
30
30
  import { registerMigrateFromV1 } from "./commands/migrate-from-v1.js"
31
31
  import { registerSelfUpdate } from "./commands/self-update.js"
32
+ import { cliPackageVersion } from "./cli-package-version.js"
32
33
  import { reportCliFatal } from "./ui/fatal.js"
34
+ import { wrapProgramActionsWithChrome } from "./ui/runtime/command-chrome.js"
33
35
 
34
36
  export async function run(): Promise<void> {
35
37
  const program = new Command()
36
38
  .name("supatype")
37
- .description("Supatype — schema-first Postgres API")
38
- .version("0.1.0")
39
+ .description("Supatype — type-first platform for PostgreSQL")
40
+ .version(cliPackageVersion())
39
41
 
40
42
  registerInit(program)
41
43
  registerDev(program)
@@ -68,6 +70,8 @@ export async function run(): Promise<void> {
68
70
  registerTypes(program)
69
71
  registerMigrateFromV1(program)
70
72
 
73
+ wrapProgramActionsWithChrome(program)
74
+
71
75
  try {
72
76
  await program.parseAsync(process.argv)
73
77
  } catch (err) {
@@ -1,9 +1,9 @@
1
1
  import type { Command } from "commander"
2
- import * as p from "@clack/prompts"
2
+ import { p, runClackFlow } from "../ui/clack.js"
3
3
  import { loadConfig } from "../config.js"
4
4
  import { selfHostTlsEnabled } from "../project-config.js"
5
5
  import { updateServerConfigInProject } from "../app-config.js"
6
- import { ensureNotCancelled, printLogo } from "../ui/prompts.js"
6
+ import { ensureNotCancelled } from "../ui/prompts.js"
7
7
  import { file, error, info, plain } from "../ui/messages.js"
8
8
  import { nextSteps } from "../ui/next-steps.js"
9
9
 
@@ -49,26 +49,33 @@ async function addDomain(domainArg?: string, emailArg?: string): Promise<void> {
49
49
  const cwd = process.cwd()
50
50
  const interactive = !domainArg?.trim() || !emailArg?.trim()
51
51
 
52
- if (interactive) {
53
- printLogo()
54
- p.intro("Add a custom domain")
55
- }
56
-
57
- const domain = await promptDomain(domainArg)
58
- const email = await promptEmail(emailArg)
52
+ const run = async (): Promise<void> => {
53
+ const domain = await promptDomain(domainArg)
54
+ const email = await promptEmail(emailArg)
59
55
 
60
- try {
61
- const configPath = updateServerConfigInProject(cwd, { domain, tlsEmail: email })
62
- if (interactive) {
63
- p.outro(`Updated ${configPath}`)
64
- } else {
65
- file("updated", configPath)
56
+ try {
57
+ const configPath = updateServerConfigInProject(cwd, { domain, tlsEmail: email })
58
+ if (interactive) {
59
+ p.outro(`Updated ${configPath}`)
60
+ } else {
61
+ file("updated", configPath)
62
+ }
63
+ printDomainNextSteps(cwd, domain)
64
+ } catch (err) {
65
+ error((err as Error).message)
66
+ process.exit(1)
66
67
  }
67
- printDomainNextSteps(cwd, domain)
68
- } catch (err) {
69
- error((err as Error).message)
70
- process.exit(1)
71
68
  }
69
+
70
+ if (interactive) {
71
+ await runClackFlow(async () => {
72
+ p.intro("Add a custom domain")
73
+ await run()
74
+ })
75
+ return
76
+ }
77
+
78
+ await run()
72
79
  }
73
80
 
74
81
  function printDomainNextSteps(cwd: string, domain: string): void {
@@ -17,16 +17,49 @@ import {
17
17
  } from "../project-config.js"
18
18
  import { readEnvValue, upsertEnvFile } from "../env-file.js"
19
19
  import { hasEngineOverride } from "../binary-cache.js"
20
+ import { readDevSessionLock } from "../dev-session-lock.js"
21
+ import { composeProjectName } from "../self-host-compose.js"
20
22
  import { confirm as uiConfirm } from "../ui/confirm.js"
21
23
  import { error, info, plain } from "../ui/messages.js"
22
- import { promptText } from "../ui/prompts.js"
24
+ import { promptPassword, promptText } from "../ui/prompts.js"
23
25
  import { isInteractive } from "../ui/interactive.js"
26
+ import {
27
+ getActiveDevSession,
28
+ } from "../dev-session.js"
24
29
 
25
30
  export const ADMIN_EMAIL_ENV = "SUPATYPE_ADMIN_EMAIL"
26
31
  export const ADMIN_PASSWORD_ENV = "SUPATYPE_ADMIN_PASSWORD"
27
32
 
28
33
  const BCRYPT_ROUNDS = 10
29
34
 
35
+ /** GoTrue scopes users to the nil instance id in single-tenant/self-host mode. */
36
+ export const GOTRUE_NIL_INSTANCE_ID = "00000000-0000-0000-0000-000000000000"
37
+
38
+ /** Audience claim used by GoTrue when looking up users (matches GOTRUE_JWT_AUD in compose). */
39
+ export function gotrueJwtAud(cwd: string): string {
40
+ return readEnvValue(cwd, "GOTRUE_JWT_AUD", "authenticated")
41
+ }
42
+
43
+ type DbQuery = (sql: string, params?: unknown[]) => Promise<QueryResult>
44
+ type AuthConfirmedColumn = "email_confirmed_at" | "confirmed_at"
45
+
46
+ /** Prefer GoTrue's column when migrated; fall back to postgres init `confirmed_at`. */
47
+ export async function resolveAuthConfirmedAtColumn(query: DbQuery): Promise<AuthConfirmedColumn> {
48
+ const result = await query(
49
+ `SELECT column_name
50
+ FROM information_schema.columns
51
+ WHERE table_schema = 'auth'
52
+ AND table_name = 'users'
53
+ AND column_name IN ('email_confirmed_at', 'confirmed_at')
54
+ ORDER BY CASE column_name WHEN 'email_confirmed_at' THEN 0 ELSE 1 END
55
+ LIMIT 1`,
56
+ )
57
+ const row = result.rows[0] as { column_name?: string; value?: string } | undefined
58
+ const name = row?.column_name ?? row?.value
59
+ if (name === "email_confirmed_at" || name === "confirmed_at") return name
60
+ return "confirmed_at"
61
+ }
62
+
30
63
  export interface EnsureFirstAdminOptions {
31
64
  email?: string
32
65
  password?: string
@@ -36,8 +69,6 @@ export interface EnsureFirstAdminOptions {
36
69
  compose?: { project: string; composePath: string }
37
70
  }
38
71
 
39
- type DbQuery = (sql: string, params?: unknown[]) => Promise<QueryResult>
40
-
41
72
  export function registerAdmin(program: Command): void {
42
73
  const adminCmd = program
43
74
  .command("admin")
@@ -78,20 +109,33 @@ export function registerAdmin(program: Command): void {
78
109
 
79
110
  info(`Creating admin user: ${email} (role: ${role})...`)
80
111
 
81
- const pg = await importPg()
82
- const pool = new pg.Pool({ connectionString: connection, max: 2 })
112
+ const compose =
113
+ opts.connection === undefined ? resolveDockerComposeContext(cwd, config) : null
83
114
 
84
115
  try {
85
- await ensureAuthUsersTable(pool)
86
- await createAdminUser(pool, email, password, role)
116
+ if (compose) {
117
+ await createAdminUser(
118
+ (sql, params) => composeExecQuery(cwd, compose, sql, params),
119
+ email,
120
+ password,
121
+ role,
122
+ { cwd },
123
+ )
124
+ } else {
125
+ const pg = await importPg()
126
+ const pool = new pg.Pool({ connectionString: connection, max: 2 })
127
+ try {
128
+ await ensureAuthUsersTable(pool)
129
+ await createAdminUser(pool, email, password, role, { cwd })
130
+ } finally {
131
+ await pool.end()
132
+ }
133
+ }
87
134
  info("This user can now log in to the admin panel at /admin")
88
135
  } catch (err) {
89
- const message =
90
- err instanceof Error ? err.message : "Unknown error"
136
+ const message = err instanceof Error ? err.message : "Unknown error"
91
137
  error(`Failed to create admin user: ${message}`)
92
138
  process.exit(1)
93
- } finally {
94
- await pool.end()
95
139
  }
96
140
  },
97
141
  )
@@ -249,8 +293,9 @@ export async function ensureFirstAdminUserForProject(
249
293
  (sql, params) => composeExecQuery(root, merged.compose!, sql, params),
250
294
  merged,
251
295
  )
252
- } catch {
253
- // Non-fatal
296
+ } catch (err) {
297
+ const message = err instanceof Error ? err.message : String(err)
298
+ error(`Could not ensure first admin user: ${message}`)
254
299
  }
255
300
  return
256
301
  }
@@ -284,9 +329,27 @@ async function ensureFirstAdminWithQuery(
284
329
  }
285
330
 
286
331
  const role = options.role ?? "admin"
287
- await createAdminUser(query, credentials.email, credentials.password, role, { quiet: true })
332
+ try {
333
+ await createAdminUser(query, credentials.email, credentials.password, role, {
334
+ quiet: true,
335
+ cwd,
336
+ })
337
+ } catch (err) {
338
+ const message = err instanceof Error ? err.message : String(err)
339
+ error(`Failed to create admin user: ${message}`)
340
+ return
341
+ }
288
342
  clearAdminSeedPassword(cwd)
289
- info(`Admin user "${credentials.email}" created (role: ${role}).`)
343
+ logFirstAdminCreated(credentials.email, role)
344
+ }
345
+
346
+ function logFirstAdminCreated(email: string, role: string): void {
347
+ if (getActiveDevSession()?.isTui()) {
348
+ console.log(`Admin user "${email}" created (role: ${role}).`)
349
+ console.log("Log in at /admin after starting the dev server.")
350
+ return
351
+ }
352
+ info(`Admin user "${email}" created (role: ${role}).`)
290
353
  info("Log in at /admin after starting the dev server.")
291
354
  }
292
355
 
@@ -325,7 +388,7 @@ async function resolveAdminCredentials(
325
388
  return null
326
389
  }
327
390
 
328
- const password = await promptText("Admin password (min 8 chars)")
391
+ const password = await promptPassword("Admin password (min 8 chars)")
329
392
  if (!password || password.length < 8) {
330
393
  info("Password too short. Skipping admin user creation.")
331
394
  return null
@@ -347,7 +410,7 @@ async function createAdminUser(
347
410
  email: string,
348
411
  password: string,
349
412
  role: string,
350
- opts: { quiet?: boolean } = {},
413
+ opts: { quiet?: boolean; aud?: string; cwd?: string } = {},
351
414
  ): Promise<{ id: string; email: string }> {
352
415
  const query: DbQuery =
353
416
  typeof (db as Pool).query === "function"
@@ -355,9 +418,15 @@ async function createAdminUser(
355
418
  : (db as DbQuery)
356
419
 
357
420
  const normalized = email.toLowerCase()
358
- const existing = await query(`SELECT id FROM auth.users WHERE email = $1`, [
359
- normalized,
360
- ])
421
+ const aud = opts.aud ?? (opts.cwd ? gotrueJwtAud(opts.cwd) : "authenticated")
422
+ const existing = await query(
423
+ `SELECT id FROM auth.users
424
+ WHERE instance_id = $1::uuid
425
+ AND LOWER(email) = $2
426
+ AND aud = $3
427
+ AND is_sso_user = false`,
428
+ [GOTRUE_NIL_INSTANCE_ID, normalized, aud],
429
+ )
361
430
  if (existing.rows.length > 0) {
362
431
  throw new Error(`User with email "${email}" already exists.`)
363
432
  }
@@ -369,18 +438,27 @@ async function createAdminUser(
369
438
  providers: ["email"],
370
439
  })
371
440
  const userMetadata = JSON.stringify({})
441
+ const confirmedCol = await resolveAuthConfirmedAtColumn(query)
372
442
 
373
443
  const result = await query(
374
444
  `INSERT INTO auth.users (
375
- email, encrypted_password, role, aud,
445
+ instance_id, id, aud, role, email, encrypted_password,
376
446
  raw_app_meta_data, raw_user_meta_data,
377
- email_confirmed_at, created_at, updated_at
447
+ ${confirmedCol},
448
+ confirmation_token, recovery_token,
449
+ email_change_token_new, email_change, email_change_token_current,
450
+ phone_change, phone_change_token, reauthentication_token,
451
+ is_sso_user, is_anonymous,
452
+ created_at, updated_at
378
453
  ) VALUES (
379
- $1, $2, 'authenticated', 'authenticated',
380
- $3::jsonb, $4::jsonb,
381
- now(), now(), now()
454
+ $1::uuid, gen_random_uuid(), $2, 'authenticated', $3, $4,
455
+ $5::jsonb, $6::jsonb,
456
+ now(),
457
+ '', '', '', '', '', '', '', '',
458
+ false, false,
459
+ now(), now()
382
460
  ) RETURNING id, email`,
383
- [normalized, passwordHash, appMetadata, userMetadata],
461
+ [GOTRUE_NIL_INSTANCE_ID, aud, normalized, passwordHash, appMetadata, userMetadata],
384
462
  )
385
463
 
386
464
  const user = result.rows[0] as { id: string; email: string }
@@ -399,7 +477,7 @@ async function ensureAuthUsersTable(pool: Pool): Promise<void> {
399
477
 
400
478
  CREATE TABLE IF NOT EXISTS auth.users (
401
479
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
402
- instance_id UUID,
480
+ instance_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
403
481
  aud TEXT DEFAULT 'authenticated',
404
482
  role TEXT DEFAULT 'authenticated',
405
483
  email TEXT UNIQUE,
@@ -412,7 +490,13 @@ async function ensureAuthUsersTable(pool: Pool): Promise<void> {
412
490
  confirmation_token TEXT DEFAULT '',
413
491
  recovery_token TEXT DEFAULT '',
414
492
  email_change_token_new TEXT DEFAULT '',
415
- email_change TEXT DEFAULT ''
493
+ email_change_token_current TEXT DEFAULT '',
494
+ email_change TEXT DEFAULT '',
495
+ phone_change TEXT DEFAULT '',
496
+ phone_change_token TEXT DEFAULT '',
497
+ reauthentication_token TEXT DEFAULT '',
498
+ is_sso_user BOOLEAN NOT NULL DEFAULT false,
499
+ is_anonymous BOOLEAN NOT NULL DEFAULT false
416
500
  );
417
501
  `)
418
502
  }
@@ -437,6 +521,33 @@ async function hasAdminUsers(query: DbQuery): Promise<boolean> {
437
521
  return count > 0
438
522
  }
439
523
 
524
+ /** Postgres password for compose `exec psql` (db is not published to the host). */
525
+ export function composePostgresPassword(cwd: string): string {
526
+ return readEnvValue(cwd, "POSTGRES_PASSWORD", "postgres")
527
+ }
528
+
529
+ function resolveDockerComposeContext(
530
+ cwd: string,
531
+ config: SupatypeProjectConfig,
532
+ ): { project: string; composePath: string } | null {
533
+ if (resolveRuntimeProvider(config) !== "docker" || hasEngineOverride(config)) {
534
+ return null
535
+ }
536
+
537
+ const session = readDevSessionLock(cwd)
538
+ if (session?.composeProject && session.composePath && existsSync(session.composePath)) {
539
+ return { project: session.composeProject, composePath: session.composePath }
540
+ }
541
+
542
+ const composePath = resolve(cwd, ".supatype/self-host/docker-compose.yml")
543
+ if (!existsSync(composePath)) return null
544
+
545
+ return {
546
+ project: composeProjectName(config.project?.name ?? "project"),
547
+ composePath,
548
+ }
549
+ }
550
+
440
551
  function composeExecQuery(
441
552
  cwd: string,
442
553
  compose: { project: string; composePath: string },
@@ -445,6 +556,7 @@ function composeExecQuery(
445
556
  ): Promise<QueryResult> {
446
557
  const db = readEnvValue(cwd, "POSTGRES_DB", "supatype")
447
558
  const user = readEnvValue(cwd, "POSTGRES_USER", "supatype_admin")
559
+ const pgPassword = composePostgresPassword(cwd)
448
560
  const envFile = join(cwd, ".env")
449
561
  const composeDir = dirname(compose.composePath)
450
562
  const args = [
@@ -459,7 +571,20 @@ function composeExecQuery(
459
571
  if (existsSync(envFile)) args.push("--env-file", envFile)
460
572
 
461
573
  if (params.length === 0) {
462
- args.push("exec", "-T", "db", "psql", "-U", user, "-d", db, "-tAc", sql)
574
+ args.push(
575
+ "exec",
576
+ "-T",
577
+ "-e",
578
+ `PGPASSWORD=${pgPassword}`,
579
+ "db",
580
+ "psql",
581
+ "-U",
582
+ user,
583
+ "-d",
584
+ db,
585
+ "-tAc",
586
+ sql,
587
+ )
463
588
  const result = spawnSync("docker", args, { cwd: composeDir, encoding: "utf8" })
464
589
  if (result.status !== 0) {
465
590
  throw new Error((result.stderr ?? result.stdout ?? "compose psql failed").trim())
@@ -486,6 +611,8 @@ function composeExecQuery(
486
611
  args.push(
487
612
  "exec",
488
613
  "-T",
614
+ "-e",
615
+ `PGPASSWORD=${pgPassword}`,
489
616
  "db",
490
617
  "psql",
491
618
  "-U",