buncargo 1.0.29 → 3.2.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 (246) 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 +317 -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 +30 -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/quick-tunnel/cloudflared-process.d.ts +10 -0
  29. package/dist/core/quick-tunnel/constants.d.ts +9 -0
  30. package/dist/core/quick-tunnel/index.d.ts +17 -0
  31. package/dist/core/quick-tunnel/install.d.ts +1 -0
  32. package/dist/core/tunnel.d.ts +34 -0
  33. package/dist/core/utils.js +2 -2
  34. package/dist/core/watchdog-runner.js +45 -42
  35. package/dist/core/watchdog.d.ts +1 -0
  36. package/dist/core/watchdog.js +4 -2
  37. package/dist/docker/index.d.ts +1 -0
  38. package/dist/docker/index.js +38 -0
  39. package/dist/docker/runtime.d.ts +87 -0
  40. package/dist/docker/runtime.js +37 -0
  41. package/dist/docker-compose/compose.d.ts +1 -0
  42. package/dist/docker-compose/generated-file.d.ts +7 -0
  43. package/dist/docker-compose/index.d.ts +3 -0
  44. package/dist/docker-compose/index.js +15 -0
  45. package/dist/docker-compose/model.d.ts +6 -0
  46. package/dist/docker-compose/services/clickhouse.d.ts +16 -0
  47. package/dist/docker-compose/services/define-docker-service.d.ts +41 -0
  48. package/dist/docker-compose/services/index.d.ts +23 -0
  49. package/dist/docker-compose/services/index.js +17 -0
  50. package/dist/docker-compose/services/postgres.d.ts +12 -0
  51. package/dist/docker-compose/services/redis.d.ts +12 -0
  52. package/dist/docker-compose/services/shared.d.ts +7 -0
  53. package/dist/docker-compose/yaml.d.ts +2 -0
  54. package/dist/environment/create-dev-environment.d.ts +23 -0
  55. package/dist/environment/index.d.ts +1 -0
  56. package/dist/environment/index.js +15 -0
  57. package/dist/environment/logging.d.ts +17 -0
  58. package/dist/environment/only-apps.d.ts +10 -0
  59. package/dist/environment/seeding.d.ts +9 -0
  60. package/dist/environment.d.ts +1 -23
  61. package/dist/environment.js +12 -14
  62. package/dist/index-045jksh5.js +147 -0
  63. package/dist/index-08wa79cs.js +125 -117
  64. package/dist/index-0kxnae3z.js +335 -0
  65. package/dist/index-1mdrf7nz.js +51 -43
  66. package/dist/index-1yvbwj4k.js +262 -242
  67. package/dist/index-23ev345g.js +475 -0
  68. package/dist/index-2ckr49sf.js +228 -0
  69. package/dist/index-2f47khe5.js +376 -369
  70. package/dist/index-2fr3g85b.js +220 -183
  71. package/dist/index-38xnzpa6.js +450 -0
  72. package/dist/index-3eyrdxw9.js +577 -0
  73. package/dist/index-3h3dhtf2.js +51 -43
  74. package/dist/index-42x95209.js +51 -43
  75. package/dist/index-4gp0az1g.js +145 -0
  76. package/dist/index-4xrxh8yv.js +72 -0
  77. package/dist/index-5aq985p4.js +250 -0
  78. package/dist/index-5gmws6ah.js +181 -0
  79. package/dist/index-5hka0tff.js +78 -76
  80. package/dist/index-5rfqps4b.js +3 -0
  81. package/dist/index-5t9jxqm0.js +428 -0
  82. package/dist/index-6c1w1xk5.js +101 -0
  83. package/dist/index-6cmex7m5.js +72 -0
  84. package/dist/index-6d6x175r.js +572 -0
  85. package/dist/index-6fm7mvwj.js +118 -97
  86. package/dist/index-6srpc523.js +127 -128
  87. package/dist/index-731rzzfp.js +157 -142
  88. package/dist/index-75y4cg2z.js +51 -43
  89. package/dist/index-7ja4ywyj.js +126 -127
  90. package/dist/index-7v19es2e.js +666 -0
  91. package/dist/index-8bw1cmz4.js +531 -0
  92. package/dist/index-8hbbj1mp.js +120 -121
  93. package/dist/index-8xj2p5n5.js +118 -97
  94. package/dist/index-9wyhzw0h.js +574 -0
  95. package/dist/index-ag90ry8t.js +576 -0
  96. package/dist/index-bj79tw5w.js +0 -0
  97. package/dist/index-bnk6nr0g.js +73 -0
  98. package/dist/index-brbbzyks.js +72 -0
  99. package/dist/index-byeqyjrz.js +72 -0
  100. package/dist/index-c0dr6mcv.js +123 -0
  101. package/dist/index-cty0bcry.js +235 -218
  102. package/dist/index-d8tyv5se.js +228 -0
  103. package/dist/index-d9efy0n4.js +176 -150
  104. package/dist/index-enj4zdma.js +574 -0
  105. package/dist/index-etfmqjjf.js +427 -0
  106. package/dist/index-fb29934k.js +172 -0
  107. package/dist/index-g50jw1yf.js +72 -0
  108. package/dist/index-g6eb5wdw.js +118 -117
  109. package/dist/index-ggq3yryx.js +99 -95
  110. package/dist/index-h70tce00.js +177 -0
  111. package/dist/index-hkxtfqtc.js +333 -0
  112. package/dist/index-k370bech.js +72 -0
  113. package/dist/index-kf3dhser.js +146 -143
  114. package/dist/index-ma6tgdb2.js +500 -0
  115. package/dist/index-mam0bcyz.js +123 -0
  116. package/dist/index-mm412dkp.js +274 -0
  117. package/dist/index-n8v18aeb.js +0 -0
  118. package/dist/index-ndnmnsej.js +378 -371
  119. package/dist/index-p8wty0e2.js +389 -379
  120. package/dist/index-qa8akv6y.js +666 -0
  121. package/dist/index-qfphr2fd.js +78 -76
  122. package/dist/index-qqmms8rs.js +51 -43
  123. package/dist/index-qw4093g2.js +51 -43
  124. package/dist/index-qzwpzjbx.js +121 -122
  125. package/dist/index-segbnm0h.js +146 -143
  126. package/dist/index-t0fj6gg1.js +112 -0
  127. package/dist/index-thdkwnv7.js +122 -0
  128. package/dist/index-tjbx2r2t.js +270 -0
  129. package/dist/index-tjqw9vtj.js +62 -54
  130. package/dist/index-vbpb89jy.js +248 -0
  131. package/dist/index-vg55rq0y.js +250 -0
  132. package/dist/index-vhs88xhe.js +99 -95
  133. package/dist/index-vs81yaks.js +244 -0
  134. package/dist/index-w8zxnjka.js +249 -0
  135. package/dist/index-wk2na3t9.js +385 -375
  136. package/dist/index-wz9x8g7z.js +383 -373
  137. package/dist/index-x249gyde.js +388 -378
  138. package/dist/index-x54nbgs7.js +355 -0
  139. package/dist/index-xkvd0nsd.js +187 -0
  140. package/dist/index-yedqxm1z.js +80 -0
  141. package/dist/index-yz4jfz7z.js +338 -0
  142. package/dist/index-zfjzzjkf.js +240 -199
  143. package/dist/index.d.ts +12 -8
  144. package/dist/index.js +56 -34
  145. package/dist/lint.d.ts +1 -46
  146. package/dist/lint.js +3 -7
  147. package/dist/loader/cache.d.ts +4 -0
  148. package/dist/loader/find-config-file.d.ts +2 -0
  149. package/dist/loader/index.d.ts +5 -0
  150. package/dist/loader/index.js +24 -0
  151. package/dist/loader/load-dev-env.d.ts +5 -0
  152. package/dist/loader/loader.d.ts +1 -0
  153. package/dist/loader.d.ts +1 -45
  154. package/dist/loader.js +22 -20
  155. package/dist/prisma/index.d.ts +1 -0
  156. package/dist/prisma/prisma.d.ts +29 -0
  157. package/dist/prisma.d.ts +1 -29
  158. package/dist/prisma.js +6 -10
  159. package/dist/src/bin.js +309 -0
  160. package/dist/src/cli.js +5 -0
  161. package/dist/src/config.js +15 -0
  162. package/dist/src/core/docker.js +38 -0
  163. package/dist/src/core/index.js +130 -0
  164. package/dist/src/core/network.js +9 -0
  165. package/dist/src/core/ports.js +23 -0
  166. package/dist/src/core/process.js +31 -0
  167. package/dist/src/core/utils.js +11 -0
  168. package/dist/src/core/watchdog-runner.js +69 -0
  169. package/dist/src/core/watchdog.js +28 -0
  170. package/dist/src/docker/runtime.js +37 -0
  171. package/dist/src/docker-compose/index.js +16 -0
  172. package/dist/src/docker-compose/services/index.js +17 -0
  173. package/dist/src/environment.js +12 -0
  174. package/dist/src/index.js +122 -0
  175. package/dist/src/lint.js +3 -0
  176. package/dist/src/loader.js +25 -0
  177. package/dist/src/prisma.js +6 -0
  178. package/dist/src/types.js +0 -0
  179. package/dist/typecheck/index.d.ts +1 -0
  180. package/dist/typecheck/index.js +7 -0
  181. package/dist/typecheck/typecheck.d.ts +46 -0
  182. package/dist/types/all-types.d.ts +544 -0
  183. package/dist/types/cli.d.ts +1 -0
  184. package/dist/types/config.d.ts +6 -0
  185. package/dist/types/docker.d.ts +15 -0
  186. package/dist/types/environment.d.ts +8 -0
  187. package/dist/types/hooks.d.ts +9 -0
  188. package/dist/types/index.d.ts +1 -0
  189. package/dist/types/index.js +0 -0
  190. package/dist/types/prisma.d.ts +1 -0
  191. package/dist/types.d.ts +1 -399
  192. package/package.json +55 -48
  193. package/readme.md +365 -109
  194. package/src/cli/bin.ts +77 -0
  195. package/src/cli/commands/help.ts +39 -0
  196. package/src/cli/commands/runtime.ts +72 -0
  197. package/src/cli/commands/version.ts +4 -0
  198. package/src/cli/index.ts +1 -0
  199. package/{cli.ts → src/cli/run-cli.ts} +114 -10
  200. package/src/config/define-config.ts +30 -0
  201. package/src/config/index.ts +3 -0
  202. package/src/config/merge-configs.ts +33 -0
  203. package/src/config/validate-config.ts +136 -0
  204. package/{core → src/core}/index.ts +2 -2
  205. package/{core → src/core}/ports.ts +5 -2
  206. package/{core → src/core}/process.ts +6 -2
  207. package/src/core/quick-tunnel/cloudflared-process.ts +83 -0
  208. package/src/core/quick-tunnel/constants.ts +31 -0
  209. package/src/core/quick-tunnel/index.ts +96 -0
  210. package/src/core/quick-tunnel/install.ts +160 -0
  211. package/src/core/tunnel.ts +165 -0
  212. package/{core → src/core}/utils.ts +1 -0
  213. package/{core → src/core}/watchdog.ts +5 -1
  214. package/src/docker/index.ts +1 -0
  215. package/{core/docker.ts → src/docker/runtime.ts} +11 -4
  216. package/src/docker-compose/generated-file.ts +45 -0
  217. package/src/docker-compose/index.ts +7 -0
  218. package/src/docker-compose/model.ts +197 -0
  219. package/src/docker-compose/services/clickhouse.ts +79 -0
  220. package/src/docker-compose/services/define-docker-service.ts +109 -0
  221. package/src/docker-compose/services/index.ts +67 -0
  222. package/src/docker-compose/services/postgres.ts +60 -0
  223. package/src/docker-compose/services/redis.ts +48 -0
  224. package/src/docker-compose/services/shared.ts +79 -0
  225. package/src/docker-compose/yaml.ts +88 -0
  226. package/{environment.ts → src/environment/create-dev-environment.ts} +214 -141
  227. package/src/environment/index.ts +1 -0
  228. package/src/environment/logging.ts +115 -0
  229. package/src/environment/only-apps.ts +34 -0
  230. package/src/environment/seeding.ts +57 -0
  231. package/{index.ts → src/index.ts} +52 -20
  232. package/src/loader/cache.ts +23 -0
  233. package/src/loader/find-config-file.ts +29 -0
  234. package/src/loader/index.ts +17 -0
  235. package/src/loader/load-dev-env.ts +38 -0
  236. package/src/prisma/index.ts +1 -0
  237. package/{prisma.ts → src/prisma/prisma.ts} +4 -2
  238. package/src/typecheck/index.ts +1 -0
  239. package/{types.ts → src/types/all-types.ts} +186 -8
  240. package/src/types/index.ts +1 -0
  241. package/bin.ts +0 -192
  242. package/config.ts +0 -194
  243. package/loader.ts +0 -126
  244. /package/{core → src/core}/network.ts +0 -0
  245. /package/{core → src/core}/watchdog-runner.ts +0 -0
  246. /package/{lint.ts → src/typecheck/typecheck.ts} +0 -0
