@supatype/cli 0.1.1 → 0.1.2

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 (316) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +114 -90
  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.map +1 -1
  22. package/dist/commands/admin.js +22 -6
  23. package/dist/commands/admin.js.map +1 -1
  24. package/dist/commands/cache.d.ts +1 -1
  25. package/dist/commands/cache.d.ts.map +1 -1
  26. package/dist/commands/cache.js +98 -5
  27. package/dist/commands/cache.js.map +1 -1
  28. package/dist/commands/dev.d.ts.map +1 -1
  29. package/dist/commands/dev.js +26 -22
  30. package/dist/commands/dev.js.map +1 -1
  31. package/dist/commands/init.d.ts +3 -4
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js +238 -168
  34. package/dist/commands/init.js.map +1 -1
  35. package/dist/commands/link-helpers.d.ts.map +1 -1
  36. package/dist/commands/link-helpers.js +26 -25
  37. package/dist/commands/link-helpers.js.map +1 -1
  38. package/dist/compose-local-server-image.d.ts +13 -0
  39. package/dist/compose-local-server-image.d.ts.map +1 -0
  40. package/dist/compose-local-server-image.js +57 -0
  41. package/dist/compose-local-server-image.js.map +1 -0
  42. package/dist/compose-rename.d.ts.map +1 -1
  43. package/dist/compose-rename.js +5 -8
  44. package/dist/compose-rename.js.map +1 -1
  45. package/dist/dev-compose.d.ts.map +1 -1
  46. package/dist/dev-compose.js +111 -54
  47. package/dist/dev-compose.js.map +1 -1
  48. package/dist/dev-log-bus.d.ts +5 -0
  49. package/dist/dev-log-bus.d.ts.map +1 -1
  50. package/dist/dev-log-bus.js +14 -0
  51. package/dist/dev-log-bus.js.map +1 -1
  52. package/dist/dev-log-filter.d.ts +4 -0
  53. package/dist/dev-log-filter.d.ts.map +1 -1
  54. package/dist/dev-log-filter.js +52 -0
  55. package/dist/dev-log-filter.js.map +1 -1
  56. package/dist/dev-ports.d.ts.map +1 -1
  57. package/dist/dev-ports.js +19 -12
  58. package/dist/dev-ports.js.map +1 -1
  59. package/dist/dev-ready-panel.d.ts +19 -0
  60. package/dist/dev-ready-panel.d.ts.map +1 -0
  61. package/dist/dev-ready-panel.js +49 -0
  62. package/dist/dev-ready-panel.js.map +1 -0
  63. package/dist/dev-session-lock.d.ts.map +1 -1
  64. package/dist/dev-session-lock.js +5 -8
  65. package/dist/dev-session-lock.js.map +1 -1
  66. package/dist/dev-session.d.ts +18 -5
  67. package/dist/dev-session.d.ts.map +1 -1
  68. package/dist/dev-session.js +91 -18
  69. package/dist/dev-session.js.map +1 -1
  70. package/dist/dev-shutdown.d.ts +2 -0
  71. package/dist/dev-shutdown.d.ts.map +1 -1
  72. package/dist/dev-shutdown.js +29 -15
  73. package/dist/dev-shutdown.js.map +1 -1
  74. package/dist/dev-task-colors.d.ts +3 -1
  75. package/dist/dev-task-colors.d.ts.map +1 -1
  76. package/dist/dev-task-colors.js +23 -3
  77. package/dist/dev-task-colors.js.map +1 -1
  78. package/dist/docker-runtime.js +1 -1
  79. package/dist/docker-runtime.js.map +1 -1
  80. package/dist/engine-push-output.d.ts +1 -0
  81. package/dist/engine-push-output.d.ts.map +1 -1
  82. package/dist/engine-push-output.js +4 -1
  83. package/dist/engine-push-output.js.map +1 -1
  84. package/dist/ensure-binary.d.ts.map +1 -1
  85. package/dist/ensure-binary.js +14 -2
  86. package/dist/ensure-binary.js.map +1 -1
  87. package/dist/ensure-component-binaries.d.ts +17 -0
  88. package/dist/ensure-component-binaries.d.ts.map +1 -0
  89. package/dist/ensure-component-binaries.js +45 -0
  90. package/dist/ensure-component-binaries.js.map +1 -0
  91. package/dist/ensure-dev-api-config.d.ts +3 -0
  92. package/dist/ensure-dev-api-config.d.ts.map +1 -0
  93. package/dist/ensure-dev-api-config.js +17 -0
  94. package/dist/ensure-dev-api-config.js.map +1 -0
  95. package/dist/init-dependency-versions.d.ts +13 -0
  96. package/dist/init-dependency-versions.d.ts.map +1 -0
  97. package/dist/init-dependency-versions.js +53 -0
  98. package/dist/init-dependency-versions.js.map +1 -0
  99. package/dist/init-package-json.d.ts +21 -0
  100. package/dist/init-package-json.d.ts.map +1 -0
  101. package/dist/init-package-json.js +46 -0
  102. package/dist/init-package-json.js.map +1 -0
  103. package/dist/postgres-ctl.d.ts.map +1 -1
  104. package/dist/postgres-ctl.js +2 -1
  105. package/dist/postgres-ctl.js.map +1 -1
  106. package/dist/required-host-components.d.ts +11 -0
  107. package/dist/required-host-components.d.ts.map +1 -0
  108. package/dist/required-host-components.js +25 -0
  109. package/dist/required-host-components.js.map +1 -0
  110. package/dist/resolve-api-url.d.ts +6 -0
  111. package/dist/resolve-api-url.d.ts.map +1 -0
  112. package/dist/resolve-api-url.js +39 -0
  113. package/dist/resolve-api-url.js.map +1 -0
  114. package/dist/rest-cache-admin.d.ts +33 -0
  115. package/dist/rest-cache-admin.d.ts.map +1 -0
  116. package/dist/rest-cache-admin.js +96 -0
  117. package/dist/rest-cache-admin.js.map +1 -0
  118. package/dist/scripts/postinstall.d.ts +4 -6
  119. package/dist/scripts/postinstall.d.ts.map +1 -1
  120. package/dist/scripts/postinstall.js +8 -41
  121. package/dist/scripts/postinstall.js.map +1 -1
  122. package/dist/self-host-compose.d.ts.map +1 -1
  123. package/dist/self-host-compose.js +23 -13
  124. package/dist/self-host-compose.js.map +1 -1
  125. package/dist/studio-dev-server.d.ts +4 -2
  126. package/dist/studio-dev-server.d.ts.map +1 -1
  127. package/dist/studio-dev-server.js +3 -2
  128. package/dist/studio-dev-server.js.map +1 -1
  129. package/dist/ui/brand.d.ts +2 -5
  130. package/dist/ui/brand.d.ts.map +1 -1
  131. package/dist/ui/brand.js +2 -7
  132. package/dist/ui/brand.js.map +1 -1
  133. package/dist/ui/clack-api.d.ts +44 -0
  134. package/dist/ui/clack-api.d.ts.map +1 -0
  135. package/dist/ui/clack-api.js +76 -0
  136. package/dist/ui/clack-api.js.map +1 -0
  137. package/dist/ui/clack.d.ts +14 -0
  138. package/dist/ui/clack.d.ts.map +1 -0
  139. package/dist/ui/clack.js +147 -0
  140. package/dist/ui/clack.js.map +1 -0
  141. package/dist/ui/components/FlowSpinner.d.ts +5 -0
  142. package/dist/ui/components/FlowSpinner.d.ts.map +1 -0
  143. package/dist/ui/components/FlowSpinner.js +8 -0
  144. package/dist/ui/components/FlowSpinner.js.map +1 -0
  145. package/dist/ui/components/LogoWordmark.d.ts +9 -0
  146. package/dist/ui/components/LogoWordmark.d.ts.map +1 -0
  147. package/dist/ui/components/LogoWordmark.js +17 -0
  148. package/dist/ui/components/LogoWordmark.js.map +1 -0
  149. package/dist/ui/components/PromptPanel.d.ts +5 -0
  150. package/dist/ui/components/PromptPanel.d.ts.map +1 -0
  151. package/dist/ui/components/PromptPanel.js +7 -0
  152. package/dist/ui/components/PromptPanel.js.map +1 -0
  153. package/dist/ui/components/SelectField.d.ts +11 -0
  154. package/dist/ui/components/SelectField.d.ts.map +1 -0
  155. package/dist/ui/components/SelectField.js +19 -0
  156. package/dist/ui/components/SelectField.js.map +1 -0
  157. package/dist/ui/confirm.d.ts +2 -1
  158. package/dist/ui/confirm.d.ts.map +1 -1
  159. package/dist/ui/confirm.js +4 -4
  160. package/dist/ui/confirm.js.map +1 -1
  161. package/dist/ui/dev/DevDashboard.d.ts +8 -0
  162. package/dist/ui/dev/DevDashboard.d.ts.map +1 -0
  163. package/dist/ui/dev/DevDashboard.js +151 -0
  164. package/dist/ui/dev/DevDashboard.js.map +1 -0
  165. package/dist/ui/dev/DevReadyPanelView.d.ts +7 -0
  166. package/dist/ui/dev/DevReadyPanelView.d.ts.map +1 -0
  167. package/dist/ui/dev/DevReadyPanelView.js +29 -0
  168. package/dist/ui/dev/DevReadyPanelView.js.map +1 -0
  169. package/dist/ui/fatal.d.ts.map +1 -1
  170. package/dist/ui/fatal.js +5 -11
  171. package/dist/ui/fatal.js.map +1 -1
  172. package/dist/ui/flows/FlowApp.d.ts +8 -0
  173. package/dist/ui/flows/FlowApp.d.ts.map +1 -0
  174. package/dist/ui/flows/FlowApp.js +42 -0
  175. package/dist/ui/flows/FlowApp.js.map +1 -0
  176. package/dist/ui/flows/prompt-fields.d.ts +48 -0
  177. package/dist/ui/flows/prompt-fields.d.ts.map +1 -0
  178. package/dist/ui/flows/prompt-fields.js +88 -0
  179. package/dist/ui/flows/prompt-fields.js.map +1 -0
  180. package/dist/ui/flows/types.d.ts +41 -0
  181. package/dist/ui/flows/types.d.ts.map +1 -0
  182. package/dist/ui/flows/types.js +2 -0
  183. package/dist/ui/flows/types.js.map +1 -0
  184. package/dist/ui/index.d.ts +1 -1
  185. package/dist/ui/index.js +1 -1
  186. package/dist/ui/messages.d.ts +1 -0
  187. package/dist/ui/messages.d.ts.map +1 -1
  188. package/dist/ui/messages.js +48 -8
  189. package/dist/ui/messages.js.map +1 -1
  190. package/dist/ui/progress.d.ts +5 -1
  191. package/dist/ui/progress.d.ts.map +1 -1
  192. package/dist/ui/progress.js +12 -3
  193. package/dist/ui/progress.js.map +1 -1
  194. package/dist/ui/prompts.d.ts +7 -5
  195. package/dist/ui/prompts.d.ts.map +1 -1
  196. package/dist/ui/prompts.js +15 -8
  197. package/dist/ui/prompts.js.map +1 -1
  198. package/dist/ui/runtime/cancel.d.ts +4 -0
  199. package/dist/ui/runtime/cancel.d.ts.map +1 -0
  200. package/dist/ui/runtime/cancel.js +6 -0
  201. package/dist/ui/runtime/cancel.js.map +1 -0
  202. package/dist/ui/runtime/command-chrome.d.ts +17 -0
  203. package/dist/ui/runtime/command-chrome.d.ts.map +1 -0
  204. package/dist/ui/runtime/command-chrome.js +123 -0
  205. package/dist/ui/runtime/command-chrome.js.map +1 -0
  206. package/dist/ui/runtime/dev-prompt-queue.d.ts +30 -0
  207. package/dist/ui/runtime/dev-prompt-queue.d.ts.map +1 -0
  208. package/dist/ui/runtime/dev-prompt-queue.js +57 -0
  209. package/dist/ui/runtime/dev-prompt-queue.js.map +1 -0
  210. package/dist/ui/runtime/flow-session.d.ts +4 -0
  211. package/dist/ui/runtime/flow-session.d.ts.map +1 -0
  212. package/dist/ui/runtime/flow-session.js +8 -0
  213. package/dist/ui/runtime/flow-session.js.map +1 -0
  214. package/dist/ui/runtime/run-clack-flow.d.ts +5 -0
  215. package/dist/ui/runtime/run-clack-flow.d.ts.map +1 -0
  216. package/dist/ui/runtime/run-clack-flow.js +34 -0
  217. package/dist/ui/runtime/run-clack-flow.js.map +1 -0
  218. package/dist/ui/theme.d.ts +24 -0
  219. package/dist/ui/theme.d.ts.map +1 -0
  220. package/dist/ui/theme.js +34 -0
  221. package/dist/ui/theme.js.map +1 -0
  222. package/dist/valkey-sidecar.d.ts +17 -0
  223. package/dist/valkey-sidecar.d.ts.map +1 -0
  224. package/dist/valkey-sidecar.js +94 -0
  225. package/dist/valkey-sidecar.js.map +1 -0
  226. package/package.json +9 -3
  227. package/src/binary-cache.ts +61 -0
  228. package/src/binary-download-lock.ts +124 -0
  229. package/src/cli-package-version.ts +15 -0
  230. package/src/cli.ts +6 -2
  231. package/src/commands/add.ts +26 -19
  232. package/src/commands/admin.ts +24 -6
  233. package/src/commands/cache.ts +105 -5
  234. package/src/commands/dev.ts +26 -21
  235. package/src/commands/init.ts +124 -45
  236. package/src/commands/link-helpers.ts +30 -29
  237. package/src/compose-local-server-image.ts +68 -0
  238. package/src/compose-rename.ts +5 -8
  239. package/src/dev-compose.ts +136 -51
  240. package/src/dev-log-bus.ts +18 -0
  241. package/src/dev-log-filter.ts +42 -0
  242. package/src/dev-ports.ts +22 -11
  243. package/src/dev-ready-panel.ts +63 -0
  244. package/src/dev-session-lock.ts +5 -8
  245. package/src/dev-session.ts +98 -18
  246. package/src/dev-shutdown.ts +29 -17
  247. package/src/dev-task-colors.ts +22 -3
  248. package/src/docker-runtime.ts +1 -1
  249. package/src/engine-push-output.ts +5 -1
  250. package/src/ensure-binary.ts +21 -1
  251. package/src/ensure-component-binaries.ts +71 -0
  252. package/src/ensure-dev-api-config.ts +18 -0
  253. package/src/init-dependency-versions.ts +69 -0
  254. package/src/init-package-json.ts +63 -0
  255. package/src/postgres-ctl.ts +2 -1
  256. package/src/required-host-components.ts +37 -0
  257. package/src/resolve-api-url.ts +43 -0
  258. package/src/rest-cache-admin.ts +135 -0
  259. package/src/scripts/postinstall.ts +9 -46
  260. package/src/self-host-compose.ts +22 -12
  261. package/src/studio-dev-server.ts +5 -4
  262. package/src/ui/README.md +13 -9
  263. package/src/ui/brand.ts +2 -8
  264. package/src/ui/clack-api.ts +123 -0
  265. package/src/ui/clack.ts +153 -0
  266. package/src/ui/components/FlowSpinner.tsx +15 -0
  267. package/src/ui/components/LogoWordmark.tsx +36 -0
  268. package/src/ui/components/PromptPanel.tsx +17 -0
  269. package/src/ui/components/SelectField.tsx +58 -0
  270. package/src/ui/confirm.ts +5 -4
  271. package/src/ui/dev/DevDashboard.tsx +213 -0
  272. package/src/ui/dev/DevReadyPanelView.tsx +67 -0
  273. package/src/ui/fatal.ts +5 -10
  274. package/src/ui/flows/FlowApp.tsx +67 -0
  275. package/src/ui/flows/prompt-fields.tsx +192 -0
  276. package/src/ui/flows/types.ts +50 -0
  277. package/src/ui/index.ts +1 -1
  278. package/src/ui/messages.ts +50 -8
  279. package/src/ui/progress.ts +14 -3
  280. package/src/ui/prompts.ts +17 -9
  281. package/src/ui/runtime/cancel.ts +6 -0
  282. package/src/ui/runtime/command-chrome.ts +147 -0
  283. package/src/ui/runtime/dev-prompt-queue.ts +84 -0
  284. package/src/ui/runtime/flow-session.ts +11 -0
  285. package/src/ui/runtime/run-clack-flow.tsx +52 -0
  286. package/src/ui/theme.ts +41 -0
  287. package/src/valkey-sidecar.ts +126 -0
  288. package/tests/binary-cache-cloud-overrides.test.ts +2 -2
  289. package/tests/binary-download-lock.test.ts +41 -0
  290. package/tests/cli-help.test.ts +7 -4
  291. package/tests/cli-package-version.test.ts +15 -0
  292. package/tests/command-chrome-coverage.test.ts +149 -0
  293. package/tests/command-chrome-wrap.test.ts +51 -0
  294. package/tests/config.test.ts +8 -4
  295. package/tests/dev-ready-panel.test.ts +20 -0
  296. package/tests/dev-ui.test.ts +42 -2
  297. package/tests/docker-runtime.test.ts +9 -20
  298. package/tests/ensure-dev-api-config.test.ts +22 -0
  299. package/tests/init-dependency-versions.test.ts +62 -0
  300. package/tests/init-package-json.test.ts +18 -0
  301. package/tests/init.test.ts +30 -3
  302. package/tests/required-host-components.test.ts +51 -0
  303. package/tests/resolve-api-url.test.ts +23 -0
  304. package/tests/rest-cache-admin.test.ts +28 -0
  305. package/tests/runtime-contract.test.ts +12 -3
  306. package/tests/tsconfig.json +8 -2
  307. package/tests/ui-confirm.test.ts +13 -9
  308. package/tests/ui-messages.test.ts +4 -18
  309. package/tsconfig.json +1 -0
  310. package/tsconfig.tsbuildinfo +1 -1
  311. package/vitest.config.ts +3 -0
  312. package/dist/dev-tui.d.ts +0 -24
  313. package/dist/dev-tui.d.ts.map +0 -1
  314. package/dist/dev-tui.js +0 -188
  315. package/dist/dev-tui.js.map +0 -1
  316. package/src/dev-tui.ts +0 -232
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Supatype terminal design tokens — shared by Ink components and plain CI output.
3
+ */
4
+ export const RESET = "\x1b[0m";
5
+ export const DIM = "\x1b[2m";
6
+ export const BOLD = "\x1b[1m";
7
+ export const theme = {
8
+ brand: "magenta",
9
+ brandHex: "#c084fc",
10
+ info: "cyan",
11
+ warn: "yellow",
12
+ error: "red",
13
+ success: "green",
14
+ dim: "gray",
15
+ muted: "gray",
16
+ };
17
+ /** Legacy ANSI exports used by dev-logo / dev-task-colors. */
18
+ export const BRAND_COLOR = "\x1b[35m";
19
+ export function brandStyle(text) {
20
+ return `${BRAND_COLOR}${BOLD}${text}${RESET}`;
21
+ }
22
+ export function plainInfo(message) {
23
+ return `${theme.info === "cyan" ? "\x1b[36m" : ""}ℹ ${message}${RESET}`;
24
+ }
25
+ export function plainWarn(message) {
26
+ return `\x1b[33m⚠ ${message}${RESET}`;
27
+ }
28
+ export function plainError(message) {
29
+ return `\x1b[31m✗ ${message}${RESET}`;
30
+ }
31
+ export function plainSuccess(message) {
32
+ return `\x1b[32m✓ ${message}${RESET}`;
33
+ }
34
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAA;AAC9B,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAA;AAC5B,MAAM,CAAC,MAAM,IAAI,GAAG,SAAS,CAAA;AAE7B,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,KAAK,EAAE,SAAkB;IACzB,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,MAAe;IACrB,IAAI,EAAE,QAAiB;IACvB,KAAK,EAAE,KAAc;IACrB,OAAO,EAAE,OAAgB;IACzB,GAAG,EAAE,MAAe;IACpB,KAAK,EAAE,MAAe;CACd,CAAA;AAEV,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAA;AAErC,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,GAAG,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,GAAG,KAAK,EAAE,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,aAAa,OAAO,GAAG,KAAK,EAAE,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,aAAa,OAAO,GAAG,KAAK,EAAE,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,aAAa,OAAO,GAAG,KAAK,EAAE,CAAA;AACvC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Lightweight Valkey container for native `supatype dev` (REST response cache).
3
+ */
4
+ export interface ValkeySidecarResult {
5
+ addr: string;
6
+ containerName: string | null;
7
+ started: boolean;
8
+ }
9
+ /**
10
+ * Ensure Valkey is reachable at 127.0.0.1:6379 for native dev.
11
+ * Starts a named Docker container when Docker is available and nothing is listening.
12
+ */
13
+ export declare function ensureValkeySidecar(projectName: string): ValkeySidecarResult;
14
+ export declare function stopValkeySidecar(containerName: string | null): void;
15
+ /** @internal Test helper — probe without subprocess. */
16
+ export declare function probeTcp(host: string, port: number): Promise<boolean>;
17
+ //# sourceMappingURL=valkey-sidecar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valkey-sidecar.d.ts","sourceRoot":"","sources":["../src/valkey-sidecar.ts"],"names":[],"mappings":"AAAA;;GAEG;AA4CH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,CAgD5E;AAED,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAGpE;AAED,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAarE"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Lightweight Valkey container for native `supatype dev` (REST response cache).
3
+ */
4
+ import { spawnSync } from "node:child_process";
5
+ import { createConnection } from "node:net";
6
+ const DEFAULT_HOST = "127.0.0.1";
7
+ const DEFAULT_PORT = 6379;
8
+ const IMAGE = "valkey/valkey:8-alpine";
9
+ function containerName(projectName) {
10
+ const safe = projectName.replace(/[^a-zA-Z0-9_-]/g, "-").slice(0, 48);
11
+ return `supatype-valkey-dev-${safe}`;
12
+ }
13
+ function dockerAvailable() {
14
+ const r = spawnSync("docker", ["info"], { stdio: "ignore" });
15
+ return r.status === 0;
16
+ }
17
+ function isAddrReachable(host, port, timeoutMs = 800) {
18
+ try {
19
+ const r = spawnSync(process.execPath, [
20
+ "-e",
21
+ `const n=require('net');const s=n.createConnection({host:${JSON.stringify(host)},port:${port}});` +
22
+ `s.on('connect',()=>{s.end();process.exit(0)});s.on('error',()=>process.exit(1));` +
23
+ `setTimeout(()=>process.exit(1),${timeoutMs})`,
24
+ ], { stdio: "ignore" });
25
+ return r.status === 0;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ function sleepMs(ms) {
32
+ const end = Date.now() + ms;
33
+ while (Date.now() < end) {
34
+ /* spin */
35
+ }
36
+ }
37
+ /**
38
+ * Ensure Valkey is reachable at 127.0.0.1:6379 for native dev.
39
+ * Starts a named Docker container when Docker is available and nothing is listening.
40
+ */
41
+ export function ensureValkeySidecar(projectName) {
42
+ const envAddr = process.env["SUPATYPE_VALKEY_ADDR"]?.trim();
43
+ if (envAddr) {
44
+ return { addr: envAddr, containerName: null, started: false };
45
+ }
46
+ const addr = `${DEFAULT_HOST}:${DEFAULT_PORT}`;
47
+ if (isAddrReachable(DEFAULT_HOST, DEFAULT_PORT)) {
48
+ return { addr, containerName: null, started: false };
49
+ }
50
+ if (!dockerAvailable()) {
51
+ console.warn("[supatype] ⚠ Valkey not available (Docker not running). " +
52
+ "REST server cache (`cache({ server: true })`) will bypass until Valkey is reachable.");
53
+ return { addr: "", containerName: null, started: false };
54
+ }
55
+ const name = containerName(projectName);
56
+ spawnSync("docker", ["rm", "-f", name], { stdio: "ignore" });
57
+ const run = spawnSync("docker", ["run", "-d", "--name", name, "-p", `${DEFAULT_PORT}:6379`, IMAGE], { encoding: "utf8" });
58
+ if (run.status !== 0) {
59
+ const detail = (run.stderr || run.stdout || "").trim();
60
+ console.warn(`[supatype] ⚠ Could not start Valkey sidecar: ${detail || `exit ${run.status}`}\n` +
61
+ " REST server cache will bypass until Valkey is available.");
62
+ return { addr: "", containerName: null, started: false };
63
+ }
64
+ for (let i = 0; i < 30; i++) {
65
+ if (isAddrReachable(DEFAULT_HOST, DEFAULT_PORT)) {
66
+ console.log(`[supatype] Valkey sidecar running (${addr})`);
67
+ return { addr, containerName: name, started: true };
68
+ }
69
+ sleepMs(100);
70
+ }
71
+ console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet — cache may bypass initially.");
72
+ return { addr, containerName: name, started: true };
73
+ }
74
+ export function stopValkeySidecar(containerName) {
75
+ if (!containerName)
76
+ return;
77
+ spawnSync("docker", ["rm", "-f", containerName], { stdio: "ignore" });
78
+ }
79
+ /** @internal Test helper — probe without subprocess. */
80
+ export function probeTcp(host, port) {
81
+ return new Promise((resolve) => {
82
+ const s = createConnection({ host, port });
83
+ s.once("connect", () => {
84
+ s.destroy();
85
+ resolve(true);
86
+ });
87
+ s.once("error", () => resolve(false));
88
+ setTimeout(() => {
89
+ s.destroy();
90
+ resolve(false);
91
+ }, 800);
92
+ });
93
+ }
94
+ //# sourceMappingURL=valkey-sidecar.js.map
@@ -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.2",
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 {
@@ -19,8 +19,11 @@ import { readEnvValue, upsertEnvFile } from "../env-file.js"
19
19
  import { hasEngineOverride } from "../binary-cache.js"
20
20
  import { confirm as uiConfirm } from "../ui/confirm.js"
21
21
  import { error, info, plain } from "../ui/messages.js"
22
- import { promptText } from "../ui/prompts.js"
22
+ import { promptPassword, promptText } from "../ui/prompts.js"
23
23
  import { isInteractive } from "../ui/interactive.js"
24
+ import {
25
+ getActiveDevSession,
26
+ } from "../dev-session.js"
24
27
 
25
28
  export const ADMIN_EMAIL_ENV = "SUPATYPE_ADMIN_EMAIL"
26
29
  export const ADMIN_PASSWORD_ENV = "SUPATYPE_ADMIN_PASSWORD"
@@ -284,9 +287,24 @@ async function ensureFirstAdminWithQuery(
284
287
  }
285
288
 
286
289
  const role = options.role ?? "admin"
287
- await createAdminUser(query, credentials.email, credentials.password, role, { quiet: true })
290
+ try {
291
+ await createAdminUser(query, credentials.email, credentials.password, role, { quiet: true })
292
+ } catch (err) {
293
+ const message = err instanceof Error ? err.message : String(err)
294
+ error(`Failed to create admin user: ${message}`)
295
+ return
296
+ }
288
297
  clearAdminSeedPassword(cwd)
289
- info(`Admin user "${credentials.email}" created (role: ${role}).`)
298
+ logFirstAdminCreated(credentials.email, role)
299
+ }
300
+
301
+ function logFirstAdminCreated(email: string, role: string): void {
302
+ if (getActiveDevSession()?.isTui()) {
303
+ console.log(`Admin user "${email}" created (role: ${role}).`)
304
+ console.log("Log in at /admin after starting the dev server.")
305
+ return
306
+ }
307
+ info(`Admin user "${email}" created (role: ${role}).`)
290
308
  info("Log in at /admin after starting the dev server.")
291
309
  }
292
310
 
@@ -325,7 +343,7 @@ async function resolveAdminCredentials(
325
343
  return null
326
344
  }
327
345
 
328
- const password = await promptText("Admin password (min 8 chars)")
346
+ const password = await promptPassword("Admin password (min 8 chars)")
329
347
  if (!password || password.length < 8) {
330
348
  info("Password too short. Skipping admin user creation.")
331
349
  return null
@@ -372,11 +390,11 @@ async function createAdminUser(
372
390
 
373
391
  const result = await query(
374
392
  `INSERT INTO auth.users (
375
- email, encrypted_password, role, aud,
393
+ id, email, encrypted_password, role, aud,
376
394
  raw_app_meta_data, raw_user_meta_data,
377
395
  email_confirmed_at, created_at, updated_at
378
396
  ) VALUES (
379
- $1, $2, 'authenticated', 'authenticated',
397
+ gen_random_uuid(), $1, $2, 'authenticated', 'authenticated',
380
398
  $3::jsonb, $4::jsonb,
381
399
  now(), now(), now()
382
400
  ) RETURNING id, email`,