@supatype/cli 0.1.0-alpha.6 → 0.1.0-alpha.8

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 (350) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +208 -1
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/dist/app/proxy-dev-app.d.ts +13 -0
  5. package/dist/app/proxy-dev-app.d.ts.map +1 -0
  6. package/dist/app/proxy-dev-app.js +53 -0
  7. package/dist/app/proxy-dev-app.js.map +1 -0
  8. package/dist/app-config.d.ts +7 -0
  9. package/dist/app-config.d.ts.map +1 -0
  10. package/dist/app-config.js +113 -0
  11. package/dist/app-config.js.map +1 -0
  12. package/dist/augmentation-generator.d.ts +2 -0
  13. package/dist/augmentation-generator.d.ts.map +1 -0
  14. package/dist/augmentation-generator.js +111 -0
  15. package/dist/augmentation-generator.js.map +1 -0
  16. package/dist/binary-cache.d.ts +94 -0
  17. package/dist/binary-cache.d.ts.map +1 -0
  18. package/dist/binary-cache.js +669 -0
  19. package/dist/binary-cache.js.map +1 -0
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +13 -7
  22. package/dist/cli.js.map +1 -1
  23. package/dist/commands/admin.d.ts.map +1 -1
  24. package/dist/commands/admin.js +4 -3
  25. package/dist/commands/admin.js.map +1 -1
  26. package/dist/commands/app.d.ts.map +1 -1
  27. package/dist/commands/app.js +56 -209
  28. package/dist/commands/app.js.map +1 -1
  29. package/dist/commands/cache.d.ts +6 -0
  30. package/dist/commands/cache.d.ts.map +1 -0
  31. package/dist/commands/cache.js +105 -0
  32. package/dist/commands/cache.js.map +1 -0
  33. package/dist/commands/cloud.d.ts +20 -0
  34. package/dist/commands/cloud.d.ts.map +1 -1
  35. package/dist/commands/cloud.js +50 -52
  36. package/dist/commands/cloud.js.map +1 -1
  37. package/dist/commands/db.d.ts.map +1 -1
  38. package/dist/commands/db.js +47 -54
  39. package/dist/commands/db.js.map +1 -1
  40. package/dist/commands/deploy.d.ts +2 -1
  41. package/dist/commands/deploy.d.ts.map +1 -1
  42. package/dist/commands/deploy.js +79 -52
  43. package/dist/commands/deploy.js.map +1 -1
  44. package/dist/commands/dev.d.ts +11 -0
  45. package/dist/commands/dev.d.ts.map +1 -1
  46. package/dist/commands/dev.js +759 -385
  47. package/dist/commands/dev.js.map +1 -1
  48. package/dist/commands/diff.d.ts.map +1 -1
  49. package/dist/commands/diff.js +30 -15
  50. package/dist/commands/diff.js.map +1 -1
  51. package/dist/commands/engine.d.ts +1 -3
  52. package/dist/commands/engine.d.ts.map +1 -1
  53. package/dist/commands/engine.js +13 -85
  54. package/dist/commands/engine.js.map +1 -1
  55. package/dist/commands/functions.d.ts.map +1 -1
  56. package/dist/commands/functions.js +92 -105
  57. package/dist/commands/functions.js.map +1 -1
  58. package/dist/commands/generate.d.ts.map +1 -1
  59. package/dist/commands/generate.js +22 -12
  60. package/dist/commands/generate.js.map +1 -1
  61. package/dist/commands/init.d.ts +1 -1
  62. package/dist/commands/init.d.ts.map +1 -1
  63. package/dist/commands/init.js +137 -410
  64. package/dist/commands/init.js.map +1 -1
  65. package/dist/commands/migrate-from-v1.d.ts +5 -0
  66. package/dist/commands/migrate-from-v1.d.ts.map +1 -0
  67. package/dist/commands/migrate-from-v1.js +125 -0
  68. package/dist/commands/migrate-from-v1.js.map +1 -0
  69. package/dist/commands/migrate.d.ts.map +1 -1
  70. package/dist/commands/migrate.js +27 -23
  71. package/dist/commands/migrate.js.map +1 -1
  72. package/dist/commands/pg.d.ts +8 -0
  73. package/dist/commands/pg.d.ts.map +1 -0
  74. package/dist/commands/pg.js +102 -0
  75. package/dist/commands/pg.js.map +1 -0
  76. package/dist/commands/pull.d.ts.map +1 -1
  77. package/dist/commands/pull.js +5 -66
  78. package/dist/commands/pull.js.map +1 -1
  79. package/dist/commands/push.d.ts.map +1 -1
  80. package/dist/commands/push.js +128 -38
  81. package/dist/commands/push.js.map +1 -1
  82. package/dist/commands/seed.d.ts +2 -0
  83. package/dist/commands/seed.d.ts.map +1 -1
  84. package/dist/commands/seed.js +44 -11
  85. package/dist/commands/seed.js.map +1 -1
  86. package/dist/commands/self-host.d.ts +7 -1
  87. package/dist/commands/self-host.d.ts.map +1 -1
  88. package/dist/commands/self-host.js +272 -758
  89. package/dist/commands/self-host.js.map +1 -1
  90. package/dist/commands/self-update.d.ts +9 -0
  91. package/dist/commands/self-update.d.ts.map +1 -0
  92. package/dist/commands/self-update.js +33 -0
  93. package/dist/commands/self-update.js.map +1 -0
  94. package/dist/commands/status.d.ts.map +1 -1
  95. package/dist/commands/status.js +4 -3
  96. package/dist/commands/status.js.map +1 -1
  97. package/dist/commands/types.d.ts +3 -0
  98. package/dist/commands/types.d.ts.map +1 -0
  99. package/dist/commands/types.js +62 -0
  100. package/dist/commands/types.js.map +1 -0
  101. package/dist/commands/update.d.ts +7 -0
  102. package/dist/commands/update.d.ts.map +1 -0
  103. package/dist/commands/update.js +93 -0
  104. package/dist/commands/update.js.map +1 -0
  105. package/dist/components.d.ts +5 -0
  106. package/dist/components.d.ts.map +1 -0
  107. package/dist/components.js +3 -0
  108. package/dist/components.js.map +1 -0
  109. package/dist/config.d.ts +10 -51
  110. package/dist/config.d.ts.map +1 -1
  111. package/dist/config.js +101 -33
  112. package/dist/config.js.map +1 -1
  113. package/dist/dev-compose.d.ts +17 -0
  114. package/dist/dev-compose.d.ts.map +1 -0
  115. package/dist/dev-compose.js +374 -0
  116. package/dist/dev-compose.js.map +1 -0
  117. package/dist/diff-output.d.ts +4 -0
  118. package/dist/diff-output.d.ts.map +1 -0
  119. package/dist/diff-output.js +12 -0
  120. package/dist/diff-output.js.map +1 -0
  121. package/dist/docker-postgres.d.ts +57 -0
  122. package/dist/docker-postgres.d.ts.map +1 -0
  123. package/dist/docker-postgres.js +208 -0
  124. package/dist/docker-postgres.js.map +1 -0
  125. package/dist/engine-client.d.ts +69 -0
  126. package/dist/engine-client.d.ts.map +1 -0
  127. package/dist/engine-client.js +157 -0
  128. package/dist/engine-client.js.map +1 -0
  129. package/dist/ensure-binary.d.ts +7 -0
  130. package/dist/ensure-binary.d.ts.map +1 -0
  131. package/dist/ensure-binary.js +17 -0
  132. package/dist/ensure-binary.js.map +1 -0
  133. package/dist/functions-router-gen.d.ts +14 -0
  134. package/dist/functions-router-gen.d.ts.map +1 -0
  135. package/dist/functions-router-gen.js +199 -0
  136. package/dist/functions-router-gen.js.map +1 -0
  137. package/dist/index.d.ts +4 -5
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +2 -3
  140. package/dist/index.js.map +1 -1
  141. package/dist/kong-config.d.ts +25 -0
  142. package/dist/kong-config.d.ts.map +1 -0
  143. package/dist/kong-config.js +71 -0
  144. package/dist/kong-config.js.map +1 -0
  145. package/dist/local-gateway.d.ts +7 -0
  146. package/dist/local-gateway.d.ts.map +1 -0
  147. package/dist/local-gateway.js +9 -0
  148. package/dist/local-gateway.js.map +1 -0
  149. package/dist/local-storage.d.ts +8 -0
  150. package/dist/local-storage.d.ts.map +1 -0
  151. package/dist/local-storage.js +14 -0
  152. package/dist/local-storage.js.map +1 -0
  153. package/dist/pgbouncer-userlist.d.ts +5 -0
  154. package/dist/pgbouncer-userlist.d.ts.map +1 -0
  155. package/dist/pgbouncer-userlist.js +14 -0
  156. package/dist/pgbouncer-userlist.js.map +1 -0
  157. package/dist/postgres-ctl.d.ts +44 -0
  158. package/dist/postgres-ctl.d.ts.map +1 -0
  159. package/dist/postgres-ctl.js +137 -0
  160. package/dist/postgres-ctl.js.map +1 -0
  161. package/dist/process-manager.d.ts +43 -0
  162. package/dist/process-manager.d.ts.map +1 -0
  163. package/dist/process-manager.js +135 -0
  164. package/dist/process-manager.js.map +1 -0
  165. package/dist/project-config.d.ts +235 -0
  166. package/dist/project-config.d.ts.map +1 -0
  167. package/dist/project-config.js +160 -0
  168. package/dist/project-config.js.map +1 -0
  169. package/dist/pull-utils.d.ts +15 -0
  170. package/dist/pull-utils.d.ts.map +1 -1
  171. package/dist/pull-utils.js +12 -0
  172. package/dist/pull-utils.js.map +1 -1
  173. package/dist/release-pins.d.ts +7 -0
  174. package/dist/release-pins.d.ts.map +1 -0
  175. package/dist/release-pins.js +27 -0
  176. package/dist/release-pins.js.map +1 -0
  177. package/dist/release-public-key.d.ts +8 -0
  178. package/dist/release-public-key.d.ts.map +1 -0
  179. package/dist/release-public-key.js +13 -0
  180. package/dist/release-public-key.js.map +1 -0
  181. package/dist/runtime-routes.d.ts +34 -0
  182. package/dist/runtime-routes.d.ts.map +1 -0
  183. package/dist/runtime-routes.js +252 -0
  184. package/dist/runtime-routes.js.map +1 -0
  185. package/dist/schema-ast-v2.d.ts +127 -0
  186. package/dist/schema-ast-v2.d.ts.map +1 -0
  187. package/dist/schema-ast-v2.js +226 -0
  188. package/dist/schema-ast-v2.js.map +1 -0
  189. package/dist/scripts/postinstall.d.ts +5 -6
  190. package/dist/scripts/postinstall.d.ts.map +1 -1
  191. package/dist/scripts/postinstall.js +36 -20
  192. package/dist/scripts/postinstall.js.map +1 -1
  193. package/dist/self-host-compose.d.ts +22 -0
  194. package/dist/self-host-compose.d.ts.map +1 -0
  195. package/dist/self-host-compose.js +347 -0
  196. package/dist/self-host-compose.js.map +1 -0
  197. package/dist/storage-provision.d.ts +24 -0
  198. package/dist/storage-provision.d.ts.map +1 -0
  199. package/dist/storage-provision.js +44 -0
  200. package/dist/storage-provision.js.map +1 -0
  201. package/dist/studio-admin-roles.d.ts +7 -0
  202. package/dist/studio-admin-roles.d.ts.map +1 -0
  203. package/dist/studio-admin-roles.js +14 -0
  204. package/dist/studio-admin-roles.js.map +1 -0
  205. package/dist/studio-dev-server.d.ts +22 -0
  206. package/dist/studio-dev-server.d.ts.map +1 -0
  207. package/dist/studio-dev-server.js +28 -0
  208. package/dist/studio-dev-server.js.map +1 -0
  209. package/dist/systemd.d.ts +26 -0
  210. package/dist/systemd.d.ts.map +1 -0
  211. package/dist/systemd.js +102 -0
  212. package/dist/systemd.js.map +1 -0
  213. package/dist/tsx-runner.d.ts.map +1 -1
  214. package/dist/tsx-runner.js +9 -2
  215. package/dist/tsx-runner.js.map +1 -1
  216. package/dist/type-extractor.d.ts +4 -0
  217. package/dist/type-extractor.d.ts.map +1 -0
  218. package/dist/type-extractor.js +1213 -0
  219. package/dist/type-extractor.js.map +1 -0
  220. package/dist/type-resolver.d.ts +33 -0
  221. package/dist/type-resolver.d.ts.map +1 -0
  222. package/dist/type-resolver.js +338 -0
  223. package/dist/type-resolver.js.map +1 -0
  224. package/package.json +4 -3
  225. package/releases/deno/VERSION +1 -0
  226. package/scripts/mirror-deno-release.sh +76 -0
  227. package/src/TYPE-RESOLUTION.md +294 -0
  228. package/src/app/proxy-dev-app.ts +67 -0
  229. package/src/app-config.ts +128 -0
  230. package/src/augmentation-generator.ts +126 -0
  231. package/src/binary-cache.ts +822 -0
  232. package/src/cli.ts +13 -8
  233. package/src/commands/admin.ts +4 -3
  234. package/src/commands/app.ts +67 -231
  235. package/src/commands/cache.ts +117 -0
  236. package/src/commands/cloud.ts +63 -64
  237. package/src/commands/db.ts +54 -63
  238. package/src/commands/deploy.ts +96 -62
  239. package/src/commands/dev.ts +933 -405
  240. package/src/commands/diff.ts +31 -29
  241. package/src/commands/engine.ts +13 -116
  242. package/src/commands/functions.ts +97 -115
  243. package/src/commands/generate.ts +23 -10
  244. package/src/commands/init.ts +149 -414
  245. package/src/commands/migrate-from-v1.ts +131 -0
  246. package/src/commands/migrate.ts +27 -23
  247. package/src/commands/pg.ts +133 -0
  248. package/src/commands/pull.ts +6 -85
  249. package/src/commands/push.ts +161 -56
  250. package/src/commands/seed.ts +54 -12
  251. package/src/commands/self-host.ts +312 -880
  252. package/src/commands/self-update.ts +45 -0
  253. package/src/commands/status.ts +4 -3
  254. package/src/commands/types.ts +76 -0
  255. package/src/commands/update.ts +109 -0
  256. package/src/components.ts +6 -0
  257. package/src/config.ts +127 -94
  258. package/src/dev-compose.ts +455 -0
  259. package/src/diff-output.ts +12 -0
  260. package/src/docker-postgres.ts +295 -0
  261. package/src/engine-client.ts +236 -0
  262. package/src/ensure-binary.ts +28 -0
  263. package/src/functions-router-gen.ts +224 -0
  264. package/src/index.ts +4 -12
  265. package/src/kong-config.ts +93 -0
  266. package/src/local-gateway.ts +9 -0
  267. package/src/local-storage.ts +14 -0
  268. package/src/pgbouncer-userlist.ts +15 -0
  269. package/src/postgres-ctl.ts +171 -0
  270. package/src/process-manager.ts +168 -0
  271. package/src/project-config.ts +386 -0
  272. package/src/pull-utils.ts +24 -0
  273. package/src/release-pins.ts +31 -0
  274. package/src/release-public-key.ts +12 -0
  275. package/src/runtime-routes.ts +291 -0
  276. package/src/schema-ast-v2.ts +324 -0
  277. package/src/scripts/postinstall.ts +36 -25
  278. package/src/self-host-compose.ts +389 -0
  279. package/src/storage-provision.ts +58 -0
  280. package/src/studio-admin-roles.ts +16 -0
  281. package/src/studio-dev-server.ts +53 -0
  282. package/src/systemd.ts +137 -0
  283. package/src/tsx-runner.ts +11 -1
  284. package/src/type-extractor.ts +1479 -0
  285. package/src/type-resolver.ts +457 -0
  286. package/tests/app-command.test.ts +54 -0
  287. package/tests/augmentation-generator.test.ts +59 -0
  288. package/tests/binary-cache-cloud-overrides.test.ts +123 -0
  289. package/tests/cached-artifact-format.test.ts +84 -0
  290. package/tests/cli-help.test.ts +40 -14
  291. package/tests/config.test.ts +171 -37
  292. package/tests/docker-postgres.test.ts +39 -0
  293. package/tests/engine-distribution.test.ts +3 -3
  294. package/tests/ensure-binary.test.ts +59 -0
  295. package/tests/init.test.ts +28 -86
  296. package/tests/migrate-from-v1.test.ts +29 -0
  297. package/tests/normalize-admin-config.test.ts +48 -0
  298. package/tests/pg-spawn-env.test.ts +18 -0
  299. package/tests/postgres-archive-tag.test.ts +9 -0
  300. package/tests/proxy-dev-app.test.ts +33 -0
  301. package/tests/pull-utils.test.ts +36 -1
  302. package/tests/release-pins.test.ts +28 -0
  303. package/tests/runtime-contract.test.ts +351 -0
  304. package/tests/seed-discover.test.ts +31 -0
  305. package/tests/studio-admin-roles.test.ts +27 -0
  306. package/tests/tsconfig.json +9 -0
  307. package/tests/type-extractor.test.ts +985 -0
  308. package/tests/type-resolver.test.ts +59 -0
  309. package/tsconfig.tsbuildinfo +1 -1
  310. package/vitest.config.ts +12 -0
  311. package/dist/engine/cache.d.ts +0 -37
  312. package/dist/engine/cache.d.ts.map +0 -1
  313. package/dist/engine/cache.js +0 -121
  314. package/dist/engine/cache.js.map +0 -1
  315. package/dist/engine/download.d.ts +0 -19
  316. package/dist/engine/download.d.ts.map +0 -1
  317. package/dist/engine/download.js +0 -108
  318. package/dist/engine/download.js.map +0 -1
  319. package/dist/engine/platform.d.ts +0 -24
  320. package/dist/engine/platform.d.ts.map +0 -1
  321. package/dist/engine/platform.js +0 -50
  322. package/dist/engine/platform.js.map +0 -1
  323. package/dist/engine/resolve.d.ts +0 -37
  324. package/dist/engine/resolve.d.ts.map +0 -1
  325. package/dist/engine/resolve.js +0 -133
  326. package/dist/engine/resolve.js.map +0 -1
  327. package/dist/engine/update-notify.d.ts +0 -11
  328. package/dist/engine/update-notify.d.ts.map +0 -1
  329. package/dist/engine/update-notify.js +0 -43
  330. package/dist/engine/update-notify.js.map +0 -1
  331. package/dist/engine/verify.d.ts +0 -50
  332. package/dist/engine/verify.d.ts.map +0 -1
  333. package/dist/engine/verify.js +0 -161
  334. package/dist/engine/verify.js.map +0 -1
  335. package/dist/engine-version.d.ts +0 -35
  336. package/dist/engine-version.d.ts.map +0 -1
  337. package/dist/engine-version.js +0 -35
  338. package/dist/engine-version.js.map +0 -1
  339. package/dist/engine.d.ts +0 -34
  340. package/dist/engine.d.ts.map +0 -1
  341. package/dist/engine.js +0 -76
  342. package/dist/engine.js.map +0 -1
  343. package/src/engine/cache.ts +0 -135
  344. package/src/engine/download.ts +0 -143
  345. package/src/engine/platform.ts +0 -66
  346. package/src/engine/resolve.ts +0 -197
  347. package/src/engine/update-notify.ts +0 -50
  348. package/src/engine/verify.ts +0 -206
  349. package/src/engine-version.ts +0 -39
  350. package/src/engine.ts +0 -99
