buncargo 1.0.26 → 3.0.0

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 (222) hide show
  1. package/dist/bin.d.ts +1 -12
  2. package/dist/bin.js +261 -252
  3. package/dist/cli/bin.d.ts +13 -0
  4. package/dist/cli/bin.js +315 -0
  5. package/dist/cli/commands/help.d.ts +1 -0
  6. package/dist/cli/commands/runtime.d.ts +5 -0
  7. package/dist/cli/commands/version.d.ts +1 -0
  8. package/dist/cli/index.d.ts +1 -0
  9. package/dist/cli/index.js +14 -0
  10. package/dist/cli/run-cli.d.ts +22 -0
  11. package/dist/cli.d.ts +1 -22
  12. package/dist/cli.js +5 -13
  13. package/dist/config/config.d.ts +1 -0
  14. package/dist/config/define-config.d.ts +13 -0
  15. package/dist/config/index.d.ts +3 -0
  16. package/dist/config/index.js +15 -0
  17. package/dist/config/merge-configs.d.ts +3 -0
  18. package/dist/config/validate-config.d.ts +3 -0
  19. package/dist/config.d.ts +1 -72
  20. package/dist/config.js +12 -12
  21. package/dist/core/docker.d.ts +1 -74
  22. package/dist/core/docker.js +35 -26
  23. package/dist/core/index.d.ts +1 -1
  24. package/dist/core/index.js +123 -108
  25. package/dist/core/network.js +2 -2
  26. package/dist/core/ports.d.ts +22 -0
  27. package/dist/core/ports.js +5 -1
  28. package/dist/core/process.js +1 -1
  29. package/dist/core/tunnel.d.ts +33 -0
  30. package/dist/core/utils.js +2 -2
  31. package/dist/core/watchdog-runner.js +45 -42
  32. package/dist/core/watchdog.d.ts +1 -0
  33. package/dist/core/watchdog.js +4 -2
  34. package/dist/docker/index.d.ts +1 -0
  35. package/dist/docker/index.js +38 -0
  36. package/dist/docker/runtime.d.ts +87 -0
  37. package/dist/docker/runtime.js +37 -0
  38. package/dist/docker-compose/compose.d.ts +1 -0
  39. package/dist/docker-compose/generated-file.d.ts +7 -0
  40. package/dist/docker-compose/index.d.ts +3 -0
  41. package/dist/docker-compose/index.js +15 -0
  42. package/dist/docker-compose/model.d.ts +6 -0
  43. package/dist/docker-compose/services/clickhouse.d.ts +16 -0
  44. package/dist/docker-compose/services/define-docker-service.d.ts +41 -0
  45. package/dist/docker-compose/services/index.d.ts +23 -0
  46. package/dist/docker-compose/services/index.js +17 -0
  47. package/dist/docker-compose/services/postgres.d.ts +12 -0
  48. package/dist/docker-compose/services/redis.d.ts +12 -0
  49. package/dist/docker-compose/services/shared.d.ts +7 -0
  50. package/dist/docker-compose/yaml.d.ts +2 -0
  51. package/dist/environment/create-dev-environment.d.ts +23 -0
  52. package/dist/environment/index.d.ts +1 -0
  53. package/dist/environment/index.js +15 -0
  54. package/dist/environment/logging.d.ts +17 -0
  55. package/dist/environment/seeding.d.ts +9 -0
  56. package/dist/environment.d.ts +1 -23
  57. package/dist/environment.js +12 -14
  58. package/dist/index-045jksh5.js +147 -0
  59. package/dist/index-08wa79cs.js +125 -117
  60. package/dist/index-0kxnae3z.js +335 -0
  61. package/dist/index-1mdrf7nz.js +66 -0
  62. package/dist/index-1yvbwj4k.js +262 -242
  63. package/dist/index-23ev345g.js +475 -0
  64. package/dist/index-2ckr49sf.js +228 -0
  65. package/dist/index-2f47khe5.js +376 -369
  66. package/dist/index-2fr3g85b.js +220 -183
  67. package/dist/index-38xnzpa6.js +450 -0
  68. package/dist/index-3h3dhtf2.js +51 -43
  69. package/dist/index-42x95209.js +51 -43
  70. package/dist/index-4gp0az1g.js +145 -0
  71. package/dist/index-4xrxh8yv.js +72 -0
  72. package/dist/index-5gmws6ah.js +181 -0
  73. package/dist/index-5hka0tff.js +78 -76
  74. package/dist/index-5rfqps4b.js +3 -0
  75. package/dist/index-5t9jxqm0.js +428 -0
  76. package/dist/index-6c1w1xk5.js +101 -0
  77. package/dist/index-6fm7mvwj.js +118 -97
  78. package/dist/index-6srpc523.js +127 -128
  79. package/dist/index-731rzzfp.js +187 -0
  80. package/dist/index-75y4cg2z.js +51 -43
  81. package/dist/index-7ja4ywyj.js +126 -127
  82. package/dist/index-8bw1cmz4.js +531 -0
  83. package/dist/index-8hbbj1mp.js +120 -121
  84. package/dist/index-8xj2p5n5.js +145 -0
  85. package/dist/index-bj79tw5w.js +0 -0
  86. package/dist/index-bnk6nr0g.js +73 -0
  87. package/dist/index-brbbzyks.js +72 -0
  88. package/dist/index-c0dr6mcv.js +123 -0
  89. package/dist/index-cty0bcry.js +235 -218
  90. package/dist/index-d8tyv5se.js +228 -0
  91. package/dist/index-d9efy0n4.js +176 -150
  92. package/dist/index-etfmqjjf.js +427 -0
  93. package/dist/index-fb29934k.js +172 -0
  94. package/dist/index-g50jw1yf.js +72 -0
  95. package/dist/index-g6eb5wdw.js +118 -117
  96. package/dist/index-ggq3yryx.js +99 -95
  97. package/dist/index-h70tce00.js +177 -0
  98. package/dist/index-hkxtfqtc.js +333 -0
  99. package/dist/index-kf3dhser.js +146 -143
  100. package/dist/index-ma6tgdb2.js +500 -0
  101. package/dist/index-mam0bcyz.js +123 -0
  102. package/dist/index-mm412dkp.js +274 -0
  103. package/dist/index-n8v18aeb.js +0 -0
  104. package/dist/index-ndnmnsej.js +378 -371
  105. package/dist/index-p8wty0e2.js +389 -379
  106. package/dist/index-qfphr2fd.js +100 -0
  107. package/dist/index-qqmms8rs.js +51 -43
  108. package/dist/index-qw4093g2.js +51 -43
  109. package/dist/index-qzwpzjbx.js +121 -122
  110. package/dist/index-segbnm0h.js +146 -143
  111. package/dist/index-t0fj6gg1.js +112 -0
  112. package/dist/index-thdkwnv7.js +122 -0
  113. package/dist/index-tjbx2r2t.js +270 -0
  114. package/dist/index-tjqw9vtj.js +62 -54
  115. package/dist/index-vbpb89jy.js +248 -0
  116. package/dist/index-vhs88xhe.js +99 -95
  117. package/dist/index-w8zxnjka.js +249 -0
  118. package/dist/index-wk2na3t9.js +404 -0
  119. package/dist/index-wz9x8g7z.js +383 -373
  120. package/dist/index-x249gyde.js +388 -378
  121. package/dist/index-xkvd0nsd.js +187 -0
  122. package/dist/index-yedqxm1z.js +80 -0
  123. package/dist/index-zfjzzjkf.js +266 -0
  124. package/dist/index.d.ts +12 -8
  125. package/dist/index.js +66 -35
  126. package/dist/lint.d.ts +1 -46
  127. package/dist/lint.js +3 -7
  128. package/dist/loader/cache.d.ts +4 -0
  129. package/dist/loader/find-config-file.d.ts +2 -0
  130. package/dist/loader/index.d.ts +5 -0
  131. package/dist/loader/index.js +24 -0
  132. package/dist/loader/load-dev-env.d.ts +5 -0
  133. package/dist/loader/loader.d.ts +1 -0
  134. package/dist/loader.d.ts +1 -45
  135. package/dist/loader.js +22 -20
  136. package/dist/prisma/index.d.ts +1 -0
  137. package/dist/prisma/prisma.d.ts +29 -0
  138. package/dist/prisma.d.ts +1 -29
  139. package/dist/prisma.js +6 -10
  140. package/dist/src/bin.js +309 -0
  141. package/dist/src/cli.js +5 -0
  142. package/dist/src/config.js +15 -0
  143. package/dist/src/core/docker.js +38 -0
  144. package/dist/src/core/index.js +130 -0
  145. package/dist/src/core/network.js +9 -0
  146. package/dist/src/core/ports.js +23 -0
  147. package/dist/src/core/process.js +31 -0
  148. package/dist/src/core/utils.js +11 -0
  149. package/dist/src/core/watchdog-runner.js +69 -0
  150. package/dist/src/core/watchdog.js +28 -0
  151. package/dist/src/docker/runtime.js +37 -0
  152. package/dist/src/docker-compose/index.js +16 -0
  153. package/dist/src/docker-compose/services/index.js +17 -0
  154. package/dist/src/environment.js +12 -0
  155. package/dist/src/index.js +122 -0
  156. package/dist/src/lint.js +3 -0
  157. package/dist/src/loader.js +25 -0
  158. package/dist/src/prisma.js +6 -0
  159. package/dist/src/types.js +0 -0
  160. package/dist/typecheck/index.d.ts +1 -0
  161. package/dist/typecheck/index.js +7 -0
  162. package/dist/typecheck/typecheck.d.ts +46 -0
  163. package/dist/types/all-types.d.ts +501 -0
  164. package/dist/types/cli.d.ts +1 -0
  165. package/dist/types/config.d.ts +6 -0
  166. package/dist/types/docker.d.ts +15 -0
  167. package/dist/types/environment.d.ts +8 -0
  168. package/dist/types/hooks.d.ts +9 -0
  169. package/dist/types/index.d.ts +1 -0
  170. package/dist/types/index.js +0 -0
  171. package/dist/types/prisma.d.ts +1 -0
  172. package/dist/types.d.ts +1 -393
  173. package/package.json +145 -140
  174. package/readme.md +358 -105
  175. package/src/cli/bin.ts +77 -0
  176. package/src/cli/commands/help.ts +39 -0
  177. package/src/cli/commands/runtime.ts +72 -0
  178. package/src/cli/commands/version.ts +4 -0
  179. package/src/cli/index.ts +1 -0
  180. package/{cli.ts → src/cli/run-cli.ts} +95 -6
  181. package/src/config/define-config.ts +30 -0
  182. package/src/config/index.ts +3 -0
  183. package/src/config/merge-configs.ts +33 -0
  184. package/src/config/validate-config.ts +136 -0
  185. package/{core → src/core}/index.ts +2 -2
  186. package/{core → src/core}/ports.ts +68 -1
  187. package/{core → src/core}/process.ts +6 -2
  188. package/src/core/tunnel.ts +151 -0
  189. package/{core → src/core}/utils.ts +1 -0
  190. package/{core → src/core}/watchdog.ts +5 -1
  191. package/src/docker/index.ts +1 -0
  192. package/{core/docker.ts → src/docker/runtime.ts} +40 -4
  193. package/src/docker-compose/generated-file.ts +45 -0
  194. package/src/docker-compose/index.ts +7 -0
  195. package/src/docker-compose/model.ts +197 -0
  196. package/src/docker-compose/services/clickhouse.ts +79 -0
  197. package/src/docker-compose/services/define-docker-service.ts +109 -0
  198. package/src/docker-compose/services/index.ts +67 -0
  199. package/src/docker-compose/services/postgres.ts +60 -0
  200. package/src/docker-compose/services/redis.ts +48 -0
  201. package/src/docker-compose/services/shared.ts +79 -0
  202. package/src/docker-compose/yaml.ts +88 -0
  203. package/{environment.ts → src/environment/create-dev-environment.ts} +101 -146
  204. package/src/environment/index.ts +1 -0
  205. package/src/environment/logging.ts +101 -0
  206. package/src/environment/seeding.ts +57 -0
  207. package/{index.ts → src/index.ts} +49 -15
  208. package/src/loader/cache.ts +23 -0
  209. package/src/loader/find-config-file.ts +29 -0
  210. package/src/loader/index.ts +17 -0
  211. package/src/loader/load-dev-env.ts +38 -0
  212. package/src/prisma/index.ts +1 -0
  213. package/{prisma.ts → src/prisma/prisma.ts} +4 -2
  214. package/src/typecheck/index.ts +1 -0
  215. package/{types.ts → src/types/all-types.ts} +137 -6
  216. package/src/types/index.ts +1 -0
  217. package/bin.ts +0 -191
  218. package/config.ts +0 -194
  219. package/loader.ts +0 -126
  220. /package/{core → src/core}/network.ts +0 -0
  221. /package/{core → src/core}/watchdog-runner.ts +0 -0
  222. /package/{lint.ts → src/typecheck/typecheck.ts} +0 -0
