@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,135 @@
1
+ /**
2
+ * Admin REST cache API client for CLI commands.
3
+ */
4
+
5
+ import { readEnvValue } from "./env-file.js"
6
+ import { resolveProjectApiUrl } from "./resolve-api-url.js"
7
+
8
+ export interface RestCacheEntrySummary {
9
+ key: string
10
+ table?: string
11
+ scope?: string
12
+ method?: string
13
+ path?: string
14
+ raw_query?: string
15
+ ttl_seconds: number
16
+ size_bytes: number
17
+ cached_at?: string
18
+ }
19
+
20
+ export interface RestCacheListResponse {
21
+ entries: RestCacheEntrySummary[]
22
+ cursor: string
23
+ }
24
+
25
+ export interface RestCacheDetail extends RestCacheEntrySummary {
26
+ status_code: number
27
+ content_type?: string
28
+ body_preview?: string
29
+ body_json?: unknown
30
+ }
31
+
32
+ function serviceRoleKey(cwd: string): string {
33
+ const key =
34
+ readEnvValue(cwd, "SUPATYPE_SERVICE_ROLE_KEY", "").trim() ||
35
+ readEnvValue(cwd, "SERVICE_ROLE_KEY", "").trim()
36
+ if (!key) {
37
+ throw new Error("SERVICE_ROLE_KEY not found in .env — run supatype dev or supatype keys")
38
+ }
39
+ return key.trim()
40
+ }
41
+
42
+ function adminHeaders(cwd: string): Record<string, string> {
43
+ const key = serviceRoleKey(cwd)
44
+ return {
45
+ Authorization: `Bearer ${key}`,
46
+ apikey: key,
47
+ "Content-Type": "application/json",
48
+ }
49
+ }
50
+
51
+ function formatCacheApiError(
52
+ operation: string,
53
+ status: number,
54
+ body: string,
55
+ baseUrl: string,
56
+ ): string {
57
+ const trimmed = body.trim()
58
+ if (status === 404) {
59
+ return (
60
+ `${operation} failed (404): ${trimmed || "not found"}\n` +
61
+ ` API: ${baseUrl}/admin/v1/cache\n` +
62
+ " Start the stack with `supatype dev`, or check SUPATYPE_URL / PUBLIC_SUPATYPE_URL in .env."
63
+ )
64
+ }
65
+ if (status === 403 && trimmed.includes("rest_cache_not_available")) {
66
+ return "REST server cache is not available on this plan or deployment."
67
+ }
68
+ if (status === 503 && trimmed.includes("valkey")) {
69
+ return "Valkey is not configured — server-side REST cache requires Valkey (supatype dev with docker)."
70
+ }
71
+ return `${operation} failed (${status}): ${trimmed || "(empty body)"}`
72
+ }
73
+
74
+ function normalizeListResponse(data: RestCacheListResponse): RestCacheListResponse {
75
+ return {
76
+ entries: data.entries ?? [],
77
+ cursor: data.cursor ?? "0",
78
+ }
79
+ }
80
+
81
+ export async function listRestCacheEntries(
82
+ cwd: string,
83
+ opts?: { table?: string | undefined; cursor?: string | undefined; limit?: number | undefined },
84
+ ): Promise<RestCacheListResponse> {
85
+ const baseUrl = resolveProjectApiUrl(cwd)
86
+ const params = new URLSearchParams()
87
+ if (opts?.table) params.set("table", opts.table)
88
+ if (opts?.cursor) params.set("cursor", opts.cursor)
89
+ if (opts?.limit !== undefined) params.set("limit", String(opts.limit))
90
+ const qs = params.toString()
91
+ const url = `${baseUrl}/admin/v1/cache${qs ? `?${qs}` : ""}`
92
+ const res = await fetch(url, { headers: adminHeaders(cwd) })
93
+ if (!res.ok) {
94
+ const body = await res.text()
95
+ throw new Error(formatCacheApiError("list cache", res.status, body, baseUrl))
96
+ }
97
+ const data = (await res.json()) as RestCacheListResponse
98
+ return normalizeListResponse(data)
99
+ }
100
+
101
+ export async function getRestCacheEntry(cwd: string, key: string): Promise<RestCacheDetail> {
102
+ const baseUrl = resolveProjectApiUrl(cwd)
103
+ const enc = Buffer.from(key, "utf8").toString("base64url")
104
+ const url = `${baseUrl}/admin/v1/cache/entries/${encodeURIComponent(enc)}`
105
+ const res = await fetch(url, { headers: adminHeaders(cwd) })
106
+ if (!res.ok) {
107
+ const body = await res.text()
108
+ throw new Error(formatCacheApiError("get cache entry", res.status, body, baseUrl))
109
+ }
110
+ return res.json() as Promise<RestCacheDetail>
111
+ }
112
+
113
+ export async function deleteRestCacheEntry(cwd: string, key: string): Promise<void> {
114
+ const baseUrl = resolveProjectApiUrl(cwd)
115
+ const enc = Buffer.from(key, "utf8").toString("base64url")
116
+ const url = `${baseUrl}/admin/v1/cache/entries/${encodeURIComponent(enc)}`
117
+ const res = await fetch(url, { method: "DELETE", headers: adminHeaders(cwd) })
118
+ if (!res.ok) {
119
+ const body = await res.text()
120
+ throw new Error(formatCacheApiError("delete cache entry", res.status, body, baseUrl))
121
+ }
122
+ }
123
+
124
+ export async function flushRestCache(cwd: string, table?: string): Promise<void> {
125
+ const baseUrl = resolveProjectApiUrl(cwd)
126
+ const params = new URLSearchParams()
127
+ if (table) params.set("table", table)
128
+ const qs = params.toString()
129
+ const url = `${baseUrl}/admin/v1/cache${qs ? `?${qs}` : ""}`
130
+ const res = await fetch(url, { method: "DELETE", headers: adminHeaders(cwd) })
131
+ if (!res.ok) {
132
+ const body = await res.text()
133
+ throw new Error(formatCacheApiError("flush cache", res.status, body, baseUrl))
134
+ }
135
+ }
@@ -1,57 +1,20 @@
1
1
  /**
2
- * Postinstall script — downloads component binaries on first install.
2
+ * Postinstall script — @supatype/cli global/project install.
3
3
  *
4
- * Components: supatype-engine, supatype-server, supatype-pg (Postgres), deno.
5
- * Binaries are cached in ~/.supatype/cache/{component}/{version}/.
6
- *
7
- * Failures are non-fatal: an installation message is printed and the user
8
- * can run `supatype update` manually to retry.
4
+ * Host binaries (engine, server, postgres, deno) are downloaded on demand:
5
+ * - native provider: first supatype dev / supatype update
6
+ * - docker provider: Compose images on first supatype dev
9
7
  */
