@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
@@ -1,9 +1,8 @@
1
- import { describe, expect, it, vi, beforeEach, afterEach, afterAll } from "vitest"
1
+ import { describe, expect, it, vi, beforeEach, afterEach, afterAll, type MockInstance } from "vitest"
2
2
  import type { SpawnSyncReturns } from "node:child_process"
3
3
 
4
4
  const spawnSyncMock = vi.hoisted(() => vi.fn())
5
5
  const isInteractiveMock = vi.hoisted(() => vi.fn(() => false))
6
- const clackLogErrorMock = vi.hoisted(() => vi.fn())
7
6
  const clackNoteMock = vi.hoisted(() => vi.fn())
8
7
  const clackIntroMock = vi.hoisted(() => vi.fn())
9
8
  const printLogoMock = vi.hoisted(() => vi.fn())
@@ -16,18 +15,12 @@ vi.mock("../src/ui/interactive.js", () => ({
16
15
  isInteractive: isInteractiveMock,
17
16
  }))
18
17
 
19
- vi.mock("@clack/prompts", async (importOriginal) => {
20
- const original = await importOriginal<typeof import("@clack/prompts")>()
21
- return {
22
- ...original,
18
+ vi.mock("../src/ui/clack.js", () => ({
19
+ p: {
23
20
  intro: clackIntroMock,
24
21
  note: clackNoteMock,
25
- log: {
26
- ...original.log,
27
- error: clackLogErrorMock,
28
- },
29
- }
30
- })
22
+ },
23
+ }))
31
24
 