@@ -27,12 +27,106 @@ export interface UrlBuilderContext {
27
27
  */
28
28
  export type UrlBuilderFn = (ctx: UrlBuilderContext) => string;
29
29
 
30
+ // ═══════════════════════════════════════════════════════════════════════════
31
+ // Docker Compose Configuration
32
+ // ═══════════════════════════════════════════════════════════════════════════
33
+
34
+ /**
35
+ * Recursive YAML-safe value used for Docker Compose objects.
36
+ */
37
+ export type DockerComposeNode =
38
+ | string
39
+ | number
40
+ | boolean
41
+ | null
42
+ | DockerComposeNode[]
43
+ | { [key: string]: DockerComposeNode | undefined };
44
+
45
+ /**
46
+ * Built-in Docker service presets.
47
+ */
48
+ export type DockerPresetName = "postgres" | "redis" | "clickhouse";
49
+
50
+ /**
51
+ * Docker Compose healthcheck object.
52
+ */
53
+ export interface DockerComposeHealthcheckRaw {
54
+ test?: string[] | string;
55
+ interval?: string;
56
+ timeout?: string;
57
+ retries?: number;
58
+ start_period?: string;
59
+ disable?: boolean;
60
+ [composeKey: string]: DockerComposeNode | undefined;
61
+ }
62
+
63
+ /**
64
+ * Docker Compose service (raw escape hatch).
65
+ * Includes common fields plus index signature for advanced keys.
66
+ */
67
+ export interface DockerComposeServiceRaw {
68
+ image?: string;
69
+ container_name?: string;
70
+ ports?: string[];
71
+ volumes?: string[];
72
+ environment?: Record<string, string | number | boolean>;
73
+ command?: string | string[];
74
+ entrypoint?: string | string[];
75
+ depends_on?: string[] | Record<string, DockerComposeNode>;
76
+ healthcheck?: DockerComposeHealthcheckRaw;
77
+ ulimits?: Record<string, number | { soft: number; hard: number }>;
78
+ restart?: string;
79
+ working_dir?: string;
80
+ [composeKey: string]: DockerComposeNode | undefined;
81
+ }
82
+
83
+ /**
84
+ * Docker Compose volume object.
85
+ */
86
+ export interface DockerComposeVolumeRaw {
87
+ driver?: string;
88
+ driver_opts?: Record<string, string | number | boolean>;
89
+ [composeKey: string]: DockerComposeNode | undefined;
90
+ }
91
+
92
+ /**
93
+ * Helper-friendly preset service definition.
94
+ */
95
+ export interface DockerPresetServiceDefinition {
96
+ kind: "preset";
97
+ preset: DockerPresetName;
98
+ service?: DockerComposeServiceRaw;
99
+ }
100
+
101
+ /**
102
+ * Docker service definition accepted by service config.
103
+ * - raw object is the manual escape hatch
104
+ * - helper mode returns `kind`-based definitions
105
+ */
106
+ export type DockerServiceDefinition =
107
+ | DockerComposeServiceRaw
108
+ | DockerPresetServiceDefinition;
109
+
110
+ /**
111
+ * Docker Compose generation configuration.
112
+ */
113
+ export interface DockerComposeGenerationOptions {
114
+ /** Path to generated compose file relative to root. Default: '.buncargo/docker-compose.generated.yml' */
115
+ generatedFile?: string;
116
+ /** Write strategy for generated compose file. Default: 'always' */
117
+ writeStrategy?: "always" | "if-missing";
118
+ /** Extra top-level named volumes */
119
+ volumes?: Record<string, DockerComposeVolumeRaw>;
120
+ }
121
+
30
122
  /**
31
123
  * Configuration for a Docker Compose service (e.g., postgres, redis).
32
124
  */
33
125
  export interface ServiceConfig {
34
126
  /** Base port for the service (before offset is applied) */
35
127
  port: number;
128
+ /** Whether this service can be exposed publicly via tunnel */
129
+ expose?: boolean;
36
130
  /** Optional secondary port (e.g., ClickHouse native protocol) */
37
131
  secondaryPort?: number;
38
132
  /** Health check: built-in name, custom function, or disabled (false) */
@@ -53,6 +147,8 @@ export interface ServiceConfig {
53
147
  user?: string;
54
148
  /** Password (default: 'postgres' for postgres, 'root' for mysql, 'clickhouse' for clickhouse) */
55
149
  password?: string;
150
+ /** Docker Compose service definition (preset helper or raw escape hatch) */
151
+ docker?: DockerServiceDefinition;
56
152
  }
57
153
 
58
154
  // ═══════════════════════════════════════════════════════════════════════════
@@ -65,6 +161,8 @@ export interface ServiceConfig {
65
161
  export interface AppConfig {
66
162
  /** Base port for the app (before offset is applied) */
67
163
  port: number;
164
+ /** Whether this app can be exposed publicly via tunnel */
165
+ expose?: boolean;
68
166
  /** Command to start the dev server */
69
167
  devCommand: string;
70
168
  /** Command to start production server (optional) */
@@ -110,6 +208,8 @@ export interface HookContext<
110
208
  ports: ComputedPorts<TServices, TApps>;
111
209
  /** Computed URLs for all services and apps */
112
210
  urls: ComputedUrls<TServices, TApps>;
211
+ /** Public tunnel URLs for exposed services/apps (when active) */
212
+ publicUrls: ComputedPublicUrls<TServices, TApps>;
113
213
  /** Execute a shell command with environment variables set */
114
214
  exec: (
115
215
  cmd: string,
@@ -269,8 +369,6 @@ export interface DevOptions {
269
369
  worktreeIsolation?: boolean;
270
370
  /** Auto-shutdown after idle time in ms. Set to false to disable. Default: false */
271
371
  autoShutdown?: number | false;
272
- /** Path to docker-compose.yml relative to root. Default: 'docker-compose.yml' */
273
- composeFile?: string;
274
372
  /** Default verbose setting for all operations. Default: true */
275
373
  verbose?: boolean;
276
374
  }
@@ -284,7 +382,12 @@ export type EnvVarsBuilder<
284
382
  > = (
285
383
  ports: ComputedPorts<TServices, TApps>,
286
384
  urls: ComputedUrls<TServices, TApps>,
287
- ctx: { projectName: string; localIp: string; portOffset: number },
385
+ ctx: {
386
+ projectName: string;
387
+ localIp: string;
388
+ portOffset: number;
389
+ publicUrls: ComputedPublicUrls<TServices, TApps>;
390
+ },
288
391
  ) => Record<string, string | number>;
289
392
 
290
393
  /**
@@ -308,11 +411,12 @@ export interface DevConfig<
308
411
  *
309
412
  * @example
310
413
  * ```typescript
311
- * envVars: (ports, urls, { localIp }) => ({
414
+ * envVars: (ports, urls, { localIp, publicUrls }) => ({
312
415
  * DATABASE_URL: urls.postgres,
313
416
  * BASE_URL: urls.api,
314
417
  * VITE_PORT: ports.platform,
315
- * EXPO_API_URL: `http://${localIp}:${ports.api}`
418
+ * EXPO_API_URL: `http://${localIp}:${ports.api}`,
419
+ * WEBHOOK_URL: publicUrls.api
316
420
  * })
317
421
  * ```
318
422
  */
@@ -327,6 +431,8 @@ export interface DevConfig<
327
431
  prisma?: PrismaConfig;
328
432
  /** Additional options (optional) */
329
433
  options?: DevOptions;
434
+ /** Docker Compose generation options (optional) */
435
+ docker?: DockerComposeGenerationOptions;
330
436
  }
331
437
 
332
438
  // ═══════════════════════════════════════════════════════════════════════════
@@ -366,6 +472,13 @@ export type ComputedUrls<
366
472
  [K in keyof TApps]: string;
367
473
  };
368
474
 
475
+ export type ComputedPublicUrls<
476
+ TServices extends Record<string, ServiceConfig>,
477
+ TApps extends Record<string, AppConfig>,
478
+ > = Partial<{
479
+ [K in keyof TServices | keyof TApps]: string;
480
+ }>;
481
+
369
482
  // ═══════════════════════════════════════════════════════════════════════════
370
483
  // Start/Stop Options
371
484
  // ═══════════════════════════════════════════════════════════════════════════
@@ -386,6 +499,10 @@ export interface StartOptions {
386
499
  suffix?: string;
387
500
  /** Skip automatic seeding (useful when CLI handles seeding separately). Default: false */
388
501
  skipSeed?: boolean;
502
+ /** Skip the initial `logInfo` banner (CLI uses this with `--expose`, then logs once with tunnel URLs). Default: false */
503
+ skipEnvironmentLog?: boolean;
504
+ /** If set, start and wait for only these app names (must exist in `apps`). */
505
+ onlyApps?: string[];
389
506
  }
390
507
 
391
508
  /**
@@ -409,6 +526,40 @@ export interface DevServerPids {
409
526
  [appName: string]: number;
410
527
  }
411
528
 
529
+ /** Tunnel rows passed to `logInfo` for public URL lines (matches `PublicTunnel` without `close`) */
530
+ export interface DevEnvironmentTunnelLog {
531
+ kind: "service" | "app";
532
+ name: string;
533
+ localUrl: string;
534
+ publicUrl: string;
535
+ }
536
+
537
+ /** Active tunnel with teardown — same shape as core `PublicTunnel`. */
538
+ export type PublicTunnelHandle = DevEnvironmentTunnelLog & {
539
+ close: () => Promise<void>;
540
+ };
541
+
542
+ /** Options for {@link DevEnvironment.openPublicTunnels}. */
543
+ export interface OpenPublicTunnelsOptions {
544
+ /** Subset of expose targets by name; omit for all `expose: true` services/apps. */
545
+ names?: string[];
546
+ /**
547
+ * Wait for these apps' HTTP health endpoints before opening tunnels.
548
+ * Servers must already be listening on their ports.
549
+ */
550
+ waitForHealthy?: string[];
551
+ }
552
+
553
+ /** Result of {@link DevEnvironment.openPublicTunnels}. */
554
+ export interface OpenPublicTunnelsResult<
555
+ TServices extends Record<string, ServiceConfig>,
556
+ TApps extends Record<string, AppConfig>,
557
+ > {
558
+ publicUrls: ComputedPublicUrls<TServices, TApps>;
559
+ tunnels: PublicTunnelHandle[];
560
+ close: () => Promise<void>;
561
+ }
562
+
412
563
  /**
413
564
  * The main dev environment interface returned by createDevEnvironment().
414
565
  */
@@ -426,6 +577,10 @@ export interface DevEnvironment<
426
577
  readonly ports: ComputedPorts<TServices, TApps>;
427
578
  /** Computed URLs for all services and apps */
428
579
  readonly urls: ComputedUrls<TServices, TApps>;
580
+ /** Public tunnel URLs for exposed services/apps (when active) */
581
+ readonly publicUrls: ComputedPublicUrls<TServices, TApps>;
582
+ /** Services configuration */
583
+ readonly services: TServices;
429
584
  /** Apps configuration (for CLI to build commands) */
430
585
  readonly apps: TApps;
431
586
  /** Port offset applied (0 for main, > 0 for worktrees) */
@@ -436,6 +591,8 @@ export interface DevEnvironment<
436
591
  readonly localIp: string;
437
592
  /** Path to monorepo root */
438
593
  readonly root: string;
594
+ /** Path passed to docker compose -f */
595
+ readonly composeFile: string;
439
596
 
440
597
  // ─────────────────────────────────────────────────────────────────────────
441
598
  // Container Management
@@ -458,6 +615,8 @@ export interface DevEnvironment<
458
615
  startServers(options?: {
459
616
  productionBuild?: boolean;
460
617
  verbose?: boolean;
618
+ /** If set, start and wait for only these app names (must exist in `apps`). */
619
+ onlyApps?: string[];
461
620
  }): Promise<DevServerPids>;
462
621
  /** Stop a process by PID */
463
622
  stopProcess(pid: number): void;
@@ -465,14 +624,25 @@ export interface DevEnvironment<
465
624
  waitForServers(options?: {
466
625
  timeout?: number;
467
626
  productionBuild?: boolean;
627
+ /** If set, wait only for these app names (must exist in `apps`). */
628
+ onlyApps?: string[];
468
629
  }): Promise<void>;
469
630
 
470
631
  // ─────────────────────────────────────────────────────────────────────────
471
632
  // Utilities
472
633
  // ─────────────────────────────────────────────────────────────────────────
473
634
 
474
- /** Build environment variables for shell commands */
635
+ /**
636
+ * Build environment variables for shell commands.
637
+ * Call **after** {@link setPublicUrls} or {@link openPublicTunnels} so `envVars` and `*_PUBLIC_URL` reflect tunnel URLs.
638
+ */
475
639
  buildEnvVars(production?: boolean): Record<string, string>;
640
+ /** Set public tunnel URLs used by envVars and *_PUBLIC_URL injection */
641
+ setPublicUrls(urls: ComputedPublicUrls<TServices, TApps>): void;
642
+ /** Clear all public tunnel URLs */
643
+ clearPublicUrls(): void;
644
+ /** Ensure generated docker compose file exists and return path used with -f */
645
+ ensureComposeFile(): string;
476
646
  /** Execute a command with environment variables set */
477
647
  exec(
478
648
  cmd: string,
@@ -480,8 +650,16 @@ export interface DevEnvironment<
480
650
  ): Promise<{ exitCode: number; stdout: string; stderr: string }>;
481
651
  /** Wait for an HTTP server to respond */
482
652
  waitForServer(url: string, timeout?: number): Promise<void>;
483
- /** Log environment info to console */
484
- logInfo(label?: string): void;
653
+ /** Log environment info to console; pass `tunnels` to show public URLs next to services/apps */
654
+ logInfo(label?: string, tunnels?: DevEnvironmentTunnelLog[]): void;
655
+
656
+ /**
657
+ * Resolve expose targets, start public quick tunnels, and apply {@link setPublicUrls}.
658
+ * Call {@link buildEnvVars} after this resolves when spawning processes that need `EXPO_PUBLIC_*` / `*_PUBLIC_URL`.
659
+ */
660
+ openPublicTunnels(
661
+ options?: OpenPublicTunnelsOptions,
662
+ ): Promise<OpenPublicTunnelsResult<TServices, TApps>>;
485
663
 
486
664
  // ─────────────────────────────────────────────────────────────────────────
487
665
  // Vibe Kanban Integration
@@ -0,0 +1 @@
1
+ export * from "./all-types";
package/bin.ts DELETED
@@ -1,192 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- /**
4
- * CLI Entry Point for buncargo
5
- *
6
- * Usage:
7
- * bunx buncargo dev # Start containers + dev servers
8
- * bunx buncargo dev --down # Stop containers
9
- * bunx buncargo dev --reset # Stop + remove volumes
10
- * bunx buncargo typecheck # Run TypeScript typecheck
11
- * bunx buncargo prisma ... # Run prisma commands
12
- * bunx buncargo help # Show help
13
- */
14
-
15
- import { runCli } from "./cli";
16
- import { loadDevEnv } from "./loader";
17
-
18
- /**
19
- * Load the dev environment with CLI-friendly error output.
20
- */
21
- async function loadEnv() {
22
- try {
23
- return await loadDevEnv();
24
- } catch (error) {
25
- console.error(`❌ ${error instanceof Error ? error.message : error}`);
26
- process.exit(1);
27
- }
28
- }
29
-
30
- // ═══════════════════════════════════════════════════════════════════════════
31
- // Command Handlers
32
- // ═══════════════════════════════════════════════════════════════════════════
33
-
34
- async function handleDev(args: string[]): Promise<void> {
35
- const env = await loadEnv();
36
- await runCli(env, { args });
37
- }
38
-
39
- async function handlePrisma(args: string[]): Promise<void> {
40
- const env = await loadEnv();
41
-
42
- if (!env.prisma) {
43
- console.error("❌ Prisma is not configured in your dev config.");
44
- console.error("");
45
- console.error(" Add prisma to your config:");
46
- console.error("");
47
- console.error(" export default defineDevConfig({");
48
- console.error(" ...");
49
- console.error(" prisma: {");
50
- console.error(" cwd: 'packages/prisma'");
51
- console.error(" }");
52
- console.error(" })");
53
- process.exit(1);
54
- }
55
-
56
- // Ensure database is running
57
- const running = await env.isRunning();
58
- if (!running) {
59
- console.log("🐳 Starting database container...");
60
- await env.start({ startServers: false, wait: true });
61
- }
62
-
63
- const exitCode = await env.prisma.run(args);
64
- process.exit(exitCode);
65
- }
66
-
67
- async function handleEnv(): Promise<void> {
68
- const env = await loadEnv();
69
- console.log(
70
- JSON.stringify(
71
- {
72
- projectName: env.projectName,
73
- ports: env.ports,
74
- urls: env.urls,
75
- portOffset: env.portOffset,
76
- isWorktree: env.isWorktree,
77
- localIp: env.localIp,
78
- root: env.root,
79
- },
80
- null,
81
- 2,
82
- ),
83
- );
84
- }
85
-
86
- async function handleTypecheck(): Promise<void> {
87
- const env = await loadEnv();
88
- const { runWorkspaceTypecheck } = await import("./lint");
89
- const result = await runWorkspaceTypecheck({
90
- root: env.root,
91
- verbose: true,
92
- });
93
- process.exit(result.success ? 0 : 1);
94
- }
95
-
96
- function showHelp(): void {
97
- console.log(`
98
- buncargo - Development environment CLI
99
-
100
- USAGE:
101
- bunx buncargo <command> [options]
102
-
103
- COMMANDS:
104
- dev Start the development environment
105
- typecheck Run TypeScript typecheck across workspaces
106
- prisma <args> Run Prisma CLI with correct DATABASE_URL
107
- env Print environment info as JSON
108
- help Show this help message
109
- version Show version
110
-
111
- EXAMPLES:
112
- bunx buncargo dev # Start everything
113
- bunx buncargo dev --help # Show dev command options
114
- bunx buncargo dev --down # Stop containers
115
- bunx buncargo typecheck # Run typecheck
116
- bunx buncargo prisma studio # Open Prisma Studio
117
- bunx buncargo env # Get ports/urls as JSON
118
-
119
- CONFIG:
120
- Create a dev.config.ts with a default export:
121
-
122
- import { defineDevConfig } from 'buncargo'
123
-
124
- export default defineDevConfig({
125
- projectPrefix: 'myapp',
126
- services: { ... },
127
- apps: { ... }
128
- })
129
-
130
- Run "bunx buncargo dev --help" for dev command options.
131
- `);
132
- }
133
-
134
- function showVersion(): void {
135
- const pkg = require("./package.json");
136
- console.log(`buncargo v${pkg.version}`);
137
- }
138
-
139
- // ═══════════════════════════════════════════════════════════════════════════
140
- // Main
141
- // ═══════════════════════════════════════════════════════════════════════════
142
-
143
- async function main(): Promise<void> {
144
- const args = process.argv.slice(2);
145
- const command = args[0];
146
- const commandArgs = args.slice(1);
147
-
148
- if (
149
- !command ||
150
- command === "help" ||
151
- command === "--help" ||
152
- command === "-h"
153
- ) {
154
- showHelp();
155
- process.exit(0);
156
- }
157
-
158
- if (command === "version" || command === "--version" || command === "-v") {
159
- showVersion();
160
- process.exit(0);
161
- }
162
-
163
- switch (command) {
164
- case "dev":
165
- await handleDev(commandArgs);
166
- break;
167
-
168
- case "typecheck":
169
- await handleTypecheck();
170
- break;
171
-
172
- case "prisma":
173
- await handlePrisma(commandArgs);
174
- break;
175
-
176
- case "env":
177
- await handleEnv();
178
- break;
179
-
180
- default:
181
- console.error(`❌ Unknown command: ${command}`);
182
- console.error("");
183
- console.error(' Run "bunx buncargo help" for available commands.');
184
- process.exit(1);
185
- }
186
- }
187
-
188
- main().catch((error) => {
189
- const message = error instanceof Error ? error.message : String(error);
190
- console.error(`❌ ${message}`);
191
- process.exit(1);
192
- });
package/config.ts DELETED
@@ -1,194 +0,0 @@
1
- import type {
2
- AppConfig,
3
- DevConfig,
4
- DevHooks,
5
- DevOptions,
6
- EnvVarsBuilder,
7
- MigrationConfig,
8
- PrismaConfig,
9
- SeedConfig,
10
- ServiceConfig,
11
- } from "./types";
12
-
13
- // ═══════════════════════════════════════════════════════════════════════════
14
- // Config Factory
15
- // ═══════════════════════════════════════════════════════════════════════════
16
-
17
- /**
18
- * Define a dev environment configuration with full TypeScript inference.
19
- *
20
- * @example
21
- * ```typescript
22
- * const config = defineDevConfig({
23
- * projectPrefix: 'myapp',
24
- * services: {
25
- * postgres: { port: 5432, healthCheck: 'pg_isready' },
26
- * redis: { port: 6379 },
27
- * },
28
- * apps: {
29
- * api: { port: 3000, devCommand: 'bun run dev', cwd: 'apps/backend' },
30
- * web: { port: 5173, devCommand: 'bun run dev', cwd: 'apps/frontend' },
31
- * },
32
- * envVars: (ports, urls) => ({
33
- * DATABASE_URL: urls.postgres,
34
- * REDIS_URL: urls.redis,
35
- * API_PORT: String(ports.api),
36
- * }),
37
- * })
38
- * ```
39
- */
40
- export function defineDevConfig<
41
- TServices extends Record<string, ServiceConfig>,
42
- TApps extends Record<string, AppConfig> = Record<string, never>,
43
- >(config: {
44
- /** Prefix for Docker project name (e.g., 'myapp' -> 'myapp-main') */
45
- projectPrefix: string;
46
- /** Docker Compose services to manage */
47
- services: TServices;
48
- /** Applications to start (optional) */
49
- apps?: TApps;
50
- /**
51
- * Environment variables builder. Define all env vars here.
52
- *
53
- * @example
54
- * ```typescript
55
- * envVars: (ports, urls, { localIp }) => ({
56
- * DATABASE_URL: urls.postgres,
57
- * BASE_URL: urls.api,
58
- * VITE_PORT: ports.platform,
59
- * EXPO_API_URL: `http://${localIp}:${ports.api}`
60
- * })
61
- * ```
62
- */
63
- envVars?: EnvVarsBuilder<TServices, TApps>;
64
- /** Lifecycle hooks (optional) */
65
- hooks?: DevHooks<TServices, TApps>;
66
- /** Migrations to run after containers are ready (optional). Runs in parallel. */
67
- migrations?: MigrationConfig[];
68
- /** Seed configuration (optional). Runs after migrations, before servers. */
69
- seed?: SeedConfig<TServices, TApps>;
70
- /** Prisma configuration (optional). When set, dev.prisma is available. */
71
- prisma?: PrismaConfig;
72
- /** Additional options (optional) */
73
- options?: DevOptions;
74
- }): DevConfig<TServices, TApps> {
75
- return config as DevConfig<TServices, TApps>;
76
- }
77
-
78
- // ═══════════════════════════════════════════════════════════════════════════
79
- // Config Validation
80
- // ═══════════════════════════════════════════════════════════════════════════
81
-
82
- /**
83
- * Validate a dev config and return any errors.
84
- */
85
- export function validateConfig<
86
- TServices extends Record<string, ServiceConfig>,
87
- TApps extends Record<string, AppConfig>,
88
- >(config: DevConfig<TServices, TApps>): string[] {
89
- const errors: string[] = [];
90
-
91
- // Check project prefix
92
- if (!config.projectPrefix) {
93
- errors.push("projectPrefix is required");
94
- } else if (!/^[a-z][a-z0-9-]*$/.test(config.projectPrefix)) {
95
- errors.push(
96
- "projectPrefix must start with a letter and contain only lowercase letters, numbers, and hyphens",
97
- );
98
- }
99
-
100
- // Check services
101
- if (!config.services || Object.keys(config.services).length === 0) {
102
- errors.push("At least one service is required");
103
- }
104
-
105
- for (const [name, service] of Object.entries(config.services ?? {})) {
106
- if (!service.port || typeof service.port !== "number") {
107
- errors.push(`Service "${name}" must have a valid port number`);
108
- }
109
- if (service.port < 1 || service.port > 65535) {
110
- errors.push(`Service "${name}" port must be between 1 and 65535`);
111
- }
112
- }
113
-
114
- // Check apps
115
- for (const [name, app] of Object.entries(config.apps ?? {})) {
116
- if (!app.port || typeof app.port !== "number") {
117
- errors.push(`App "${name}" must have a valid port number`);
118
- }
119
- if (!app.devCommand) {
120
- errors.push(`App "${name}" must have a devCommand`);
121
- }
122
- }
123
-
124
- // Check migrations
125
- for (const migration of config.migrations ?? []) {
126
- if (!migration.name) {
127
- errors.push("Migration must have a name");
128
- }
129
- if (!migration.command) {
130
- errors.push(`Migration "${migration.name}" must have a command`);
131
- }
132
- }
133
-
134
- // Check seed
135
- if (config.seed && !config.seed.command) {
136
- errors.push("Seed must have a command");
137
- }
138
-
139
- return errors;
140
- }
141
-
142
- /**
143
- * Validate config and throw if invalid.
144
- */
145
- export function assertValidConfig<
146
- TServices extends Record<string, ServiceConfig>,
147
- TApps extends Record<string, AppConfig>,
148
- >(config: DevConfig<TServices, TApps>): void {
149
- const errors = validateConfig(config);
150
- if (errors.length > 0) {
151
- throw new Error(`Invalid dev config:\n - ${errors.join("\n - ")}`);
152
- }
153
- }
154
-
155
- // ═══════════════════════════════════════════════════════════════════════════
156
- // Config Helpers
157
- // ═══════════════════════════════════════════════════════════════════════════
158
-
159
- /**
160
- * Merge two configs, with the second taking precedence.
161
- */
162
- export function mergeConfigs<
163
- TServices extends Record<string, ServiceConfig>,
164
- TApps extends Record<string, AppConfig>,
165
- >(
166
- base: DevConfig<TServices, TApps>,
167
- overrides: Partial<DevConfig<TServices, TApps>>,
168
- ): DevConfig<TServices, TApps> {
169
- return {
170
- ...base,
171
- ...overrides,
172
- services: { ...base.services, ...overrides.services } as TServices,
173
- apps: { ...base.apps, ...overrides.apps } as TApps,
174
- hooks: { ...base.hooks, ...overrides.hooks },
175
- migrations: overrides.migrations ?? base.migrations,
176
- seed: overrides.seed ?? base.seed,
177
- options: { ...base.options, ...overrides.options },
178
- };
179
- }
180
-
181
- /**
182
- * Create a partial config that can be merged later.
183
- */
184
- export function definePartialConfig<
185
- TServices extends Record<string, ServiceConfig> = Record<
186
- string,
187
- ServiceConfig
188
- >,
189
- TApps extends Record<string, AppConfig> = Record<string, AppConfig>,
190
- >(
191
- config: Partial<DevConfig<TServices, TApps>>,
192
- ): Partial<DevConfig<TServices, TApps>> {
193
- return config;
194
- }