@@ -1,390 +1,397 @@
1
+ // environment.ts
2
+ import pc from "picocolors";
1
3
  import {
2
- spawnWatchdog,
3
- startHeartbeat,
4
- stopHeartbeat,
5
- stopWatchdog
6
- } from "./index-vhs88xhe.js";
7
- import {
8
- buildApps,
9
- execAsync,
10
- startDevServers,
11
- stopProcess
12
- } from "./index-cty0bcry.js";
13
- import {
14
- assertValidConfig
15
- } from "./index-tjqw9vtj.js";
16
- import {
17
- createPrismaRunner
18
- } from "./index-5hka0tff.js";
19
- import {
20
- areContainersRunning,
21
- startContainers,
22
- stopContainers,
23
- waitForAllServices
4
+ areContainersRunning,
5
+ startContainers,
6
+ stopContainers,
7
+ waitForAllServices,
24
8
  } from "./index-2fr3g85b.js";
9
+ import { createPrismaRunner } from "./index-5hka0tff.js";
25
10
  import {
26
- getLocalIp,
27
- isCI,
28
- logExpoApiUrl,
29
- logFrontendPort,
30
- waitForDevServers,
31
- waitForServer
11
+ getLocalIp,
12
+ isCI,
13
+ logExpoApiUrl,
14
+ logFrontendPort,
15
+ waitForDevServers,
16
+ waitForServer,
32
17
  } from "./index-6fm7mvwj.js";