32
25
  vi.mock("../src/ui/prompts.js", async (importOriginal) => {
33
26
  const original = await importOriginal<typeof import("../src/ui/prompts.js")>()
@@ -124,7 +117,6 @@ describe("reportDockerUnavailable", () => {
124
117
  isInteractiveMock.mockReturnValue(false)
125
118
  errorMock.mockClear()
126
119
  logMock.mockClear()
127
- clackLogErrorMock.mockClear()
128
120
  clackNoteMock.mockClear()
129
121
  clackIntroMock.mockClear()
130
122
  printLogoMock.mockClear()
@@ -171,7 +163,7 @@ describe("reportDockerUnavailable", () => {
171
163
  expect(logMock.mock.calls.some((call) => String(call[0]).includes("docker-desktop"))).toBe(true)
172
164
  })
173
165
 
174
- it("uses Clack log + note in interactive mode", () => {
166
+ it("uses Ink intro + note and themed error in interactive mode", () => {
175
167
  isInteractiveMock.mockReturnValue(true)
176
168
 
177
169
  reportDockerUnavailable(
@@ -185,20 +177,17 @@ describe("reportDockerUnavailable", () => {
185
177
 
186
178
  expect(printLogoMock).toHaveBeenCalled()
187
179
  expect(clackIntroMock).toHaveBeenCalledWith("Local development")
188
- expect(clackLogErrorMock).toHaveBeenCalledWith(
189
- "Docker is installed but the daemon is not running.",
190
- )
180
+ expect(logMock.mock.calls.some((call) => String(call[0]).includes("daemon is not running"))).toBe(true)
191
181
  expect(clackNoteMock).toHaveBeenCalledWith(
192
182
  expect.stringContaining("Unpause Docker Desktop"),
193
183
  )
194
184
  expect(errorMock).not.toHaveBeenCalled()
195
- expect(logMock).not.toHaveBeenCalled()
196
185
  })
197
186
  })
198
187
 
199
188
  describe("requireDockerDaemon", () => {
200
- let exitMock: ReturnType<typeof vi.spyOn<typeof process, "exit">>
201
- let errorMock: ReturnType<typeof vi.spyOn<typeof console, "error">>
189
+ let exitMock: MockInstance<(code?: string | number | null | undefined) => never>
190
+ let errorMock: MockInstance<typeof console.error>
202
191
 
203
192
  beforeEach(() => {
204
193
  spawnSyncMock.mockReset()
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"
3
+ import { join } from "node:path"
4
+ import { tmpdir } from "node:os"
5
+ import { ensureDevApiConfig } from "../src/ensure-dev-api-config.js"
6
+
7
+ describe("ensureDevApiConfig()", () => {
8
+ it("copies config/api-config.json when target is missing", () => {
9
+ const dir = mkdtempSync(join(tmpdir(), "supatype-api-config-"))
10
+ const configDir = join(dir, "config")
11
+ const template = join(configDir, "api-config.json")
12
+ const target = join(dir, ".supatype", "api-config.json")
13
+
14
+ mkdirSync(configDir, { recursive: true })
15
+ writeFileSync(template, '{"rest":{"schema":"public"}}\n', "utf8")
16
+
17
+ expect(ensureDevApiConfig(dir)).toBe(true)
18
+ expect(existsSync(target)).toBe(true)
19
+ expect(readFileSync(target, "utf8")).toContain('"rest"')
20
+ expect(ensureDevApiConfig(dir)).toBe(false)
21
+ })
22
+ })
@@ -0,0 +1,62 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest"
2
+ import {
3
+ initDependencyVersionsFallback,
4
+ resolveInitDependencyVersions,
5
+ } from "../src/init-dependency-versions.js"
6
+
7
+ function mockRegistry(packages: Record<string, { latest: string; versions: string[] }>) {
8
+ vi.stubGlobal(
9
+ "fetch",
10
+ vi.fn(async (url: string) => {
11
+ const name = decodeURIComponent(url.replace("https://registry.npmjs.org/", ""))
12
+ const pkg = packages[name]
13
+ if (!pkg) return new Response(null, { status: 404 })
14
+ const versions = Object.fromEntries(pkg.versions.map((v) => [v, {}]))
15
+ return Response.json({ versions, "dist-tags": { latest: pkg.latest } })
16
+ }),
17
+ )
18
+ }
19
+
20
+ describe("resolveInitDependencyVersions", () => {
21
+ afterEach(() => {
22
+ vi.unstubAllGlobals()
23
+ })
24
+
25
+ it("uses the running CLI version when both packages publish it", async () => {
26
+ mockRegistry({
27
+ "@supatype/cli": { latest: "0.1.3", versions: ["0.1.1", "0.1.3"] },
28
+ "@supatype/types": { latest: "0.1.3", versions: ["0.1.1", "0.1.3"] },
29
+ })
30
+
31
+ const deps = await resolveInitDependencyVersions()
32
+ expect(deps.cli).toBe("0.1.3")
33
+ expect(deps.types).toBe("0.1.3")
34
+ })
35
+
36
+ it("falls back to npm latest when the running CLI version is unpublished", async () => {
37
+ mockRegistry({
38
+ "@supatype/cli": { latest: "0.1.1", versions: ["0.1.1"] },
39
+ "@supatype/types": { latest: "0.1.1", versions: ["0.1.1"] },
40
+ })
41
+
42
+ const deps = await resolveInitDependencyVersions()
43
+ expect(deps.cli).toBe("0.1.1")
44
+ expect(deps.types).toBe("0.1.1")
45
+ })
46
+
47
+ it("can pin cli and types to different published versions", async () => {
48
+ mockRegistry({
49
+ "@supatype/cli": { latest: "0.1.3", versions: ["0.1.1", "0.1.3"] },
50
+ "@supatype/types": { latest: "0.1.1", versions: ["0.1.1"] },
51
+ })
52
+
53
+ const deps = await resolveInitDependencyVersions()
54
+ expect(deps.cli).toBe("0.1.3")
55
+ expect(deps.types).toBe("0.1.1")
56
+ })
57
+
58
+ it("falls back to the running CLI version when the registry is unreachable", async () => {
59
+ vi.stubGlobal("fetch", vi.fn(async () => new Response(null, { status: 500 })))
60
+ expect(await resolveInitDependencyVersions()).toEqual(initDependencyVersionsFallback())
61
+ })
62
+ })
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { mergeSupatypePackageJson } from "../src/init-package-json.js"
3
+
4
+ describe("mergeSupatypePackageJson", () => {
5
+ it("adds Supatype deps and scripts without overwriting existing dev script", () => {
6
+ const merged = mergeSupatypePackageJson(
7
+ { name: "existing", scripts: { dev: "next dev" } },
8
+ { projectName: "existing", app: { mode: "none" }, helloFunction: false },
9
+ { cli: "0.1.1", types: "0.1.1" },
10
+ )
11
+
12
+ expect(merged.dependencies?.["@supatype/cli"]).toBe("^0.1.1")
13
+ expect(merged.dependencies?.["@supatype/types"]).toBe("^0.1.1")
14
+ expect(merged.scripts?.dev).toBe("next dev")
15
+ expect(merged.scripts?.["supatype:dev"]).toBe("supatype dev")
16
+ expect(merged.scripts?.push).toBe("supatype push")
17
+ })
18
+ })
@@ -53,11 +53,15 @@ describe("scaffold()", () => {
53
53
  expect(content).toContain("pkg-app")
54
54
  })
55
55
 
56
- it("skips package.json when it already exists", () => {
56
+ it("merges Supatype deps into package.json when it already exists", () => {
57
57
  const pkgPath = join(tmpRoot, "package.json")
58
- writeFileSync(pkgPath, '{"name":"existing"}', "utf8")
58
+ writeFileSync(pkgPath, '{"name":"existing","scripts":{"dev":"next dev"}}', "utf8")
59
59
  scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
60
- expect(readFileSync(pkgPath, "utf8")).toBe('{"name":"existing"}')
60
+ const content = readFileSync(pkgPath, "utf8")
61
+ expect(content).toContain("@supatype/cli")
62
+ expect(content).toContain("@supatype/types")
63
+ expect(content).toContain("next dev")
64
+ expect(content).toContain("supatype:dev")
61
65
  })
62
66
 
63
67
  it("supatype.config.ts documents self-host workflow", () => {
@@ -185,6 +189,29 @@ describe("scaffold()", () => {
185
189
  expect(html).toContain("github.com/supatype")
186
190
  })
187
191
 
192
+ it("static app mode with Vite on self-host splits production static and local proxy override", () => {
193
+ scaffold(tmpRoot, {
194
+ ...defaultScaffoldOptions("my-app", "self-host"),
195
+ domain: "api.example.com",
196
+ app: {
197
+ mode: "static",
198
+ staticDir: "./public",
199
+ viteDevUrl: "http://127.0.0.1:5173",
200
+ },
201
+ })
202
+ const committed = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
203
+ expect(committed).toContain('mode: "static"')
204
+ expect(committed).toContain('static_dir: "./dist"')
205
+ expect(committed).not.toContain("vite_dev_url")
206
+
207
+ const local = readFileSync(join(tmpRoot, "supatype.local.config.ts"), "utf8")
208
+ expect(local).toContain('mode: "proxy"')
209
+ expect(local).toContain('start: "vite"')
210
+ expect(local).toContain('vite_dev_url: "http://127.0.0.1:5173"')
211
+ expect(existsSync(join(tmpRoot, "dist/index.html"))).toBe(true)
212
+ expect(existsSync(join(tmpRoot, "vite.config.ts"))).toBe(true)
213
+ })
214
+
188
215
  it("static app mode with Vite scaffolds root index.html and vite.config.ts", () => {
189
216
  scaffold(tmpRoot, {
190
217
  ...defaultScaffoldOptions("my-app"),
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { mkdirSync, rmSync } from "node:fs"
3
+ import { join } from "node:path"
4
+ import { tmpdir } from "node:os"
5
+ import { requiredHostComponents } from "../src/required-host-components.js"
6
+ import type { SupatypeProjectConfig } from "../src/project-config.js"
7
+
8
+ function baseConfig(provider: "docker" | "native"): SupatypeProjectConfig {
9
+ return {
10
+ project: { name: "test" },
11
+ provider,
12
+ database: { provider },
13
+ server: { mode: "dev" },
14
+ app: { mode: "none" },
15
+ }
16
+ }
17
+
18
+ describe("requiredHostComponents", () => {
19
+ it("returns engine for docker (types + admin config on the host)", () => {
20
+ expect(requiredHostComponents(baseConfig("docker"))).toEqual(["engine"])
21
+ })
22
+
23
+ it("returns engine for docker with overrides.engine", () => {
24
+ const config = baseConfig("docker")
25
+ config.overrides = { engine: "/path/to/engine" }
26
+ expect(requiredHostComponents(config)).toEqual(["engine"])
27
+ })
28
+
29
+ it("returns native core binaries without functions/", () => {
30
+ const dir = join(tmpdir(), `supatype-req-host-${Date.now()}`)
31
+ mkdirSync(dir, { recursive: true })
32
+ expect(requiredHostComponents(baseConfig("native"), dir)).toEqual([
33
+ "engine",
34
+ "server",
35
+ "postgres",
36
+ ])
37
+ rmSync(dir, { recursive: true, force: true })
38
+ })
39
+
40
+ it("includes deno for native when functions/ exists", () => {
41
+ const dir = join(tmpdir(), `supatype-req-host-fn-${Date.now()}`)
42
+ mkdirSync(join(dir, "functions"), { recursive: true })
43
+ expect(requiredHostComponents(baseConfig("native"), dir)).toEqual([
44
+ "engine",
45
+ "server",
46
+ "postgres",
47
+ "deno",
48
+ ])
49
+ rmSync(dir, { recursive: true, force: true })
50
+ })
51
+ })
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { mkdtempSync, writeFileSync } from "node:fs"
3
+ import { join } from "node:path"
4
+ import { tmpdir } from "node:os"
5
+ import { resolveProjectApiUrl } from "../src/resolve-api-url.js"
6
+
7
+ describe("resolveProjectApiUrl()", () => {
8
+ it("prefers PUBLIC_SUPATYPE_URL from .env (docker dev)", () => {
9
+ const cwd = mkdtempSync(join(tmpdir(), "supatype-api-url-"))
10
+ writeFileSync(
11
+ join(cwd, ".env"),
12
+ "PUBLIC_SUPATYPE_URL=http://localhost:18473\nPORT=54321\n",
13
+ "utf8",
14
+ )
15
+ expect(resolveProjectApiUrl(cwd)).toBe("http://localhost:18473")
16
+ })
17
+
18
+ it("uses SUPATYPE_KONG_PORT when no URL env is set", () => {
19
+ const cwd = mkdtempSync(join(tmpdir(), "supatype-api-url-"))
20
+ writeFileSync(join(cwd, ".env"), "SUPATYPE_KONG_PORT=19200\nPORT=54321\n", "utf8")
21
+ expect(resolveProjectApiUrl(cwd)).toBe("http://localhost:19200")
22
+ })
23
+ })
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it, vi } from "vitest"
2
+
3
+ vi.mock("../src/env-file.js", () => ({
4
+ readEnvValue: () => "test-service-role-key",
5
+ }))
6
+
7
+ vi.mock("../src/resolve-api-url.js", () => ({
8
+ resolveProjectApiUrl: () => "http://localhost:1234",
9
+ }))
10
+
11
+ describe("listRestCacheEntries", () => {
12
+ it("coerces null entries to an empty array", async () => {
13
+ const { listRestCacheEntries } = await import("../src/rest-cache-admin.js")
14
+
15
+ const originalFetch = globalThis.fetch
16
+ globalThis.fetch = vi.fn(async () =>
17
+ new Response(JSON.stringify({ entries: null, cursor: "0" }), { status: 200 }),
18
+ )
19
+
20
+ try {
21
+ const result = await listRestCacheEntries(process.cwd())
22
+ expect(result.entries).toEqual([])
23
+ expect(result.cursor).toBe("0")
24
+ } finally {
25
+ globalThis.fetch = originalFetch
26
+ }
27
+ })
28
+ })
@@ -115,7 +115,9 @@ describe("runtime contract", () => {
115
115
  SUPATYPE_SERVER_IMAGE: "supatype/server:v0.1.0",
116
116
  SUPATYPE_POSTGRES_IMAGE: "supatype/postgres:17-latest",
117
117
  })
118
- expect(composeDockerImageEnv({ ...baseConfig, versions: undefined })).toEqual({})
118
+ const withoutVersions = { ...baseConfig }
119
+ delete withoutVersions.versions
120
+ expect(composeDockerImageEnv(withoutVersions)).toEqual({})
119
121
  expect(
120
122
  composeDockerImageEnv({
121
123
  ...baseConfig,
@@ -483,9 +485,16 @@ export default defineConfig({
483
485
  expect(compose).not.toContain("HTTPS is off")
484
486
  })
485
487
 
488
+ it("self-host compose always includes Valkey and SUPATYPE_VALKEY_ADDR on server", () => {
489
+ const compose = renderSelfHostCompose(baseConfig)
490
+ expect(compose).toContain("\n valkey:\n")
491
+ expect(compose).toContain("valkey/valkey:8-alpine")
492
+ expect(compose).toContain("SUPATYPE_VALKEY_ADDR: valkey:6379")
493
+ expect(compose).toMatch(/^\s{2}valkey-data:/m)
494
+ })
495
+
486
496
  it("self-host compose stays plain HTTP with a discoverable hint when TLS is off", () => {
487
497
  const compose = renderSelfHostCompose(baseConfig)
488
- expect(compose).not.toContain("\n valkey:\n")
489
498
  expect(compose).not.toContain('- "443:8443"')
490
499
  expect(compose).toContain("${SUPATYPE_KONG_PORT:-18473}:8000")
491
500
  expect(compose).toContain("HTTPS is off")
@@ -496,7 +505,7 @@ export default defineConfig({
496
505
  ...baseConfig,
497
506
  server: { mode: "standalone", domain: "api.example.com" },
498
507
  })
499
- expect(compose).not.toContain("\n valkey:\n")
508
+ expect(compose).toContain("\n valkey:\n")
500
509
  expect(compose).not.toContain('- "443:8443"')
501
510
  })
502
511
 
@@ -3,7 +3,13 @@
3
3
  "compilerOptions": {
4
4
  "noEmit": true,
5
5
  "composite": false,
6
- "rootDir": ".."
6
+ "rootDir": "../.."
7
7
  },
8
- "include": ["./**/*.ts"]
8
+ "include": [
9
+ "./**/*.ts",
10
+ "../src/**/*.ts",
11
+ "../../studio/src/lib/normalize-admin-config.ts",
12
+ "../../studio/src/config.ts"
13
+ ],
14
+ "exclude": ["engine-distribution.test.ts"]
9
15
  }
@@ -1,35 +1,39 @@
1
1
  import { describe, expect, it, vi, beforeEach } from "vitest"
2
2
 
3
- vi.mock("@clack/prompts", () => ({
4
- confirm: vi.fn(),
3
+ const confirmMock = vi.hoisted(() => vi.fn())
4
+
5
+ vi.mock("../src/ui/clack.js", () => ({
6
+ p: {
7
+ confirm: confirmMock,
8
+ cancel: vi.fn(() => process.exit(0)),
9
+ },
5
10
  isCancel: vi.fn((v: unknown) => v === Symbol.for("cancel")),
6
- cancel: vi.fn(),
11
+ CLACK_CANCEL: Symbol.for("cancel"),
7
12
  }))
8
13
 
9
14
  vi.mock("../src/ui/interactive.js", () => ({
10
15
  isInteractive: vi.fn(() => true),
11
16
  }))
12
17
 
13
- import * as clack from "@clack/prompts"
14
18
  import { confirm, logSkippedConfirm } from "../src/ui/confirm.js"
15
19
  import { isInteractive } from "../src/ui/interactive.js"
16
20
 
17
21
  describe("ui confirm", () => {
18
22
  beforeEach(() => {
19
- vi.mocked(clack.confirm).mockReset()
23
+ confirmMock.mockReset()
20
24
  vi.mocked(isInteractive).mockReturnValue(true)
21
25
  })
22
26
 
23
- it("returns clack confirm result in TTY mode", async () => {
24
- vi.mocked(clack.confirm).mockResolvedValue(true)
27
+ it("returns ink confirm result in TTY mode", async () => {
28
+ confirmMock.mockResolvedValue(true)
25
29
  await expect(confirm("Proceed?")).resolves.toBe(true)
26
- expect(clack.confirm).toHaveBeenCalledWith({ message: "Proceed?", initialValue: false })
30
+ expect(confirmMock).toHaveBeenCalledWith({ message: "Proceed?", initialValue: false })
27
31
  })
28
32
 
29
33
  it("uses nonInteractive fallback when not a TTY", async () => {
30
34
  vi.mocked(isInteractive).mockReturnValue(false)
31
35
  await expect(confirm("Proceed?", { nonInteractive: false })).resolves.toBe(false)
32
- expect(clack.confirm).not.toHaveBeenCalled()
36
+ expect(confirmMock).not.toHaveBeenCalled()
33
37
  })
34
38
 
35
39
  it("logSkippedConfirm mentions --yes", () => {
@@ -1,45 +1,31 @@
1
- import { describe, expect, it, vi, beforeEach, afterAll } from "vitest"
1
+ import { describe, expect, it, vi, beforeEach } from "vitest"
2
2
 
3
3
  const isInteractiveMock = vi.hoisted(() => vi.fn(() => false))
4
- const clackInfoMock = vi.hoisted(() => vi.fn())
5
4
 
6
5
  vi.mock("../src/ui/interactive.js", () => ({
7
6
  isInteractive: isInteractiveMock,
8
7
  }))
9
8
 
10
- vi.mock("@clack/prompts", async (importOriginal) => {
11
- const original = await importOriginal<typeof import("@clack/prompts")>()
12
- return {
13
- ...original,
14
- log: {
15
- ...original.log,
16
- info: clackInfoMock,
17
- },
18
- }
19
- })
20
-
21
9
  import { file, info, plain, step, SUPATYPE_PREFIX } from "../src/ui/messages.js"
22
10
 
23
11
  describe("ui messages", () => {
24
12
  beforeEach(() => {
25
13
  isInteractiveMock.mockReturnValue(false)
26
- clackInfoMock.mockClear()
27
14
  })
28
15
 
29
16
  it("info prefixes with [supatype] when non-interactive", () => {
30
17
  const log = vi.spyOn(console, "log").mockImplementation(() => {})
31
18
  info("hello")
32
19
  expect(log.mock.calls[0]?.[0]).toBe(`${SUPATYPE_PREFIX} hello`)
33
- expect(clackInfoMock).not.toHaveBeenCalled()
34
20
  log.mockRestore()
35
21
  })
36
22
 
37
- it("info uses Clack log in interactive mode", () => {
23
+ it("info uses themed plain output in interactive mode", () => {
38
24
  isInteractiveMock.mockReturnValue(true)
39
25
  const log = vi.spyOn(console, "log").mockImplementation(() => {})
40
26
  info("hello")
41
- expect(clackInfoMock).toHaveBeenCalledWith("hello")
42
- expect(log).not.toHaveBeenCalled()
27
+ expect(String(log.mock.calls[0]?.[0])).toContain("hello")
28
+ expect(String(log.mock.calls[0]?.[0])).toContain("ℹ")
43
29
  log.mockRestore()
44
30
  })
45
31
 
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "outDir": "dist",
5
5
  "rootDir": "src",
6
6
  "composite": true,
7
+ "jsx": "react-jsx",
7
8
  "types": ["node"]
8
9
  },
9
10
  "include": ["src"]