@@ -0,0 +1,389 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs"
2
+ import { dirname, join, relative, resolve } from "node:path"
3
+ import { spawnSync } from "node:child_process"
4
+ import { preferredFunctionsPathFromProject, type SupatypeProjectConfig } from "./project-config.js"
5
+ import { hasEngineOverride, hasStudioOverride } from "./binary-cache.js"
6
+ import { buildKongDeclarative } from "./kong-config.js"
7
+
8
+ export interface SelfHostComposePaths {
9
+ dir: string
10
+ composePath: string
11
+ kongPath: string
12
+ nginxPath: string
13
+ }
14
+
15
+ export function selfHostComposePaths(cwd: string): SelfHostComposePaths {
16
+ const dir = resolve(cwd, ".supatype", "self-host")
17
+ return {
18
+ dir,
19
+ composePath: join(dir, "docker-compose.yml"),
20
+ kongPath: join(dir, "kong.yml"),
21
+ nginxPath: join(dir, "nginx.conf"),
22
+ }
23
+ }
24
+
25
+ export function appUpstreamForCompose(config: SupatypeProjectConfig): string | undefined {
26
+ if (config.app.mode !== "proxy") return undefined
27
+ const upstream = config.app.upstream?.trim()
28
+ return upstream && upstream.length > 0 ? upstream : undefined
29
+ }
30
+
31
+ export function staticDirForCompose(config: SupatypeProjectConfig): string | undefined {
32
+ if (config.app.mode !== "static") return undefined
33
+ const dir = config.app.static_dir?.trim()
34
+ return dir && dir.length > 0 ? dir : "./public"
35
+ }
36
+
37
+ /**
38
+ * Bind-mount source for `/project` in generated compose files.
39
+ * Paths are resolved from `--project-directory` (always the project root in `runDockerCompose`),
40
+ * not from the compose file directory — use `.` not `../..`.
41
+ */
42
+ function projectMountPath(_cwd: string): string {
43
+ return "."
44
+ }
45
+
46
+ /** Paths in generated compose are resolved from `--project-directory` (project root). */
47
+ function relativeFromProjectRoot(cwd: string, target: string): string {
48
+ let rel = relative(resolve(cwd), resolve(target)).replace(/\\/g, "/")
49
+ if (!rel.startsWith(".") && !rel.startsWith("/")) {
50
+ rel = `./${rel}`
51
+ }
52
+ return rel
53
+ }
54
+
55
+ function kongMountPath(_cwd: string): string {
56
+ return ".supatype/self-host/kong.yml"
57
+ }
58
+
59
+ /** Host Vite dev server as seen from Kong inside Docker Compose. */
60
+ export const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002"
61
+
62
+ /** Local monorepo Studio image for `supatype dev` (dogfooding). */
63
+ function studioServiceBlock(cwd: string, devLocal: boolean): string {
64
+ if (!devLocal) {
65
+ return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`
66
+ }
67
+ const monorepoRoot = resolve(cwd, "..", "supatype")
68
+ const studioDockerfile = join(monorepoRoot, "packages", "studio", "Dockerfile")
69
+ if (!existsSync(studioDockerfile) || !existsSync(join(monorepoRoot, "pnpm-workspace.yaml"))) {
70
+ return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`
71
+ }
72
+ const context = relativeFromProjectRoot(cwd, monorepoRoot)
73
+ return ` build:
74
+ context: ${context}
75
+ dockerfile: packages/studio/Dockerfile
76
+ image: supatype/studio:dev-local`
77
+ }
78
+
79
+ /** Host dev app (Astro/Vite on the machine) as seen from inside compose services. */
80
+ function proxyUpstreamForCompose(upstream: string, devLocal: boolean): string {
81
+ const trimmed = upstream.trim()
82
+ if (!devLocal) return trimmed
83
+ try {
84
+ const url = new URL(trimmed)
85
+ if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
86
+ url.hostname = "host.docker.internal"
87
+ return url.toString()
88
+ }
89
+ } catch {
90
+ // keep literal upstream when not a URL
91
+ }
92
+ return trimmed
93
+ }
94
+
95
+ function serverAppEnvForCompose(config: SupatypeProjectConfig, devLocal: boolean): string {
96
+ const mode = config.app.mode ?? "none"
97
+ const lines = [` SUPATYPE_APP_MODE: ${mode}`]
98
+ if (mode === "static") {
99
+ const dir = staticDirForCompose(config) ?? "./public"
100
+ lines.push(` SUPATYPE_APP_STATIC_DIR: /project/${dir.replace(/^\.\//, "")}`)
101
+ } else if (mode === "proxy" && config.app.upstream?.trim()) {
102
+ lines.push(` SUPATYPE_APP_UPSTREAM: ${proxyUpstreamForCompose(config.app.upstream, devLocal)}`)
103
+ }
104
+ return lines.join("\n")
105
+ }
106
+
107
+ export interface SelfHostComposeOptions {
108
+ /** `supatype dev` with provider docker: internal-only db/server; Kong on host :18473. */
109
+ devLocal?: boolean
110
+ }
111
+
112
+ export function renderSelfHostCompose(
113
+ config: SupatypeProjectConfig,
114
+ cwd: string = process.cwd(),
115
+ options?: SelfHostComposeOptions,
116
+ ): string {
117
+ const projectMount = projectMountPath(cwd)
118
+ const kongMount = kongMountPath(cwd)
119
+ const devLocal = options?.devLocal === true
120
+ const studioHostDev = devLocal && hasStudioOverride(config)
121
+ const appEnv = serverAppEnvForCompose(config, devLocal)
122
+ const studioService = studioServiceBlock(cwd, devLocal)
123
+ const studioBlock = studioHostDev
124
+ ? ""
125
+ : `
126
+ studio:
127
+ ${studioService}
128
+ environment:
129
+ SUPATYPE_CLOUD_JSON: '{"url":"\${API_EXTERNAL_URL:-http://localhost:18473}","anonKey":"\${ANON_KEY:-}"}'
130
+ expose:
131
+ - "3002"
132
+ `
133
+ const kongDependsOn = studioHostDev
134
+ ? ` - server`
135
+ : ` - server
136
+ - studio`
137
+ const publishDbToHost = !devLocal || hasEngineOverride(config)
138
+ const dbPorts = publishDbToHost
139
+ ? devLocal
140
+ ? ` ports:
141
+ - "127.0.0.1:\${SUPATYPE_DEV_DB_PORT:-54329}:5432"
142
+ `
143
+ : ` ports:
144
+ - "5432:5432"
145
+ `
146
+ : ""
147
+ const serverPorts = devLocal
148
+ ? ""
149
+ : ` ports:
150
+ - "9999:9999"
151
+ `
152
+ const minioPorts = devLocal
153
+ ? ""
154
+ : ` ports:
155
+ - "9000:9000"
156
+ - "9001:9001"
157
+ `
158
+
159
+ return `# Generated by supatype self-host compose
160
+ # Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
161
+ services:
162
+ db:
163
+ image: \${SUPATYPE_POSTGRES_IMAGE:-supatype/postgres:latest}
164
+ environment:
165
+ POSTGRES_USER: \${POSTGRES_USER:-supatype_admin}
166
+ POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-postgres}
167
+ POSTGRES_DB: \${POSTGRES_DB:-supatype}
168
+ ${dbPorts} volumes:
169
+ - db-data:/var/lib/postgresql/data
170
+ healthcheck:
171
+ test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-supatype_admin}"]
172
+ interval: 5s
173
+ timeout: 5s
174
+ retries: 20
175
+
176
+ postgrest:
177
+ image: postgrest/postgrest:v12.2.8
178
+ expose:
179
+ - "3000"
180
+ environment:
181
+ PGRST_DB_URI: postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}
182
+ PGRST_DB_SCHEMA: "public, supatype, graphql_public"
183
+ PGRST_DB_ANON_ROLE: anon
184
+ PGRST_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
185
+ PGRST_DB_EXTRA_SEARCH_PATH: public,extensions
186
+ PGRST_DB_POOL: 3
187
+ depends_on:
188
+ db:
189
+ condition: service_healthy
190
+
191
+ storage:
192
+ image: \${SUPATYPE_STORAGE_IMAGE:-supatype/storage:latest}
193
+ expose:
194
+ - "5000"
195
+ environment:
196
+ PORT: 5000
197
+ DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
198
+ JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
199
+ S3_ENDPOINT: http://minio:9000
200
+ S3_REGION: us-east-1
201
+ S3_ACCESS_KEY: supatype
202
+ S3_SECRET_KEY: supatype-secret
203
+ S3_FORCE_PATH_STYLE: "true"
204
+ depends_on:
205
+ db:
206
+ condition: service_healthy
207
+
208
+ functions-worker:
209
+ image: \${SUPATYPE_FUNCTIONS_WORKER_IMAGE:-supatype/functions-worker:latest}
210
+ expose:
211
+ - "8001"
212
+ volumes:
213
+ - ${projectMount}:/project:ro
214
+ environment:
215
+ SUPATYPE_FUNCTIONS_ROOT: /project/functions
216
+ SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
217
+ PORT: "8001"
218
+ SUPATYPE_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
219
+ SUPATYPE_ANON_KEY: \${ANON_KEY:-}
220
+ SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
221
+ STRIPE_SECRET_KEY: \${STRIPE_SECRET_KEY:-}
222
+ STRIPE_WEBHOOK_SECRET: \${STRIPE_WEBHOOK_SECRET:-}
223
+ SITE_URL: \${SITE_URL:-\${API_EXTERNAL_URL:-http://localhost:18473}}
224
+ depends_on:
225
+ db:
226
+ condition: service_healthy
227
+
228
+ server:
229
+ image: \${SUPATYPE_SERVER_IMAGE:-\${SUPATYPE_AUTH_IMAGE:-supatype/server:latest}}
230
+ ${serverPorts} volumes:
231
+ - ${projectMount}:/project:ro
232
+ working_dir: /project
233
+ environment:
234
+ SUPATYPE_MODE: ${devLocal ? "dev" : "standalone"}
235
+ SUPATYPE_MANIFEST_PATH: /project/.supatype/manifest.json
236
+ SUPATYPE_ADMIN_CONFIG_PATH: /project/.supatype/admin-config.json
237
+ SUPATYPE_API_CONFIG_PATH: /project/.supatype/api-config.json
238
+ SUPATYPE_POSTGREST_URL: http://postgrest:3000
239
+ SUPATYPE_GRAPHQL_URL: http://postgrest:3000
240
+ SUPATYPE_STORAGE_URL: http://storage:5000
241
+ SUPATYPE_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
242
+ SUPATYPE_ANON_KEY: \${ANON_KEY:-}
243
+ SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
244
+ SUPATYPE_SQL_DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
245
+ SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
246
+ SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
247
+ ${appEnv}
248
+ GOTRUE_API_HOST: 0.0.0.0
249
+ GOTRUE_API_PORT: 9999
250
+ API_EXTERNAL_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
251
+ GOTRUE_API_EXTERNAL_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
252
+ GOTRUE_DB_DRIVER: postgres
253
+ GOTRUE_DB_DATABASE_URL: "postgres://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}?search_path=auth"
254
+ GOTRUE_SITE_URL: \${SITE_URL:-http://localhost:3000}
255
+ GOTRUE_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
256
+ GOTRUE_JWT_EXP: 3600
257
+ GOTRUE_JWT_AUD: authenticated
258
+ GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
259
+ GOTRUE_JWT_ADMIN_ROLES: service_role,supatype_admin
260
+ GOTRUE_MAILER_AUTOCONFIRM: \${GOTRUE_MAILER_AUTOCONFIRM:-true}
261
+ GOTRUE_DISABLE_SIGNUP: \${DISABLE_SIGNUP:-false}
262
+ ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
263
+ depends_on:
264
+ db:
265
+ condition: service_healthy
266
+ postgrest:
267
+ condition: service_started
268
+ storage:
269
+ condition: service_started
270
+ functions-worker:
271
+ condition: service_started
272
+
273
+ minio:
274
+ image: minio/minio:RELEASE.2024-11-07T00-52-20Z
275
+ command: server /data --console-address ":9001"
276
+ environment:
277
+ MINIO_ROOT_USER: supatype
278
+ MINIO_ROOT_PASSWORD: supatype-secret
279
+ ${minioPorts} volumes:
280
+ - minio-data:/data
281
+
282
+ schema-engine:
283
+ image: \${SUPATYPE_ENGINE_IMAGE:-supatype/schema-engine:latest}
284
+ profiles: ["tools"]
285
+ entrypoint: ["supatype-engine"]
286
+ volumes:
287
+ - ${projectMount}:/project
288
+ working_dir: /project
289
+ depends_on:
290
+ db:
291
+ condition: service_healthy
292
+ ${studioBlock}
293
+ kong:
294
+ image: kong:3.6
295
+ environment:
296
+ KONG_DATABASE: "off"
297
+ KONG_DECLARATIVE_CONFIG: /etc/kong/kong.yml
298
+ KONG_PROXY_ACCESS_LOG: /dev/stdout
299
+ KONG_ADMIN_ACCESS_LOG: /dev/stdout
300
+ KONG_PROXY_ERROR_LOG: /dev/stderr
301
+ KONG_ADMIN_ERROR_LOG: /dev/stderr
302
+ volumes:
303
+ - ${kongMount}:/etc/kong/kong.yml:ro
304
+ ports:
305
+ - "\${SUPATYPE_KONG_PORT:-18473}:8000"
306
+ depends_on:
307
+ ${kongDependsOn}
308
+
309
+ volumes:
310
+ db-data:
311
+ minio-data:
312
+ `
313
+ }
314
+
315
+ function ensureComposeManifest(cwd: string): void {
316
+ const manifestPath = join(cwd, ".supatype", "manifest.json")
317
+ if (existsSync(manifestPath)) return
318
+ mkdirSync(dirname(manifestPath), { recursive: true })
319
+ const manifest = {
320
+ schema: "public",
321
+ postgrest_url: "http://postgrest:3000",
322
+ storage_url: "http://storage:5000",
323
+ realtime_enabled: true,
324
+ functions_enabled: false,
325
+ }
326
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8")
327
+ }
328
+
329
+ function ensureProjectFunctionsDir(cwd: string, config: SupatypeProjectConfig): void {
330
+ mkdirSync(preferredFunctionsPathFromProject(config, cwd), { recursive: true })
331
+ }
332
+
333
+ export function writeSelfHostCompose(
334
+ cwd: string,
335
+ config: SupatypeProjectConfig,
336
+ options?: SelfHostComposeOptions,
337
+ ): SelfHostComposePaths {
338
+ const paths = selfHostComposePaths(cwd)
339
+ mkdirSync(paths.dir, { recursive: true })
340
+ ensureProjectFunctionsDir(cwd, config)
341
+ ensureComposeManifest(cwd)
342
+ writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd, options), "utf8")
343
+ const studioHostDev = options?.devLocal === true && hasStudioOverride(config)
344
+ writeFileSync(
345
+ paths.kongPath,
346
+ buildKongDeclarative({
347
+ unifiedGateway: true,
348
+ ...(studioHostDev && {
349
+ studioServiceUrl: COMPOSE_STUDIO_HOST_URL,
350
+ studioStripPath: false,
351
+ }),
352
+ }),
353
+ "utf8",
354
+ )
355
+ return paths
356
+ }
357
+
358
+ export function runDockerCompose(
359
+ composePath: string,
360
+ args: string[],
361
+ projectRoot: string = process.cwd(),
362
+ composeProject?: string,
363
+ ): number {
364
+ const envFile = resolve(projectRoot, ".env")
365
+ const composeArgs = ["compose"]
366
+ // Per-project name isolates containers/volumes/network so multiple Supatype
367
+ // projects on one machine never share a database (default would be the
368
+ // ".supatype/self-host" dir name, identical for every project).
369
+ if (composeProject) composeArgs.push("-p", composeProject)
370
+ // Resolve ${VAR} in compose.yml from the project root .env (not .supatype/self-host/).
371
+ composeArgs.push("--project-directory", projectRoot)
372
+ composeArgs.push("-f", composePath)
373
+ if (existsSync(envFile)) {
374
+ composeArgs.push("--env-file", envFile)
375
+ }
376
+ composeArgs.push(...args)
377
+ const result = spawnSync(
378
+ "docker",
379
+ composeArgs,
380
+ { stdio: "inherit", cwd: projectRoot },
381
+ )
382
+ return result.status ?? 1
383
+ }
384
+
385
+ /** Compose project name for a Supatype project — isolates docker state per project. */
386
+ export function composeProjectName(projectName: string): string {
387
+ const slug = projectName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "")
388
+ return `supatype-${slug || "project"}`
389
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Provision storage buckets declared in a schema AST via the storage server API.
3
+ *
4
+ * The storage server is the authority on bucket existence — going through the API
5
+ * ensures it creates any backing resources (directories, S3 buckets, etc.).
6
+ * Buckets already registered return 409 Conflict, which is treated as success.
7
+ */
8
+
9
+ export interface BucketSpec {
10
+ id: string
11
+ public: boolean
12
+ allowed_mime_types?: string[] | null
13
+ file_size_limit?: number | null
14
+ access_mode?: "public" | "private" | "custom"
15
+ s3_bucket_policy?: string | null
16
+ }
17
+
18
+ /**
19
+ * Ensure all declared buckets exist in the storage server.
20
+ *
21
+ * @param storageApiUrl Base URL of the storage API, e.g. "http://localhost:54321/storage/v1"
22
+ * @param serviceRoleKey A service_role JWT for the storage server
23
+ * @param buckets Buckets to provision (from the resolved AST)
24
+ */
25
+ export async function provisionBuckets(
26
+ storageApiUrl: string,
27
+ serviceRoleKey: string,
28
+ buckets: BucketSpec[],
29
+ ): Promise<void> {
30
+ const base = storageApiUrl.replace(/\/$/, "")
31
+ const headers = {
32
+ "Authorization": `Bearer ${serviceRoleKey}`,
33
+ "Content-Type": "application/json",
34
+ }
35
+
36
+ for (const bucket of buckets) {
37
+ const body = JSON.stringify({
38
+ id: bucket.id,
39
+ name: bucket.id,
40
+ public: bucket.public,
41
+ ...(bucket.allowed_mime_types != null && { allowed_mime_types: bucket.allowed_mime_types }),
42
+ ...(bucket.file_size_limit != null && { file_size_limit: bucket.file_size_limit }),
43
+ ...(bucket.access_mode != null && { access_mode: bucket.access_mode }),
44
+ ...(bucket.s3_bucket_policy != null &&
45
+ bucket.s3_bucket_policy !== "" && { s3_bucket_policy: bucket.s3_bucket_policy }),
46
+ })
47
+
48
+ const res = await fetch(`${base}/bucket`, { method: "POST", headers, body })
49
+ .catch(() => null)
50
+
51
+ if (res === null) continue // server not reachable — skip silently
52
+ if (res.status === 409) continue // already exists — fine
53
+ if (!res.ok) {
54
+ const msg = await res.text().catch(() => res.statusText)
55
+ console.warn(`[storage] Failed to provision bucket "${bucket.id}": ${msg}`)
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,16 @@
1
+ import type { SupatypeProjectConfig } from "./project-config.js"
2
+
3
+ export const DEFAULT_STUDIO_ADMIN_ROLES = ["admin", "supatype_admin"] as const
4
+
5
+ /** Studio admin roles from `supatype.config.ts` `admin.roles` or defaults. */
6
+ export function studioAdminRoles(cfg: SupatypeProjectConfig): string[] {
7
+ const roles = cfg.admin?.roles
8
+ if (roles !== undefined && roles.length > 0) return roles
9
+ return [...DEFAULT_STUDIO_ADMIN_ROLES]
10
+ }
11
+
12
+ /** Merge `adminRoles` into engine admin-config JSON for Studio and supatype-server. */
13
+ export function withAdminRoles(admin: unknown, cfg: SupatypeProjectConfig): Record<string, unknown> {
14
+ const base = typeof admin === "object" && admin !== null ? (admin as Record<string, unknown>) : {}
15
+ return { ...base, adminRoles: studioAdminRoles(cfg) }
16
+ }
@@ -0,0 +1,53 @@
1
+ import { existsSync } from "node:fs"
2
+ import { join, resolve } from "node:path"
3
+ import { ProcessManager } from "./process-manager.js"
4
+
5
+ const STUDIO_PORT = 3002
6
+
7
+ export interface StudioDevServerOptions {
8
+ cwd: string
9
+ studioOverride: string
10
+ pidDir: string
11
+ serviceRoleKey: string
12
+ /**
13
+ * Where Vite proxies API requests (Kong gateway port for compose dev, or
14
+ * supatype-server port for native `supatype dev`).
15
+ */
16
+ proxyTarget: string
17
+ /**
18
+ * Public Supatype URL the browser uses. Compose dev: Kong on the host.
19
+ * Native dev: Vite dev server (same origin as Studio).
20
+ */
21
+ viteSupatypeUrl: string
22
+ /** Vite `base` — `/studio/` when behind Kong at `/studio/`; `/` for native dev on :3002. */
23
+ basePath?: string
24
+ }
25
+
26
+ /** Start @supatype/studio Vite dev server when `overrides.studio` is set. */
27
+ export function startStudioViteDevServer(opts: StudioDevServerOptions): ProcessManager | null {
28
+ const studioDir = resolve(opts.cwd, opts.studioOverride)
29
+ const viteJs = join(studioDir, "node_modules", "vite", "bin", "vite.js")
30
+ if (!existsSync(viteJs)) {
31
+ console.warn(`[supatype] ⚠ Studio override set but vite not found at ${viteJs}. Run: pnpm install`)
32
+ return null
33
+ }
34
+
35
+ const basePath = opts.basePath ?? "/"
36
+ return new ProcessManager(
37
+ process.execPath,
38
+ [viteJs, "--port", String(STUDIO_PORT), "--strictPort", "--host"],
39
+ {
40
+ label: "studio",
41
+ pidDir: opts.pidDir,
42
+ cwd: studioDir,
43
+ colour: "\x1b[35m",
44
+ env: {
45
+ VITE_SUPATYPE_URL: opts.viteSupatypeUrl,
46
+ SUPATYPE_PROXY_TARGET: opts.proxyTarget,
47
+ VITE_SUPATYPE_ANON_KEY: opts.serviceRoleKey,
48
+ VITE_SUPATYPE_SERVICE_ROLE_KEY: opts.serviceRoleKey,
49
+ VITE_BASE_PATH: basePath,
50
+ },
51
+ },
52
+ )
53
+ }
package/src/systemd.ts ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * systemd.ts — generate systemd unit files for self-hosted deployments.
3
+ *
4
+ * Usage:
5
+ * generateUnits(config, outputDir)
6
+ * → writes supatype-postgres.service + supatype-server.service to outputDir
7
+ */
8
+
9
+ import { writeFileSync, mkdirSync } from "node:fs"
10
+ import { join, resolve } from "node:path"
11
+ import { homedir } from "node:os"
12
+ import type { SupatypeProjectConfig } from "./project-config.js"
13
+
14
+ export interface SystemdOptions {
15
+ /** Directory where unit files are written. Defaults to .supatype/systemd/. */
16
+ outputDir?: string
17
+ /** User to run services as. Defaults to current user. */
18
+ user?: string
19
+ /** EnvironmentFile path injected into the units. Defaults to project .env. */
20
+ envFile?: string
21
+ }
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Public API
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /**
28
+ * Generate supatype-postgres.service and supatype-server.service.
29
+ *
30
+ * Returns the paths of the written files.
31
+ */
32
+ export function generateUnits(
33
+ config: SupatypeProjectConfig,
34
+ projectDir: string,
35
+ opts: SystemdOptions = {},
36
+ ): { postgres: string; server: string } {
37
+ const outputDir = opts.outputDir ?? resolve(projectDir, ".supatype", "systemd")
38
+ mkdirSync(outputDir, { recursive: true })
39
+
40
+ const user = opts.user ?? process.env["USER"] ?? "supatype"
41
+ const envFile = opts.envFile ?? resolve(projectDir, ".env")
42
+ const stateDir = join(homedir(), ".supatype", "projects", config.project.name)
43
+
44
+ const postgresPath = join(outputDir, "supatype-postgres.service")
45
+ const serverPath = join(outputDir, "supatype-server.service")
46
+
47
+ writeFileSync(postgresPath, postgresUnit(config, stateDir, user, envFile), "utf8")
48
+ writeFileSync(serverPath, serverUnit(config, stateDir, user, envFile), "utf8")
49
+
50
+ return { postgres: postgresPath, server: serverPath }
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Unit templates
55
+ // ---------------------------------------------------------------------------
56
+
57
+ function postgresUnit(
58
+ config: SupatypeProjectConfig,
59
+ stateDir: string,
60
+ user: string,
61
+ envFile: string,
62
+ ): string {
63
+ const dataDir = config.database.data_dir ?? join(stateDir, "data")
64
+ const logDir = join(stateDir, "logs")
65
+ const pgBinDir = `%h/.supatype/cache/postgres/${config.versions.postgres}/bin`
66
+
67
+ return `[Unit]
68
+ Description=Supatype Postgres (${config.project.name})
69
+ After=network.target
70
+ StartLimitIntervalSec=60
71
+ StartLimitBurst=5
72
+
73
+ [Service]
74
+ Type=forking
75
+ User=${user}
76
+ EnvironmentFile=-${envFile}
77
+ ExecStartPre=/bin/mkdir -p ${logDir}
78
+ ExecStart=${pgBinDir}/pg_ctl start \\
79
+ -D ${dataDir} \\
80
+ -l ${logDir}/postgres.log \\
81
+ -w \\
82
+ -t 60
83
+ ExecStop=${pgBinDir}/pg_ctl stop -D ${dataDir} -m fast
84
+ ExecReload=${pgBinDir}/pg_ctl reload -D ${dataDir}
85
+ PIDFile=${stateDir}/pid/postgres.pid
86
+ Restart=on-failure
87
+ RestartSec=5s
88
+ TimeoutStartSec=90
89
+ TimeoutStopSec=30
90
+
91
+ [Install]
92
+ WantedBy=multi-user.target
93
+ `
94
+ }
95
+
96
+ function serverUnit(
97
+ config: SupatypeProjectConfig,
98
+ stateDir: string,
99
+ user: string,
100
+ envFile: string,
101
+ ): string {
102
+ const port = config.server.port ?? 54321
103
+ const serverBin = `%h/.supatype/cache/server/${config.versions.server}/supatype-server`
104
+ const logDir = join(stateDir, "logs")
105
+
106
+ const extraArgs: string[] = [`--mode ${config.server.mode}`]
107
+ if (config.server.domain) extraArgs.push(`--domain ${config.server.domain}`)
108
+
109
+ return `[Unit]
110
+ Description=Supatype Server (${config.project.name})
111
+ After=network.target supatype-postgres.service
112
+ Requires=supatype-postgres.service
113
+ StartLimitIntervalSec=60
114
+ StartLimitBurst=5
115
+
116
+ [Service]
117
+ Type=simple
118
+ User=${user}
119
+ EnvironmentFile=-${envFile}
120
+ ExecStartPre=/bin/mkdir -p ${logDir}
121
+ ExecStart=${serverBin} \\
122
+ --port ${port} \\
123
+ ${extraArgs.join(" \\\n ")}
124
+ PIDFile=${stateDir}/pid/server.pid
125
+ StandardOutput=append:${logDir}/server.log
126
+ StandardError=append:${logDir}/server.log
127
+ Restart=on-failure
128
+ RestartSec=5s
129
+ TimeoutStartSec=30
130
+ TimeoutStopSec=15
131
+ KillMode=mixed
132
+ KillSignal=SIGTERM
133
+
134
+ [Install]
135
+ WantedBy=multi-user.target
136
+ `
137
+ }
package/src/tsx-runner.ts CHANGED
@@ -7,11 +7,16 @@ import { spawnSync, type SpawnSyncOptions } from "node:child_process"
7
7
  import { existsSync, readFileSync } from "node:fs"
8
8
  import { resolve, dirname } from "node:path"
9
9
  import { createRequire } from "node:module"
10
+ import { fileURLToPath } from "node:url"
10
11
  import { writeFileSync, unlinkSync } from "node:fs"
11
12
  import { tmpdir } from "node:os"
12
13
 
13
14
  const _require = createRequire(import.meta.url)
14
15
 
16
+ // The CLI's own source directory — workspace packages are
17
+ // resolvable from here. Eval snippets are written here so ESM resolution finds them.
18
+ const CLI_SRC_DIR = dirname(fileURLToPath(import.meta.url))
19
+
15
20
  /**
16
21
  * Resolve the absolute path to the tsx CLI entry point.
17
22
  * tsx is a direct dependency so this will always succeed after `npm install`.
@@ -34,6 +39,7 @@ function findTsxBin(): string {
34
39
 
35
40
  const TSX_BIN = findTsxBin()
36
41
 
42
+
37
43
  export interface RunResult {
38
44
  stdout: string
39
45
  stderr: string
@@ -65,7 +71,11 @@ export function evalTsSnippet(
65
71
  snippet: string,
66
72
  opts: SpawnSyncOptions = {},
67
73
  ): RunResult {
68
- const tmpFile = resolve(tmpdir(), `supatype-eval-${Date.now()}.mts`)
74
+ // Always write the temp file into the CLI's source directory so that ESM
75
+ // resolution can find workspace packages from there.
76
+ // The subprocess CWD is kept as opts.cwd (the user's project dir) so that
77
+ // any relative paths in the snippet resolve correctly.
78
+ const tmpFile = resolve(CLI_SRC_DIR, `supatype-eval-${Date.now()}.mts`)
69
79
  writeFileSync(tmpFile, snippet, "utf8")
70
80
  try {
71
81
  return runTsFile(tmpFile, opts)