10
8
 
11
- import { download, currentPlatform, fetchAllLatestVersions, type Component } from "../binary-cache.js"
12
-
13
9
  async function main() {
14
- const platform = currentPlatform()
15
-
16
- let versions: Record<Component, string>
17
- try {
18
- console.log("[supatype] Fetching latest component versions...")
19
- versions = await fetchAllLatestVersions()
20
- } catch (err) {
21
- console.error(`[supatype] Failed to fetch latest versions: ${(err as Error).message}`)
22
- console.error("[supatype] Run 'supatype update' to download component binaries.")
23
- return
24
- }
25
-
26
- console.log(`[supatype] Downloading component binaries for ${platform.os}/${platform.arch}...`)
27
-
28
- const components = Object.entries(versions) as [Component, string][]
29
-
30
- let anyFailed = false
31
- for (const [component, version] of components) {
32
- try {
33
- await download(component, version, platform)
34
- } catch (err) {
35
- console.error(`[supatype] Failed to download ${component} v${version}: ${(err as Error).message}`)
36
- anyFailed = true
37
- }
38
- }
39
-
40
- if (anyFailed) {
41
- // npm hides postinstall output unless --foreground-scripts, so don't rely on
42
- // this being seen: the CLI re-attempts the download (with retry) on first use.
43
- console.error(
44
- "[supatype] Some component binaries failed to download. " +
45
- "They will be re-downloaded automatically on first use; " +
46
- "run 'supatype update' to retry now.",
47
- )
48
- } else {
49
- console.log("[supatype] All component binaries downloaded successfully.")
50
- }
10
+ console.log(
11
+ "[supatype] CLI installed. " +
12
+ "Runtime components download automatically on first use " +
13
+ "(supatype dev or supatype update).",
14
+ )
51
15
  }
