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