33
18
  import {
34
- calculatePortOffset,
35
- computePorts,
36
- computeUrls,
37
- findMonorepoRoot,
38
- getProjectName,
39
- isWorktree
19
+ calculatePortOffset,
20
+ computePorts,
21
+ computeUrls,
22
+ findMonorepoRoot,
23
+ getProjectName,
24
+ isWorktree,
40
25
  } from "./index-08wa79cs.js";
26
+ import {
27
+ buildApps,
28
+ execAsync,
29
+ startDevServers,
30
+ stopProcess,
31
+ } from "./index-cty0bcry.js";
32
+ import { assertValidConfig } from "./index-tjqw9vtj.js";
33
+ import {
34
+ spawnWatchdog,
35
+ startHeartbeat,
36
+ stopHeartbeat,
37
+ stopWatchdog,
38
+ } from "./index-vhs88xhe.js";
41
39
 
42
- // environment.ts
43
- import pc from "picocolors";
44
40
  function formatUrl(url) {
45
- return pc.cyan(url.replace(/:(\d+)(\/?)/, (_, port, slash) => `:${pc.bold(port)}${slash}`));
41
+ return pc.cyan(
42
+ url.replace(/:(\d+)(\/?)/, (_, port, slash) => `:${pc.bold(port)}${slash}`),
43
+ );
46
44
  }