52
16
 
53
17
  main().catch((err) => {
54
- // Non-fatal — postinstall failures should not break npm install.
55
18
  console.error("[supatype] Postinstall failed:", err)
56
19
  process.exit(0)
57
20
  })
@@ -292,9 +292,7 @@ ${studioService}
292
292
  ? ` - "80:8000"
293
293
  - "443:8443"`
294
294
  : ` - "\${SUPATYPE_KONG_PORT:-18473}:8000"`
295
- const kongTlsDependsOn = tlsEnabled ? "\n - valkey" : ""
296
- const valkeyBlock = tlsEnabled
297
- ? `
295
+ const valkeyBlock = `
298
296
  valkey:
299
297
  image: \${SUPATYPE_VALKEY_IMAGE:-valkey/valkey:8-alpine}
300
298
  command: ["valkey-server", "--appendonly", "yes"]
@@ -303,23 +301,18 @@ ${studioService}
303
301
  volumes:
304
302
  - valkey-data:/data
305
303
  `
306
- : ""
304
+ const kongValkeyDepends = "\n - valkey"
307
305
  const tlsHintComment = tlsEnabled
308
306
  ? ""
309
307
  : ` # HTTPS is off. To enable automatic TLS (Let's Encrypt) for production, set in supatype.config.ts:
310
308
  # server: { mode: "standalone", domain: "your.domain", tls: { email: "you@example.com" } }
311
309
  # then re-run \`supatype self-host compose up -d\`. Kong publishes :80/:443 and provisions certs automatically.
312
310
  `
313
- const volumesBlock = tlsEnabled
314
- ? `volumes:
311
+ const volumesBlock = `volumes:
315
312
  db-data:
316
313
  minio-data:
317
314
  valkey-data:
318
315
  `
319
- : `volumes:
320
- db-data:
321
- minio-data:
322
- `
323
316
 
324
317
  return `# Generated by supatype self-host compose
325
318
  # Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
@@ -431,6 +424,7 @@ ${serverPorts} volumes:
431
424
  SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
432
425
  SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
433
426
  SUPATYPE_CONTROL_PLANE_URL: http://control-plane:8080
427
+ SUPATYPE_VALKEY_ADDR: valkey:6379
434
428
  ${appEnv}
435
429
  GOTRUE_API_HOST: 0.0.0.0
436
430
  GOTRUE_API_PORT: 9999
@@ -450,6 +444,8 @@ ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
450
444
  depends_on:
451
445
  db:
452
446
  condition: service_healthy
447
+ valkey:
448
+ condition: service_started
453
449
  postgrest:
454
450
  condition: service_started
455
451
  storage:
@@ -492,7 +488,7 @@ ${kongTlsEnv} volumes:
492
488
  ports:
493
489
  ${kongPorts}
494
490
  depends_on:
495
- ${kongDependsOn}${kongTlsDependsOn}
491
+ ${kongDependsOn}${kongValkeyDepends}
496
492
 
497
493
  ${volumesBlock}`
498
494
  }
@@ -594,7 +590,21 @@ export function runDockerCompose(
594
590
  ? { ...process.env, COMPOSE_PROGRESS: "quiet" }
595
591
  : process.env
596
592
  const stdio = options?.quiet ? "pipe" : "inherit"
597
- const result = spawnSync("docker", composeArgs, { stdio, cwd: projectRoot, env })
593
+ const result = spawnSync("docker", composeArgs, {
594
+ stdio,
595
+ cwd: projectRoot,
596
+ env,
597
+ ...(options?.quiet ? { encoding: "utf8" as const } : {}),
598
+ })
599
+ if (options?.quiet && result.status !== 0) {
600
+ const detail = [result.stderr, result.stdout]
601
+ .filter((s): s is string => typeof s === "string" && s.trim() !== "")
602
+ .join("\n")
603
+ .trim()
604
+ if (detail) {
605
+ console.error(`[supatype] docker compose: ${detail}`)
606
+ }
607
+ }
598
608
  return result.status ?? 1
599
609
  }
600
610
 
@@ -2,7 +2,8 @@ import { existsSync } from "node:fs"
2
2
  import { join, resolve } from "node:path"
3
3
  import { ProcessManager } from "./process-manager.js"
4
4
 
5
- const STUDIO_PORT = 3002
5
+ /** Vite dev server port when `overrides.studio` is set. */
6
+ export const STUDIO_DEV_PORT = 3002
6
7
 
7
8
  export interface StudioDevServerOptions {
8
9
  cwd: string
@@ -15,8 +16,8 @@ export interface StudioDevServerOptions {
15
16
  */
16
17
  proxyTarget: string
17
18
  /**
18
- * Public Supatype URL the browser uses. Compose dev: Kong on the host.
19
- * Native dev: Vite dev server (same origin as Studio).
19
+ * Browser API base URL. Must match the Vite dev origin (`http://localhost:3002`)
20
+ * so fetches hit the Vite proxy (SUPATYPE_PROXY_TARGET) and avoid CORS.
20
21
  */
21
22
  viteSupatypeUrl: string
22
23
  /** Vite `base` — `/studio/` when behind Kong at `/studio/`; `/` for native dev on :3002. */
@@ -35,7 +36,7 @@ export function startStudioViteDevServer(opts: StudioDevServerOptions): ProcessM
35
36
  const basePath = opts.basePath ?? "/"
36
37
  return new ProcessManager(
37
38
  process.execPath,
38
- [viteJs, "--port", String(STUDIO_PORT), "--strictPort", "--host"],
39
+ [viteJs, "--port", String(STUDIO_DEV_PORT), "--strictPort", "--host"],
39
40
  {
40
41
  label: "studio",
41
42
  pidDir: opts.pidDir,
package/src/ui/README.md CHANGED
@@ -1,17 +1,21 @@
1
1
  # CLI terminal UI (`packages/cli/src/ui/`)
2
2
 
3
- Shared output layer for `supatype` commands (not `supatype dev` TUI).
3
+ Shared Ink-based design system for the Supatype CLI.
4
4
 
5
5
  | Module | Use for |
6
6
  |--------|---------|
7
- | `messages.ts` | `info` / `warn` / `error` (Clack log in TTY; `[supatype]` in CI), `file`, `step`, `plain` |
8
- | `fatal.ts` | `fatalError`, `reportCliFatal` branded fatals + global catch helper |
9
- | `confirm.ts` | Yes/no prompts (Clack in TTY; respects `--yes` / non-TTY) |
10
- | `progress.ts` | `withSpinner` for long async work |
11
- | `prompts.ts` | Logo, Clack wizard helpers, `promptText` |
7
+ | `theme.ts` | Brand + semantic colours (Ink + plain ANSI) |
8
+ | `messages.ts` | `info` / `warn` / `error` / `success`, `file`, `step`, `plain` |
9
+ | `fatal.ts` | `fatalError`, `reportCliFatal` |
10
+ | `confirm.ts` | Yes/no prompts (Ink overlay in dev, Ink flow in TTY) |
11
+ | `progress.ts` | `withSpinner` + `runCommandChrome` for one-shot commands |
12
+ | `runtime/command-chrome.ts` | Ink shell (logo, logs, spinner) — applied globally via `wrapProgramActionsWithChrome` in `cli.ts` |
13
+ | `prompts.ts` | Logo, `promptText`, `promptPassword`, `ensureNotCancelled` |
14
+ | `clack.ts` | Clack-compatible `p.*` API + `runClackFlow()` for wizards |
15
+ | `flows/` | Ink flow shell + prompt fields |
16
+ | `dev/DevDashboard.tsx` | `supatype dev` task list + log pane + prompt overlay |
12
17
  | `next-steps.ts` | Bulleted follow-up commands |
13
- | `brand.ts` | ANSI colours + logo styling (shared with dev TUI) |
14
18
 
15
- **`supatype dev`** keeps its own alt-screen TUI (`dev-tui.ts`). Do not route dev logs through Clack.
19
+ **Convention:** interactive wizards use `runClackFlow(async (p) => …)` (`init`, `link`, `add domain`); one-shot commands get branded chrome automatically in `cli.ts` via `wrapProgramActionsWithChrome`. **`supatype dev`** keeps a persistent Ink dashboard (excluded from auto-wrap).
16
20
 
17
- **Convention:** interactive multi-step flows use Clack (`init`, `add`, `link`); one-shot commands use `info` + optional `withSpinner`.
21
+ **Plain profile:** when `!isInteractive()` (CI, pipes), helpers fall back to `[supatype]`-prefixed lines.
package/src/ui/brand.ts CHANGED
@@ -1,12 +1,6 @@
1
1
  /**
2
2
  * Shared ANSI styling for Supatype CLI output and the dev TUI.
3
+ * @deprecated Prefer `theme.ts` for new code — re-exports kept for dev-logo / task colors.
3
4
  */
4
5
 
5
- export const RESET = "\x1b[0m"
6
- export const DIM = "\x1b[2m"
7
- export const BOLD = "\x1b[1m"
8
- export const BRAND_COLOR = "\x1b[35m"
9
-
10
- export function brandStyle(text: string): string {
11
- return `${BRAND_COLOR}${BOLD}${text}${RESET}`
12
- }
6
+ export { BOLD, BRAND_COLOR, brandStyle, DIM, RESET } from "./theme.js"
@@ -0,0 +1,123 @@
1
+ import type { FlowController } from "./flows/types.js"
2
+ import type { DevSelectOption } from "./runtime/dev-prompt-queue.js"
3
+ import { CLACK_CANCEL } from "./runtime/cancel.js"
4
+
5
+ export interface ClackTextOptions {
6
+ message: string
7
+ defaultValue?: string
8
+ placeholder?: string
9
+ validate?: (value: string) => string | undefined
10
+ }
11
+
12
+ export interface ClackSelectOptions<T extends string = string> {
13
+ message: string
14
+ options: DevSelectOption<T>[]
15
+ initialValue?: T
16
+ }
17
+
18
+ export interface ClackConfirmOptions {
19
+ message: string
20
+ initialValue?: boolean
21
+ }
22
+
23
+ export interface ClackPasswordOptions {
24
+ message: string
25
+ }
26
+
27
+ export interface ClackSpinner {
28
+ start(message: string): void
29
+ stop(message: string): void
30
+ }
31
+
32
+ export interface ClackApi {
33
+ intro(message: string): void
34
+ outro(message: string): void
35
+ note(message: string): void
36
+ cancel(message: string): never
37
+ text(options: ClackTextOptions): Promise<string | typeof CLACK_CANCEL>
38
+ password(options: ClackPasswordOptions): Promise<string | typeof CLACK_CANCEL>
39
+ select<T extends string>(options: ClackSelectOptions<T>): Promise<T | typeof CLACK_CANCEL>
40
+ confirm(options: ClackConfirmOptions): Promise<boolean | typeof CLACK_CANCEL>
41
+ spinner(): ClackSpinner
42
+ log: {
43
+ info(message: string): void
44
+ warn(message: string): void
45
+ error(message: string): void
46
+ success(message: string): void
47
+ }
48
+ }
49
+
50
+ export function createClackApi(controller: FlowController): ClackApi {
51
+ return {
52
+ intro(message) {
53
+ controller.appendLog("plain", message)
54
+ },
55
+ outro(message) {
56
+ controller.appendLog("success", message)
57
+ },
58
+ note(message) {
59
+ for (const line of message.split("\n")) {
60
+ if (line.trim()) controller.appendPlain(line)
61
+ }
62
+ },
63
+ cancel(message): never {
64
+ controller.appendLog("warn", message)
65
+ process.exit(0)
66
+ },
67
+ async text(options) {
68
+ return controller.waitForPrompt<string>({
69
+ kind: "text",
70
+ message: options.message,
71
+ ...(options.defaultValue !== undefined ? { defaultValue: options.defaultValue } : {}),
72
+ ...(options.placeholder !== undefined ? { placeholder: options.placeholder } : {}),
73
+ ...(options.validate !== undefined ? { validate: options.validate } : {}),
74
+ })
75
+ },
76
+ async password(options) {
77
+ return controller.waitForPrompt<string>({
78
+ kind: "password",
79
+ message: options.message,
80
+ })
81
+ },
82
+ async select<T extends string>(options: ClackSelectOptions<T>) {
83
+ return controller.waitForPrompt<T>({
84
+ kind: "select",
85
+ message: options.message,
86
+ options: options.options,
87
+ ...(options.initialValue !== undefined ? { initialValue: options.initialValue } : {}),
88
+ })
89
+ },
90
+ async confirm(options) {
91
+ return controller.waitForPrompt<boolean>({
92
+ kind: "confirm",
93
+ message: options.message,
94
+ initialValue: options.initialValue ?? false,
95
+ })
96
+ },
97
+ spinner() {
98
+ return {
99
+ start(message: string) {
100
+ controller.setSpinner(message)
101
+ },
102
+ stop(message: string) {
103
+ controller.setSpinner(null)
104
+ controller.appendLog("success", message)
105
+ },
106
+ }
107
+ },
108
+ log: {
109
+ info(message) {
110
+ controller.appendLog("info", message)
111
+ },
112
+ warn(message) {
113
+ controller.appendLog("warn", message)
114
+ },
115
+ error(message) {
116
+ controller.appendLog("error", message)
117
+ },
118
+ success(message) {
119
+ controller.appendLog("success", message)
120
+ },
121
+ },
122
+ }
123
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Clack-compatible prompt API backed by Ink.
3
+ * Use inside `runClackFlow()` for multi-step wizards, or via `confirm()` / `promptText()` helpers.
4
+ */
5
+
6
+ import { getActiveDevSession } from "../dev-session.js"
7
+ import { createClackApi, type ClackApi } from "./clack-api.js"
8
+ import { isInteractive } from "./interactive.js"
9
+ import { CLACK_CANCEL, isCancel } from "./runtime/cancel.js"
10
+ import { enqueueDevPrompt } from "./runtime/dev-prompt-queue.js"
11
+ import { runClackFlow as mountClackFlow } from "./runtime/run-clack-flow.js"
12
+ import type { DevSelectOption } from "./runtime/dev-prompt-queue.js"
13
+
14
+ export { CLACK_CANCEL, isCancel }
15
+ export type { ClackApi } from "./clack-api.js"
16
+
17
+ import { getActiveFlowApi, setActiveFlowApi } from "./runtime/flow-session.js"
18
+
19
+ function inDevTui(): boolean {
20
+ const session = getActiveDevSession()
21
+ return Boolean(session?.isTui() && session.isInkMounted())
22
+ }
23
+
24
+ async function devOrFlow<T>(
25
+ spec: Parameters<typeof enqueueDevPrompt>[0],
26
+ flowFn: (api: ClackApi) => Promise<T>,
27
+ ): Promise<T | typeof CLACK_CANCEL> {
28
+ if (inDevTui()) {
29
+ return enqueueDevPrompt(spec) as Promise<T | typeof CLACK_CANCEL>
30
+ }
31
+ const api = getActiveFlowApi()
32
+ if (api) {
33
+ return flowFn(api)
34
+ }
35
+ return mountClackFlow(async (flowApi) => flowFn(flowApi))
36
+ }
37
+
38
+ export async function runClackFlow<T>(run: (api: ClackApi) => Promise<T>): Promise<T> {
39
+ return mountClackFlow(async (api) => {
40
+ setActiveFlowApi(api)
41
+ try {
42
+ return await run(api)
43
+ } finally {
44
+ setActiveFlowApi(null)
45
+ }
46
+ })
47
+ }
48
+
49
+ export { getActiveFlowApi } from "./runtime/flow-session.js"
50
+
51
+ export const p: ClackApi = {
52
+ intro(message) {
53
+ const api = getActiveFlowApi()
54
+ if (api) api.intro(message)
55
+ else console.log(`\n${message}\n`)
56
+ },
57
+ outro(message) {
58
+ const api = getActiveFlowApi()
59
+ if (api) api.outro(message)
60
+ else console.log(`\n${message}\n`)
61
+ },
62
+ note(message) {
63
+ const api = getActiveFlowApi()
64
+ if (api) api.note(message)
65
+ else {
66
+ for (const line of message.split("\n")) {
67
+ if (line.trim()) console.log(` ${line}`)
68
+ }
69
+ }
70
+ },
71
+ cancel(message): never {
72
+ const api = getActiveFlowApi()
73
+ if (api) {
74
+ api.cancel(message)
75
+ }
76
+ console.log(message)
77
+ process.exit(0)
78
+ },
79
+ async text(options) {
80
+ return devOrFlow(
81
+ {
82
+ kind: "text",
83
+ message: options.message,
84
+ ...(options.defaultValue !== undefined ? { defaultValue: options.defaultValue } : {}),
85
+ ...(options.placeholder !== undefined ? { placeholder: options.placeholder } : {}),
86
+ ...(options.validate !== undefined ? { validate: options.validate } : {}),
87
+ },
88
+ (api) => api.text(options),
89
+ )
90
+ },
91
+ async password(options) {
92
+ return devOrFlow({ kind: "password", message: options.message }, (api) => api.password(options))
93
+ },
94
+ async select<T extends string>(options: { message: string; options: DevSelectOption<T>[]; initialValue?: T }) {
95
+ return devOrFlow(
96
+ {
97
+ kind: "select",
98
+ message: options.message,
99
+ options: options.options,
100
+ ...(options.initialValue !== undefined ? { initialValue: options.initialValue as string | boolean } : {}),
101
+ },
102
+ (api) => api.select(options),
103
+ )
104
+ },
105
+ async confirm(options) {
106
+ return devOrFlow(
107
+ {
108
+ kind: "confirm",
109
+ message: options.message,
110
+ initialValue: options.initialValue ?? false,
111
+ },
112
+ (api) => api.confirm(options),
113
+ )
114
+ },
115
+ spinner() {
116
+ const api = getActiveFlowApi()
117
+ if (api) return api.spinner()
118
+ return {
119
+ start(message: string) {
120
+ console.log(`${message}...`)
121
+ },
122
+ stop(message: string) {
123
+ console.log(message)
124
+ },
125
+ }
126
+ },
127
+ log: {
128
+ info(message) {
129
+ const api = getActiveFlowApi()
130
+ if (api) api.log.info(message)
131
+ else if (isInteractive()) console.log(message)
132
+ else console.log(`[supatype] ${message}`)
133
+ },
134
+ warn(message) {
135
+ const api = getActiveFlowApi()
136
+ if (api) api.log.warn(message)
137
+ else console.warn(`[supatype] ${message}`)
138
+ },
139
+ error(message) {
140
+ const api = getActiveFlowApi()
141
+ if (api) api.log.error(message)
142
+ else console.error(`[supatype] ${message}`)
143
+ },
144
+ success(message) {
145
+ const api = getActiveFlowApi()
146
+ if (api) api.log.success(message)
147
+ else console.log(`[supatype] ${message}`)
148
+ },
149
+ },
150
+ }
151
+
152
+ /** @deprecated Use `p` from this module inside `runClackFlow`. */
153
+ export { p as clack }
@@ -0,0 +1,15 @@
1
+ import React from "react"
2
+ import { Box, Text } from "ink"
3
+ import Spinner from "ink-spinner"
4
+ import { theme } from "../theme.js"
5
+
6
+ export function FlowSpinner({ message }: { message: string }): React.ReactElement {
7
+ return (
8
+ <Box marginBottom={1}>
9
+ <Text color={theme.brand}>
10
+ <Spinner type="dots" />
11
+ {` ${message}`}
12
+ </Text>
13
+ </Box>
14
+ )
15
+ }