47
45
  function formatLabel(label, value, arrow = "➜") {
48
- return ` ${pc.green(arrow)} ${pc.bold(label.padEnd(10))} ${value}`;
46
+ return ` ${pc.green(arrow)} ${pc.bold(label.padEnd(10))} ${value}`;
49
47
  }
50
48
  function formatDimLabel(label, value) {
51
- return ` ${pc.dim("•")} ${pc.dim(label.padEnd(10))} ${pc.dim(value)}`;
49
+ return ` ${pc.dim("•")} ${pc.dim(label.padEnd(10))} ${pc.dim(value)}`;
52
50
  }
53
51
  function createDevEnvironment(config, options = {}) {
54
- assertValidConfig(config);
55
- const root = findMonorepoRoot();
56
- const suffix = options.suffix;
57
- const worktree = isWorktree(root);
58
- const portOffset = calculatePortOffset(suffix, root);
59
- const projectName = getProjectName(config.projectPrefix, suffix, root);
60
- const localIp = getLocalIp();
61
- const services = config.services;
62
- const apps = config.apps ?? {};
63
- const ports = computePorts(services, apps, portOffset);
64
- const urls = computeUrls(services, apps, ports, localIp);
65
- function buildEnvVars(production = false) {
66
- const baseEnv = {
67
- COMPOSE_PROJECT_NAME: projectName,
68
- NODE_ENV: production ? "production" : "development"
69
- };
70
- for (const [name, port] of Object.entries(ports)) {
71
- const envName = `${name.toUpperCase()}_PORT`;
72
- baseEnv[envName] = String(port);
73
- }
74
- for (const [name, url] of Object.entries(urls)) {
75
- const envName = `${name.toUpperCase()}_URL`;
76
- baseEnv[envName] = url;
77
- }
78
- if (config.envVars) {
79
- const userEnv = config.envVars(ports, urls, {
80
- projectName,
81
- localIp,
82
- portOffset
83
- });
84
- for (const [key, value] of Object.entries(userEnv)) {
85
- baseEnv[key] = String(value);
86
- }
87
- }
88
- return baseEnv;
89
- }
90
- let hookContext = null;
91
- function getHookContext() {
92
- if (!hookContext) {
93
- hookContext = {
94
- projectName,
95
- ports,
96
- urls,
97
- root,
98
- isCI: isCI(),
99
- portOffset,
100
- localIp,
101
- exec: async (cmd, opts) => {
102
- const envVars = buildEnvVars();
103
- return execAsync(cmd, root, envVars, opts);
104
- }
105
- };
106
- }
107
- return hookContext;
108
- }
109
- function exec(cmd, options2) {
110
- const envVars = buildEnvVars();
111
- return execAsync(cmd, root, envVars, options2);
112
- }
113
- async function start(startOptions = {}) {
114
- const isCI2 = process.env.CI === "true";
115
- const {
116
- verbose = config.options?.verbose ?? true,
117
- wait = true,
118
- startServers: shouldStartServers = true,
119
- productionBuild = isCI2
120
- } = startOptions;
121
- const envVars = buildEnvVars(productionBuild);
122
- if (verbose) {
123
- logInfo(productionBuild ? "Production Environment" : "Dev Environment");
124
- }
125
- const serviceCount = Object.keys(services).length;
126
- const alreadyRunning = await areContainersRunning(projectName, serviceCount);
127
- if (alreadyRunning) {
128
- if (verbose)
129
- console.log("✓ Containers already running");
130
- } else {
131
- startContainers(root, projectName, envVars, {
132
- verbose,
133
- wait,
134
- composeFile: config.options?.composeFile
135
- });
136
- }
137
- if (wait) {
138
- await waitForAllServices(services, ports, {
139
- verbose,
140
- projectName,
141
- root
142
- });
143
- }
144
- const allMigrations = [
145
- ...config.prisma ? [
146
- {
147
- name: "prisma",
148
- command: "bunx prisma migrate deploy",
149
- cwd: config.prisma.cwd ?? "packages/prisma"
150
- }
151
- ] : [],
152
- ...config.migrations ?? []
153
- ];
154
- if (allMigrations.length > 0) {
155
- if (verbose)
156
- console.log("\uD83D\uDCE6 Running migrations...");
157
- const migrationResults = await Promise.all(allMigrations.map(async (migration) => {
158
- const result = await exec(migration.command, {
159
- cwd: migration.cwd,
160
- throwOnError: false
161
- });
162
- return { name: migration.name, result };
163
- }));
164
- for (const { name, result } of migrationResults) {
165
- if (result.exitCode !== 0) {
166
- console.error(`❌ Migration "${name}" failed`);
167
- console.error(result.stderr);
168
- throw new Error(`Migration "${name}" failed`);
169
- }
170
- }
171
- if (verbose)
172
- console.log("✓ Migrations complete");
173
- }
174
- if (config.hooks?.afterContainersReady) {
175
- await config.hooks.afterContainersReady(getHookContext());
176
- }
177
- if (config.seed) {
178
- let shouldSeed = true;
179
- if (config.seed.check) {
180
- const checkTable = async (tableName, service) => {
181
- const serviceName = service ?? "postgres";
182
- const serviceUrl = urls[serviceName];
183
- if (!serviceUrl) {
184
- console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
185
- return true;
186
- }
187
- const checkResult = await exec(`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`, { throwOnError: false });
188
- const count = checkResult.stdout.trim();
189
- return checkResult.exitCode !== 0 || count === "0" || count === "";
190
- };
191
- const seedCheckContext = {
192
- ...getHookContext(),
193
- checkTable
194
- };
195
- shouldSeed = await config.seed.check(seedCheckContext);
196
- }
197
- if (shouldSeed) {
198
- if (verbose)
199
- console.log("\uD83C\uDF31 Running seeders...");
200
- const seedResult = await exec(config.seed.command, {
201
- cwd: config.seed.cwd,
202
- verbose,
203
- throwOnError: false
204
- });
205
- if (seedResult.exitCode !== 0) {
206
- console.error("❌ Seeding failed");
207
- console.error(seedResult.stderr);
208
- } else {
209
- if (verbose)
210
- console.log("✓ Seeding complete");
211
- }
212
- } else {
213
- if (verbose)
214
- console.log("✓ Database already has data, skipping seeders");
215
- }
216
- }
217
- if (shouldStartServers && Object.keys(apps).length > 0) {
218
- if (config.hooks?.beforeServers) {
219
- await config.hooks.beforeServers(getHookContext());
220
- }
221
- if (productionBuild) {
222
- buildApps(apps, root, envVars, { verbose });
223
- }
224
- const pids = await startDevServers(apps, root, envVars, ports, {
225
- verbose,
226
- productionBuild,
227
- isCI: isCI2
228
- });
229
- if (verbose)
230
- console.log("⏳ Waiting for servers to be ready...");
231
- await waitForDevServers(apps, ports, {
232
- timeout: isCI2 ? 120000 : 60000,
233
- verbose,
234
- productionBuild
235
- });
236
- if (config.hooks?.afterServers) {
237
- await config.hooks.afterServers(getHookContext());
238
- }
239
- if (verbose)
240
- console.log(`✅ Environment ready
52
+ assertValidConfig(config);
53
+ const root = findMonorepoRoot();
54
+ const suffix = options.suffix;
55
+ const worktree = isWorktree(root);
56
+ const portOffset = calculatePortOffset(suffix, root);
57
+ const projectName = getProjectName(config.projectPrefix, suffix, root);
58
+ const localIp = getLocalIp();
59
+ const services = config.services;
60
+ const apps = config.apps ?? {};
61
+ const ports = computePorts(services, apps, portOffset);
62
+ const urls = computeUrls(services, apps, ports, localIp);
63
+ function buildEnvVars(production = false) {
64
+ const baseEnv = {
65
+ COMPOSE_PROJECT_NAME: projectName,
66
+ NODE_ENV: production ? "production" : "development",
67
+ };
68
+ for (const [name, port] of Object.entries(ports)) {
69
+ const envName = `${name.toUpperCase()}_PORT`;
70
+ baseEnv[envName] = String(port);
71
+ }
72
+ for (const [name, url] of Object.entries(urls)) {
73
+ const envName = `${name.toUpperCase()}_URL`;
74
+ baseEnv[envName] = url;
75
+ }
76
+ if (config.envVars) {
77
+ const userEnv = config.envVars(ports, urls, {
78
+ projectName,
79
+ localIp,
80
+ portOffset,
81
+ });
82
+ for (const [key, value] of Object.entries(userEnv)) {
83
+ baseEnv[key] = String(value);
84
+ }
85
+ }
86
+ return baseEnv;
87
+ }
88
+ let hookContext = null;
89
+ function getHookContext() {
90
+ if (!hookContext) {
91
+ hookContext = {
92
+ projectName,
93
+ ports,
94
+ urls,
95
+ root,
96
+ isCI: isCI(),
97
+ portOffset,
98
+ localIp,
99
+ exec: async (cmd, opts) => {
100
+ const envVars = buildEnvVars();
101
+ return execAsync(cmd, root, envVars, opts);
102
+ },
103
+ };
104
+ }
105
+ return hookContext;
106
+ }
107
+ function exec(cmd, options2) {
108
+ const envVars = buildEnvVars();
109
+ return execAsync(cmd, root, envVars, options2);
110
+ }
111
+ async function start(startOptions = {}) {
112
+ const isCI2 = process.env.CI === "true";
113
+ const {
114
+ verbose = config.options?.verbose ?? true,
115
+ wait = true,
116
+ startServers: shouldStartServers = true,
117
+ productionBuild = isCI2,
118
+ } = startOptions;
119
+ const envVars = buildEnvVars(productionBuild);
120
+ if (verbose) {
121
+ logInfo(productionBuild ? "Production Environment" : "Dev Environment");
122
+ }
123
+ const serviceCount = Object.keys(services).length;
124
+ const alreadyRunning = await areContainersRunning(
125
+ projectName,
126
+ serviceCount,
127
+ );
128
+ if (alreadyRunning) {
129
+ if (verbose) console.log("✓ Containers already running");
130
+ } else {
131
+ startContainers(root, projectName, envVars, {
132
+ verbose,
133
+ wait,
134
+ composeFile: config.options?.composeFile,
135
+ });
136
+ }
137
+ if (wait) {
138
+ await waitForAllServices(services, ports, {
139
+ verbose,
140
+ projectName,
141
+ root,
142
+ });
143
+ }
144
+ const allMigrations = [
145
+ ...(config.prisma
146
+ ? [
147
+ {
148
+ name: "prisma",
149
+ command: "bunx prisma migrate deploy",
150
+ cwd: config.prisma.cwd ?? "packages/prisma",
151
+ },
152
+ ]
153
+ : []),
154
+ ...(config.migrations ?? []),
155
+ ];
156
+ if (allMigrations.length > 0) {
157
+ if (verbose) console.log("\uD83D\uDCE6 Running migrations...");
158
+ const migrationResults = await Promise.all(
159
+ allMigrations.map(async (migration) => {
160
+ const result = await exec(migration.command, {
161
+ cwd: migration.cwd,
162
+ throwOnError: false,
163
+ });
164
+ return { name: migration.name, result };
165
+ }),
166
+ );
167
+ for (const { name, result } of migrationResults) {
168
+ if (result.exitCode !== 0) {
169
+ console.error(`❌ Migration "${name}" failed`);
170
+ console.error(result.stderr);
171
+ throw new Error(`Migration "${name}" failed`);
172
+ }
173
+ }
174
+ if (verbose) console.log("✓ Migrations complete");
175
+ }
176
+ if (config.hooks?.afterContainersReady) {
177
+ await config.hooks.afterContainersReady(getHookContext());
178
+ }
179
+ if (config.seed) {
180
+ let shouldSeed = true;
181
+ if (config.seed.check) {
182
+ const checkTable = async (tableName, service) => {
183
+ const serviceName = service ?? "postgres";
184
+ const serviceUrl = urls[serviceName];
185
+ if (!serviceUrl) {
186
+ console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
187
+ return true;
188
+ }
189
+ const checkResult = await exec(
190
+ `psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`,
191
+ { throwOnError: false },
192
+ );
193
+ const count = checkResult.stdout.trim();
194
+ return checkResult.exitCode !== 0 || count === "0" || count === "";
195
+ };
196
+ const seedCheckContext = {
197
+ ...getHookContext(),
198
+ checkTable,
199
+ };
200
+ shouldSeed = await config.seed.check(seedCheckContext);
201
+ }
202
+ if (shouldSeed) {
203
+ if (verbose) console.log("\uD83C\uDF31 Running seeders...");
204
+ const seedResult = await exec(config.seed.command, {
205
+ cwd: config.seed.cwd,
206
+ verbose,
207
+ throwOnError: false,
208
+ });
209
+ if (seedResult.exitCode !== 0) {
210
+ console.error("❌ Seeding failed");
211
+ console.error(seedResult.stderr);
212
+ } else {
213
+ if (verbose) console.log("✓ Seeding complete");
214
+ }
215
+ } else {
216
+ if (verbose)
217
+ console.log("✓ Database already has data, skipping seeders");
218
+ }
219
+ }
220
+ if (shouldStartServers && Object.keys(apps).length > 0) {
221
+ if (config.hooks?.beforeServers) {
222
+ await config.hooks.beforeServers(getHookContext());
223
+ }
224
+ if (productionBuild) {
225
+ buildApps(apps, root, envVars, { verbose });
226
+ }
227
+ const pids = await startDevServers(apps, root, envVars, ports, {
228
+ verbose,
229
+ productionBuild,
230
+ isCI: isCI2,
231
+ });
232
+ if (verbose) console.log("⏳ Waiting for servers to be ready...");
233
+ await waitForDevServers(apps, ports, {
234
+ timeout: isCI2 ? 120000 : 60000,
235
+ verbose,
236
+ productionBuild,
237
+ });
238
+ if (config.hooks?.afterServers) {
239
+ await config.hooks.afterServers(getHookContext());
240
+ }
241
+ if (verbose)
242
+ console.log(`✅ Environment ready
241
243
  `);
242
- return pids;
243
- }
244
- if (verbose)
245
- console.log(`✅ Containers ready
244
+ return pids;
245
+ }
246
+ if (verbose)
247
+ console.log(`✅ Containers ready
246
248
  `);
247
- return null;
248
- }
249
- async function stop(stopOptions = {}) {
250
- const { verbose = true, removeVolumes = false } = stopOptions;
251
- if (config.hooks?.beforeStop) {
252
- await config.hooks.beforeStop(getHookContext());
253
- }
254
- stopContainers(root, projectName, {
255
- verbose,
256
- removeVolumes,
257
- composeFile: config.options?.composeFile
258
- });
259
- }
260
- async function restart() {
261
- await stop();
262
- await start({ startServers: false });
263
- }
264
- async function isRunning() {
265
- const serviceCount = Object.keys(services).length;
266
- return areContainersRunning(projectName, serviceCount);
267
- }
268
- async function startServersOnly(options2 = {}) {
269
- const { productionBuild = false, verbose = true } = options2;
270
- const envVars = buildEnvVars(productionBuild);
271
- const isCI2 = process.env.CI === "true";
272
- if (productionBuild) {
273
- buildApps(apps, root, envVars, { verbose });
274
- }
275
- return startDevServers(apps, root, envVars, ports, {
276
- verbose,
277
- productionBuild,
278
- isCI: isCI2
279
- });
280
- }
281
- async function waitForServersReady(options2 = {}) {
282
- const { timeout = 60000, productionBuild = false } = options2;
283
- await waitForDevServers(apps, ports, { timeout, productionBuild });
284
- }
285
- function logInfo(label = "Docker Dev") {
286
- const serviceNames = Object.keys(services);
287
- const appNames = Object.keys(apps);
288
- console.log("");
289
- console.log(` ${pc.cyan(pc.bold(`\uD83D\uDC33 ${label}`))}`);
290
- console.log(formatLabel("Project:", pc.white(projectName)));
291
- if (serviceNames.length > 0) {
292
- console.log("");
293
- console.log(` ${pc.dim("─── Services ───")}`);
294
- for (const name of serviceNames) {
295
- const port = ports[name];
296
- const url = `localhost:${port}`;
297
- console.log(formatLabel(`${name}:`, formatUrl(`http://${url}`)));
298
- }
299
- }
300
- if (appNames.length > 0) {
301
- console.log("");
302
- console.log(` ${pc.dim("─── Applications ───")}`);
303
- for (const name of appNames) {
304
- const port = ports[name];
305
- const localUrl = `http://localhost:${port}`;
306
- const networkUrl = `http://${localIp}:${port}`;
307
- console.log(` ${pc.green("➜")} ${pc.bold(pc.cyan(name))}`);
308
- console.log(` ${pc.dim("Local:")} ${formatUrl(localUrl)}`);
309
- console.log(` ${pc.dim("Network:")} ${formatUrl(networkUrl)}`);
310
- }
311
- }
312
- console.log("");
313
- console.log(` ${pc.dim("─── Environment ───")}`);
314
- console.log(formatDimLabel("Worktree:", worktree ? "yes" : "no"));
315
- console.log(formatDimLabel("Port offset:", portOffset > 0 ? `+${portOffset}` : "none"));
316
- if (suffix) {
317
- console.log(formatDimLabel("Suffix:", suffix));
318
- }
319
- console.log(formatDimLabel("Local IP:", localIp));
320
- console.log("");
321
- }
322
- async function waitForServerUrl(url, timeout) {
323
- await waitForServer(url, { timeout });
324
- }
325
- function startHeartbeat2(intervalMs) {
326
- startHeartbeat(projectName, intervalMs);
327
- }
328
- function stopHeartbeat2() {
329
- stopHeartbeat();
330
- }
331
- async function spawnWatchdog2(timeoutMinutes) {
332
- await spawnWatchdog(projectName, root, {
333
- timeoutMinutes,
334
- verbose: true,
335
- composeFile: config.options?.composeFile
336
- });
337
- }
338
- function stopWatchdog2() {
339
- stopWatchdog(projectName);
340
- }
341
- function getExpoApiUrl() {
342
- const apiPort = ports.api;
343
- const url = `http://${localIp}:${apiPort}`;
344
- logExpoApiUrl(url);
345
- return url;
346
- }
347
- function getFrontendPort() {
348
- const port = ports.platform;
349
- logFrontendPort(port);
350
- return port;
351
- }
352
- function withSuffix(newSuffix) {
353
- return createDevEnvironment(config, { suffix: newSuffix });
354
- }
355
- const env = {
356
- projectName,
357
- ports,
358
- urls,
359
- apps,
360
- portOffset,
361
- isWorktree: worktree,
362
- localIp,
363
- root,
364
- start,
365
- stop,
366
- restart,
367
- isRunning,
368
- startServers: startServersOnly,
369
- stopProcess,
370
- waitForServers: waitForServersReady,
371
- buildEnvVars,
372
- exec,
373
- waitForServer: waitForServerUrl,
374
- logInfo,
375
- getExpoApiUrl,
376
- getFrontendPort,
377
- startHeartbeat: startHeartbeat2,
378
- stopHeartbeat: stopHeartbeat2,
379
- spawnWatchdog: spawnWatchdog2,
380
- stopWatchdog: stopWatchdog2,
381
- prisma: undefined,
382
- withSuffix
383
- };
384
- if (config.prisma) {
385
- env.prisma = createPrismaRunner(env, config.prisma);
386
- }
387
- return env;
249
+ return null;
250
+ }
251
+ async function stop(stopOptions = {}) {
252
+ const { verbose = true, removeVolumes = false } = stopOptions;
253
+ if (config.hooks?.beforeStop) {
254
+ await config.hooks.beforeStop(getHookContext());
255
+ }
256
+ stopContainers(root, projectName, {
257
+ verbose,
258
+ removeVolumes,
259
+ composeFile: config.options?.composeFile,
260
+ });
261
+ }
262
+ async function restart() {
263
+ await stop();
264
+ await start({ startServers: false });
265
+ }
266
+ async function isRunning() {
267
+ const serviceCount = Object.keys(services).length;
268
+ return areContainersRunning(projectName, serviceCount);
269
+ }
270
+ async function startServersOnly(options2 = {}) {
271
+ const { productionBuild = false, verbose = true } = options2;
272
+ const envVars = buildEnvVars(productionBuild);
273
+ const isCI2 = process.env.CI === "true";
274
+ if (productionBuild) {
275
+ buildApps(apps, root, envVars, { verbose });
276
+ }
277
+ return startDevServers(apps, root, envVars, ports, {
278
+ verbose,
279
+ productionBuild,
280
+ isCI: isCI2,
281
+ });
282
+ }
283
+ async function waitForServersReady(options2 = {}) {
284
+ const { timeout = 60000, productionBuild = false } = options2;
285
+ await waitForDevServers(apps, ports, { timeout, productionBuild });
286
+ }
287
+ function logInfo(label = "Docker Dev") {
288
+ const serviceNames = Object.keys(services);
289
+ const appNames = Object.keys(apps);
290
+ console.log("");
291
+ console.log(` ${pc.cyan(pc.bold(`\uD83D\uDC33 ${label}`))}`);
292
+ console.log(formatLabel("Project:", pc.white(projectName)));
293
+ if (serviceNames.length > 0) {
294
+ console.log("");
295
+ console.log(` ${pc.dim("─── Services ───")}`);
296
+ for (const name of serviceNames) {
297
+ const port = ports[name];
298
+ const url = `localhost:${port}`;
299
+ console.log(formatLabel(`${name}:`, formatUrl(`http://${url}`)));
300
+ }
301
+ }
302
+ if (appNames.length > 0) {
303
+ console.log("");
304
+ console.log(` ${pc.dim("─── Applications ───")}`);
305
+ for (const name of appNames) {
306
+ const port = ports[name];
307
+ const localUrl = `http://localhost:${port}`;
308
+ const networkUrl = `http://${localIp}:${port}`;
309
+ console.log(` ${pc.green("➜")} ${pc.bold(pc.cyan(name))}`);
310
+ console.log(` ${pc.dim("Local:")} ${formatUrl(localUrl)}`);
311
+ console.log(` ${pc.dim("Network:")} ${formatUrl(networkUrl)}`);
312
+ }
313
+ }
314
+ console.log("");
315
+ console.log(` ${pc.dim("─── Environment ───")}`);
316
+ console.log(formatDimLabel("Worktree:", worktree ? "yes" : "no"));
317
+ console.log(
318
+ formatDimLabel(
319
+ "Port offset:",
320
+ portOffset > 0 ? `+${portOffset}` : "none",
321
+ ),
322
+ );
323
+ if (suffix) {
324
+ console.log(formatDimLabel("Suffix:", suffix));
325
+ }
326
+ console.log(formatDimLabel("Local IP:", localIp));
327
+ console.log("");
328
+ }
329
+ async function waitForServerUrl(url, timeout) {
330
+ await waitForServer(url, { timeout });
331
+ }
332
+ function startHeartbeat2(intervalMs) {
333
+ startHeartbeat(projectName, intervalMs);
334
+ }
335
+ function stopHeartbeat2() {
336
+ stopHeartbeat();
337
+ }
338
+ async function spawnWatchdog2(timeoutMinutes) {
339
+ await spawnWatchdog(projectName, root, {
340
+ timeoutMinutes,
341
+ verbose: true,
342
+ composeFile: config.options?.composeFile,
343
+ });
344
+ }
345
+ function stopWatchdog2() {
346
+ stopWatchdog(projectName);
347
+ }
348
+ function getExpoApiUrl() {
349
+ const apiPort = ports.api;
350
+ const url = `http://${localIp}:${apiPort}`;
351
+ logExpoApiUrl(url);
352
+ return url;
353
+ }
354
+ function getFrontendPort() {
355
+ const port = ports.platform;
356
+ logFrontendPort(port);
357
+ return port;
358
+ }
359
+ function withSuffix(newSuffix) {
360
+ return createDevEnvironment(config, { suffix: newSuffix });
361
+ }
362
+ const env = {
363
+ projectName,
364
+ ports,
365
+ urls,
366
+ apps,
367
+ portOffset,
368
+ isWorktree: worktree,
369
+ localIp,
370
+ root,
371
+ start,
372
+ stop,
373
+ restart,
374
+ isRunning,
375
+ startServers: startServersOnly,
376
+ stopProcess,
377
+ waitForServers: waitForServersReady,
378
+ buildEnvVars,
379
+ exec,
380
+ waitForServer: waitForServerUrl,
381
+ logInfo,
382
+ getExpoApiUrl,
383
+ getFrontendPort,
384
+ startHeartbeat: startHeartbeat2,
385
+ stopHeartbeat: stopHeartbeat2,
386
+ spawnWatchdog: spawnWatchdog2,
387
+ stopWatchdog: stopWatchdog2,
388
+ prisma: undefined,
389
+ withSuffix,
390
+ };
391
+ if (config.prisma) {
392
+ env.prisma = createPrismaRunner(env, config.prisma);
393
+ }
394
+ return env;
388
395
  }
389
396
 
390
397
  export { createDevEnvironment };