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.
- package/dist/bin.d.ts +1 -12
- package/dist/bin.js +261 -253
- package/dist/cli/bin.d.ts +13 -0
- package/dist/cli/bin.js +315 -0
- package/dist/cli/commands/help.d.ts +1 -0
- package/dist/cli/commands/runtime.d.ts +5 -0
- package/dist/cli/commands/version.d.ts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/run-cli.d.ts +22 -0
- package/dist/cli.d.ts +1 -22
- package/dist/cli.js +5 -13
- package/dist/config/config.d.ts +1 -0
- package/dist/config/define-config.d.ts +13 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +15 -0
- package/dist/config/merge-configs.d.ts +3 -0
- package/dist/config/validate-config.d.ts +3 -0
- package/dist/config.d.ts +1 -72
- package/dist/config.js +12 -12
- package/dist/core/docker.d.ts +1 -83
- package/dist/core/docker.js +35 -32
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +123 -118
- package/dist/core/network.js +2 -2
- package/dist/core/ports.js +1 -1
- package/dist/core/process.js +1 -1
- package/dist/core/tunnel.d.ts +33 -0
- package/dist/core/utils.js +2 -2
- package/dist/core/watchdog-runner.js +45 -42
- package/dist/core/watchdog.d.ts +1 -0
- package/dist/core/watchdog.js +4 -2
- package/dist/docker/index.d.ts +1 -0
- package/dist/docker/index.js +38 -0
- package/dist/docker/runtime.d.ts +87 -0
- package/dist/docker/runtime.js +37 -0
- package/dist/docker-compose/compose.d.ts +1 -0
- package/dist/docker-compose/generated-file.d.ts +7 -0
- package/dist/docker-compose/index.d.ts +3 -0
- package/dist/docker-compose/index.js +15 -0
- package/dist/docker-compose/model.d.ts +6 -0
- package/dist/docker-compose/services/clickhouse.d.ts +16 -0
- package/dist/docker-compose/services/define-docker-service.d.ts +41 -0
- package/dist/docker-compose/services/index.d.ts +23 -0
- package/dist/docker-compose/services/index.js +17 -0
- package/dist/docker-compose/services/postgres.d.ts +12 -0
- package/dist/docker-compose/services/redis.d.ts +12 -0
- package/dist/docker-compose/services/shared.d.ts +7 -0
- package/dist/docker-compose/yaml.d.ts +2 -0
- package/dist/environment/create-dev-environment.d.ts +23 -0
- package/dist/environment/index.d.ts +1 -0
- package/dist/environment/index.js +15 -0
- package/dist/environment/logging.d.ts +17 -0
- package/dist/environment/seeding.d.ts +9 -0
- package/dist/environment.d.ts +1 -23
- package/dist/environment.js +12 -14
- package/dist/index-045jksh5.js +147 -0
- package/dist/index-08wa79cs.js +125 -117
- package/dist/index-0kxnae3z.js +335 -0
- package/dist/index-1mdrf7nz.js +51 -43
- package/dist/index-1yvbwj4k.js +262 -242
- package/dist/index-23ev345g.js +475 -0
- package/dist/index-2ckr49sf.js +228 -0
- package/dist/index-2f47khe5.js +376 -369
- package/dist/index-2fr3g85b.js +220 -183
- package/dist/index-38xnzpa6.js +450 -0
- package/dist/index-3h3dhtf2.js +51 -43
- package/dist/index-42x95209.js +51 -43
- package/dist/index-4gp0az1g.js +145 -0
- package/dist/index-4xrxh8yv.js +72 -0
- package/dist/index-5gmws6ah.js +181 -0
- package/dist/index-5hka0tff.js +78 -76
- package/dist/index-5rfqps4b.js +3 -0
- package/dist/index-5t9jxqm0.js +428 -0
- package/dist/index-6c1w1xk5.js +101 -0
- package/dist/index-6fm7mvwj.js +118 -97
- package/dist/index-6srpc523.js +127 -128
- package/dist/index-731rzzfp.js +157 -142
- package/dist/index-75y4cg2z.js +51 -43
- package/dist/index-7ja4ywyj.js +126 -127
- package/dist/index-8bw1cmz4.js +531 -0
- package/dist/index-8hbbj1mp.js +120 -121
- package/dist/index-8xj2p5n5.js +118 -97
- package/dist/index-bj79tw5w.js +0 -0
- package/dist/index-bnk6nr0g.js +73 -0
- package/dist/index-brbbzyks.js +72 -0
- package/dist/index-c0dr6mcv.js +123 -0
- package/dist/index-cty0bcry.js +235 -218
- package/dist/index-d8tyv5se.js +228 -0
- package/dist/index-d9efy0n4.js +176 -150
- package/dist/index-etfmqjjf.js +427 -0
- package/dist/index-fb29934k.js +172 -0
- package/dist/index-g50jw1yf.js +72 -0
- package/dist/index-g6eb5wdw.js +118 -117
- package/dist/index-ggq3yryx.js +99 -95
- package/dist/index-h70tce00.js +177 -0
- package/dist/index-hkxtfqtc.js +333 -0
- package/dist/index-kf3dhser.js +146 -143
- package/dist/index-ma6tgdb2.js +500 -0
- package/dist/index-mam0bcyz.js +123 -0
- package/dist/index-mm412dkp.js +274 -0
- package/dist/index-n8v18aeb.js +0 -0
- package/dist/index-ndnmnsej.js +378 -371
- package/dist/index-p8wty0e2.js +389 -379
- package/dist/index-qfphr2fd.js +78 -76
- package/dist/index-qqmms8rs.js +51 -43
- package/dist/index-qw4093g2.js +51 -43
- package/dist/index-qzwpzjbx.js +121 -122
- package/dist/index-segbnm0h.js +146 -143
- package/dist/index-t0fj6gg1.js +112 -0
- package/dist/index-thdkwnv7.js +122 -0
- package/dist/index-tjbx2r2t.js +270 -0
- package/dist/index-tjqw9vtj.js +62 -54
- package/dist/index-vbpb89jy.js +248 -0
- package/dist/index-vhs88xhe.js +99 -95
- package/dist/index-w8zxnjka.js +249 -0
- package/dist/index-wk2na3t9.js +385 -375
- package/dist/index-wz9x8g7z.js +383 -373
- package/dist/index-x249gyde.js +388 -378
- package/dist/index-xkvd0nsd.js +187 -0
- package/dist/index-yedqxm1z.js +80 -0
- package/dist/index-zfjzzjkf.js +240 -199
- package/dist/index.d.ts +12 -8
- package/dist/index.js +56 -35
- package/dist/lint.d.ts +1 -46
- package/dist/lint.js +3 -7
- package/dist/loader/cache.d.ts +4 -0
- package/dist/loader/find-config-file.d.ts +2 -0
- package/dist/loader/index.d.ts +5 -0
- package/dist/loader/index.js +24 -0
- package/dist/loader/load-dev-env.d.ts +5 -0
- package/dist/loader/loader.d.ts +1 -0
- package/dist/loader.d.ts +1 -45
- package/dist/loader.js +22 -20
- package/dist/prisma/index.d.ts +1 -0
- package/dist/prisma/prisma.d.ts +29 -0
- package/dist/prisma.d.ts +1 -29
- package/dist/prisma.js +6 -10
- package/dist/src/bin.js +309 -0
- package/dist/src/cli.js +5 -0
- package/dist/src/config.js +15 -0
- package/dist/src/core/docker.js +38 -0
- package/dist/src/core/index.js +130 -0
- package/dist/src/core/network.js +9 -0
- package/dist/src/core/ports.js +23 -0
- package/dist/src/core/process.js +31 -0
- package/dist/src/core/utils.js +11 -0
- package/dist/src/core/watchdog-runner.js +69 -0
- package/dist/src/core/watchdog.js +28 -0
- package/dist/src/docker/runtime.js +37 -0
- package/dist/src/docker-compose/index.js +16 -0
- package/dist/src/docker-compose/services/index.js +17 -0
- package/dist/src/environment.js +12 -0
- package/dist/src/index.js +122 -0
- package/dist/src/lint.js +3 -0
- package/dist/src/loader.js +25 -0
- package/dist/src/prisma.js +6 -0
- package/dist/src/types.js +0 -0
- package/dist/typecheck/index.d.ts +1 -0
- package/dist/typecheck/index.js +7 -0
- package/dist/typecheck/typecheck.d.ts +46 -0
- package/dist/types/all-types.d.ts +501 -0
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/config.d.ts +6 -0
- package/dist/types/docker.d.ts +15 -0
- package/dist/types/environment.d.ts +8 -0
- package/dist/types/hooks.d.ts +9 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +0 -0
- package/dist/types/prisma.d.ts +1 -0
- package/dist/types.d.ts +1 -399
- package/package.json +145 -140
- package/readme.md +349 -109
- package/src/cli/bin.ts +77 -0
- package/src/cli/commands/help.ts +39 -0
- package/src/cli/commands/runtime.ts +72 -0
- package/src/cli/commands/version.ts +4 -0
- package/src/cli/index.ts +1 -0
- package/{cli.ts → src/cli/run-cli.ts} +95 -6
- package/src/config/define-config.ts +30 -0
- package/src/config/index.ts +3 -0
- package/src/config/merge-configs.ts +33 -0
- package/src/config/validate-config.ts +136 -0
- package/{core → src/core}/index.ts +2 -2
- package/{core → src/core}/ports.ts +5 -2
- package/{core → src/core}/process.ts +6 -2
- package/src/core/tunnel.ts +151 -0
- package/{core → src/core}/utils.ts +1 -0
- package/{core → src/core}/watchdog.ts +5 -1
- package/src/docker/index.ts +1 -0
- package/{core/docker.ts → src/docker/runtime.ts} +11 -4
- package/src/docker-compose/generated-file.ts +45 -0
- package/src/docker-compose/index.ts +7 -0
- package/src/docker-compose/model.ts +197 -0
- package/src/docker-compose/services/clickhouse.ts +79 -0
- package/src/docker-compose/services/define-docker-service.ts +109 -0
- package/src/docker-compose/services/index.ts +67 -0
- package/src/docker-compose/services/postgres.ts +60 -0
- package/src/docker-compose/services/redis.ts +48 -0
- package/src/docker-compose/services/shared.ts +79 -0
- package/src/docker-compose/yaml.ts +88 -0
- package/{environment.ts → src/environment/create-dev-environment.ts} +93 -130
- package/src/environment/index.ts +1 -0
- package/src/environment/logging.ts +101 -0
- package/src/environment/seeding.ts +57 -0
- package/{index.ts → src/index.ts} +49 -20
- package/src/loader/cache.ts +23 -0
- package/src/loader/find-config-file.ts +29 -0
- package/src/loader/index.ts +17 -0
- package/src/loader/load-dev-env.ts +38 -0
- package/src/prisma/index.ts +1 -0
- package/{prisma.ts → src/prisma/prisma.ts} +4 -2
- package/src/typecheck/index.ts +1 -0
- package/{types.ts → src/types/all-types.ts} +130 -5
- package/src/types/index.ts +1 -0
- package/bin.ts +0 -192
- package/config.ts +0 -194
- package/loader.ts +0 -126
- /package/{core → src/core}/network.ts +0 -0
- /package/{core → src/core}/watchdog-runner.ts +0 -0
- /package/{lint.ts → src/typecheck/typecheck.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createDevEnvironment } from "./create-dev-environment";
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
|
|
3
|
+
function formatUrl(url: string): string {
|
|
4
|
+
return pc.cyan(
|
|
5
|
+
url.replace(/:(\d+)(\/?)/, (_, port, slash) => `:${pc.bold(port)}${slash}`),
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function formatLabel(label: string, value: string, arrow = "➜"): string {
|
|
10
|
+
return ` ${pc.green(arrow)} ${pc.bold(label.padEnd(10))} ${value}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function formatDimLabel(label: string, value: string): string {
|
|
14
|
+
return ` ${pc.dim("•")} ${pc.dim(label.padEnd(10))} ${pc.dim(value)}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function logEnvironmentInfo(input: {
|
|
18
|
+
label: string;
|
|
19
|
+
projectName: string;
|
|
20
|
+
services: Record<string, unknown>;
|
|
21
|
+
apps: Record<string, unknown>;
|
|
22
|
+
ports: Record<string, number>;
|
|
23
|
+
localIp: string;
|
|
24
|
+
worktree: boolean;
|
|
25
|
+
portOffset: number;
|
|
26
|
+
projectSuffix?: string;
|
|
27
|
+
}): void {
|
|
28
|
+
const {
|
|
29
|
+
label,
|
|
30
|
+
projectName,
|
|
31
|
+
services,
|
|
32
|
+
apps,
|
|
33
|
+
ports,
|
|
34
|
+
localIp,
|
|
35
|
+
worktree,
|
|
36
|
+
portOffset,
|
|
37
|
+
projectSuffix,
|
|
38
|
+
} = input;
|
|
39
|
+
const serviceNames = Object.keys(services);
|
|
40
|
+
const appNames = Object.keys(apps);
|
|
41
|
+
|
|
42
|
+
console.log("");
|
|
43
|
+
console.log(` ${pc.cyan(pc.bold(`🐳 ${label}`))}`);
|
|
44
|
+
console.log(formatLabel("Project:", pc.white(projectName)));
|
|
45
|
+
|
|
46
|
+
if (serviceNames.length > 0) {
|
|
47
|
+
console.log("");
|
|
48
|
+
console.log(` ${pc.dim("─── Services ───")}`);
|
|
49
|
+
for (const name of serviceNames) {
|
|
50
|
+
const port = ports[name];
|
|
51
|
+
const url = `localhost:${port}`;
|
|
52
|
+
console.log(formatLabel(`${name}:`, formatUrl(`http://${url}`)));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (appNames.length > 0) {
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log(` ${pc.dim("─── Applications ───")}`);
|
|
59
|
+
for (const name of appNames) {
|
|
60
|
+
const port = ports[name];
|
|
61
|
+
const localUrl = `http://localhost:${port}`;
|
|
62
|
+
const networkUrl = `http://${localIp}:${port}`;
|
|
63
|
+
|
|
64
|
+
console.log(` ${pc.green("➜")} ${pc.bold(pc.cyan(name))}`);
|
|
65
|
+
console.log(` ${pc.dim("Local:")} ${formatUrl(localUrl)}`);
|
|
66
|
+
console.log(` ${pc.dim("Network:")} ${formatUrl(networkUrl)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log("");
|
|
71
|
+
console.log(` ${pc.dim("─── Environment ───")}`);
|
|
72
|
+
console.log(formatDimLabel("Worktree:", worktree ? "yes" : "no"));
|
|
73
|
+
console.log(
|
|
74
|
+
formatDimLabel("Port offset:", portOffset > 0 ? `+${portOffset}` : "none"),
|
|
75
|
+
);
|
|
76
|
+
if (projectSuffix) {
|
|
77
|
+
console.log(formatDimLabel("Suffix:", projectSuffix));
|
|
78
|
+
}
|
|
79
|
+
console.log(formatDimLabel("Local IP:", localIp));
|
|
80
|
+
console.log("");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function logPublicUrls(
|
|
84
|
+
tunnels: Array<{
|
|
85
|
+
kind: "service" | "app";
|
|
86
|
+
name: string;
|
|
87
|
+
publicUrl: string;
|
|
88
|
+
localUrl: string;
|
|
89
|
+
}>,
|
|
90
|
+
): void {
|
|
91
|
+
if (tunnels.length === 0) return;
|
|
92
|
+
|
|
93
|
+
console.log("");
|
|
94
|
+
console.log(` ${pc.dim("─── Public URLs (Quick Tunnel) ───")}`);
|
|
95
|
+
for (const tunnel of tunnels) {
|
|
96
|
+
const label = `${tunnel.name} (${tunnel.kind})`;
|
|
97
|
+
console.log(formatLabel(`${label}:`, formatUrl(tunnel.publicUrl), "🌐"));
|
|
98
|
+
console.log(formatDimLabel("Local target:", tunnel.localUrl));
|
|
99
|
+
}
|
|
100
|
+
console.log("");
|
|
101
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AppConfig,
|
|
3
|
+
HookContext,
|
|
4
|
+
SeedCheckContext,
|
|
5
|
+
ServiceConfig,
|
|
6
|
+
} from "../types";
|
|
7
|
+
|
|
8
|
+
export function createCheckTableHelper<
|
|
9
|
+
TServices extends Record<string, ServiceConfig>,
|
|
10
|
+
TApps extends Record<string, AppConfig>,
|
|
11
|
+
>(
|
|
12
|
+
urls: Record<string, string>,
|
|
13
|
+
exec: (
|
|
14
|
+
cmd: string,
|
|
15
|
+
options?: { throwOnError?: boolean },
|
|
16
|
+
) => Promise<{
|
|
17
|
+
exitCode: number;
|
|
18
|
+
stdout: string;
|
|
19
|
+
stderr: string;
|
|
20
|
+
}>,
|
|
21
|
+
): SeedCheckContext<TServices, TApps>["checkTable"] {
|
|
22
|
+
return async (
|
|
23
|
+
tableName: string,
|
|
24
|
+
service?: keyof TServices,
|
|
25
|
+
): Promise<boolean> => {
|
|
26
|
+
const serviceName = (service ?? "postgres") as string;
|
|
27
|
+
const serviceUrl = urls[serviceName];
|
|
28
|
+
if (!serviceUrl) {
|
|
29
|
+
console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
const checkResult = await exec(
|
|
33
|
+
`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`,
|
|
34
|
+
{ throwOnError: false },
|
|
35
|
+
);
|
|
36
|
+
const count = checkResult.stdout.trim();
|
|
37
|
+
const shouldSeed =
|
|
38
|
+
checkResult.exitCode !== 0 || count === "0" || count === "";
|
|
39
|
+
if (!shouldSeed) {
|
|
40
|
+
console.log(` 📊 Table "${tableName}" has ${count} rows`);
|
|
41
|
+
}
|
|
42
|
+
return shouldSeed;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function createSeedCheckContext<
|
|
47
|
+
TServices extends Record<string, ServiceConfig>,
|
|
48
|
+
TApps extends Record<string, AppConfig>,
|
|
49
|
+
>(
|
|
50
|
+
baseContext: HookContext<TServices, TApps>,
|
|
51
|
+
checkTable: SeedCheckContext<TServices, TApps>["checkTable"],
|
|
52
|
+
): SeedCheckContext<TServices, TApps> {
|
|
53
|
+
return {
|
|
54
|
+
...baseContext,
|
|
55
|
+
checkTable,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -3,25 +3,33 @@
|
|
|
3
3
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
4
4
|
|
|
5
5
|
// CLI runner
|
|
6
|
-
export { getFlagValue, hasFlag, runCli } from "./cli";
|
|
6
|
+
export { getFlagValue, hasFlag, runCli } from "./cli/run-cli";
|
|
7
7
|
// Config factory
|
|
8
8
|
export {
|
|
9
9
|
assertValidConfig,
|
|
10
10
|
defineDevConfig,
|
|
11
11
|
mergeConfigs,
|
|
12
12
|
validateConfig,
|
|
13
|
-
} from "./config";
|
|
13
|
+
} from "./config/index";
|
|
14
|
+
export type {
|
|
15
|
+
ClickhouseServiceOptions,
|
|
16
|
+
CustomServiceOptions,
|
|
17
|
+
PostgresServiceOptions,
|
|
18
|
+
RedisServiceOptions,
|
|
19
|
+
} from "./docker-compose/services";
|
|
20
|
+
// Service helpers
|
|
21
|
+
export { service } from "./docker-compose/services";
|
|
14
22
|
// Environment factory
|
|
15
|
-
export { createDevEnvironment } from "./environment";
|
|
23
|
+
export { createDevEnvironment } from "./environment/index";
|
|
24
|
+
// Config loader (for programmatic access)
|
|
25
|
+
export { clearDevEnvCache, getDevEnv, loadDevEnv } from "./loader/index";
|
|
16
26
|
// Lint / Typecheck
|
|
17
27
|
export {
|
|
18
28
|
runWorkspaceTypecheck,
|
|
19
29
|
type TypecheckResult,
|
|
20
30
|
type WorkspaceTypecheckOptions,
|
|
21
31
|
type WorkspaceTypecheckResult,
|
|
22
|
-
} from "./
|
|
23
|
-
// Config loader (for programmatic access)
|
|
24
|
-
export { clearDevEnvCache, getDevEnv, loadDevEnv } from "./loader";
|
|
32
|
+
} from "./typecheck/index";
|
|
25
33
|
|
|
26
34
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
27
35
|
// Types
|
|
@@ -34,6 +42,7 @@ export type {
|
|
|
34
42
|
CliOptions,
|
|
35
43
|
// Computed types
|
|
36
44
|
ComputedPorts,
|
|
45
|
+
ComputedPublicUrls,
|
|
37
46
|
ComputedUrls,
|
|
38
47
|
// Main config
|
|
39
48
|
DevConfig,
|
|
@@ -42,6 +51,14 @@ export type {
|
|
|
42
51
|
DevHooks,
|
|
43
52
|
DevOptions,
|
|
44
53
|
DevServerPids,
|
|
54
|
+
DockerComposeGenerationOptions,
|
|
55
|
+
DockerComposeHealthcheckRaw,
|
|
56
|
+
DockerComposeNode,
|
|
57
|
+
DockerComposeServiceRaw,
|
|
58
|
+
DockerComposeVolumeRaw,
|
|
59
|
+
DockerPresetName,
|
|
60
|
+
DockerPresetServiceDefinition,
|
|
61
|
+
DockerServiceDefinition,
|
|
45
62
|
EnvVarsBuilder,
|
|
46
63
|
ExecOptions,
|
|
47
64
|
HealthCheckFn,
|
|
@@ -61,33 +78,22 @@ export type {
|
|
|
61
78
|
StopOptions,
|
|
62
79
|
UrlBuilderContext,
|
|
63
80
|
UrlBuilderFn,
|
|
64
|
-
} from "./types";
|
|
81
|
+
} from "./types/index";
|
|
65
82
|
|
|
66
83
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
67
84
|
// Core Utilities (for advanced use cases)
|
|
68
85
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
69
86
|
|
|
70
|
-
export {
|
|
71
|
-
areContainersRunning,
|
|
72
|
-
assertDockerRunning,
|
|
73
|
-
DOCKER_NOT_RUNNING_MESSAGE,
|
|
74
|
-
isContainerRunning,
|
|
75
|
-
isDockerRunning,
|
|
76
|
-
MAX_ATTEMPTS,
|
|
77
|
-
POLL_INTERVAL,
|
|
78
|
-
} from "./core/docker";
|
|
79
|
-
|
|
80
87
|
export { getLocalIp, isPortAvailable, waitForServer } from "./core/network";
|
|
81
88
|
export {
|
|
82
|
-
computeDevIdentity,
|
|
83
89
|
calculatePortOffset,
|
|
90
|
+
computeDevIdentity,
|
|
84
91
|
findMonorepoRoot,
|
|
85
92
|
getProjectName,
|
|
86
|
-
getWorktreeProjectSuffix,
|
|
87
93
|
getWorktreeName,
|
|
94
|
+
getWorktreeProjectSuffix,
|
|
88
95
|
isWorktree,
|
|
89
96
|
} from "./core/ports";
|
|
90
|
-
|
|
91
97
|
export {
|
|
92
98
|
getProcessOnPort,
|
|
93
99
|
isPortInUse,
|
|
@@ -96,6 +102,13 @@ export {
|
|
|
96
102
|
killProcessOnPort,
|
|
97
103
|
killProcessOnPortAndWait,
|
|
98
104
|
} from "./core/process";
|
|
105
|
+
export {
|
|
106
|
+
type PublicExposeTarget,
|
|
107
|
+
type PublicTunnel,
|
|
108
|
+
resolveExposeTargets,
|
|
109
|
+
startPublicTunnels,
|
|
110
|
+
stopPublicTunnels,
|
|
111
|
+
} from "./core/tunnel";
|
|
99
112
|
export {
|
|
100
113
|
getEnvVar,
|
|
101
114
|
isCI,
|
|
@@ -113,3 +126,19 @@ export {
|
|
|
113
126
|
stopHeartbeat,
|
|
114
127
|
stopWatchdog,
|
|
115
128
|
} from "./core/watchdog";
|
|
129
|
+
export {
|
|
130
|
+
areContainersRunning,
|
|
131
|
+
assertDockerRunning,
|
|
132
|
+
DOCKER_NOT_RUNNING_MESSAGE,
|
|
133
|
+
isContainerRunning,
|
|
134
|
+
isDockerRunning,
|
|
135
|
+
MAX_ATTEMPTS,
|
|
136
|
+
POLL_INTERVAL,
|
|
137
|
+
} from "./docker/index";
|
|
138
|
+
export {
|
|
139
|
+
buildComposeModel,
|
|
140
|
+
composeToYaml,
|
|
141
|
+
DEFAULT_GENERATED_COMPOSE_FILE,
|
|
142
|
+
getGeneratedComposePath,
|
|
143
|
+
writeGeneratedComposeFile,
|
|
144
|
+
} from "./docker-compose/index";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AppConfig, DevEnvironment, ServiceConfig } from "../types";
|
|
2
|
+
|
|
3
|
+
let cachedEnv: DevEnvironment<
|
|
4
|
+
Record<string, ServiceConfig>,
|
|
5
|
+
Record<string, AppConfig>
|
|
6
|
+
> | null = null;
|
|
7
|
+
|
|
8
|
+
export function setCachedDevEnv(
|
|
9
|
+
env: DevEnvironment<Record<string, ServiceConfig>, Record<string, AppConfig>>,
|
|
10
|
+
): void {
|
|
11
|
+
cachedEnv = env;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getCachedDevEnv(): DevEnvironment<
|
|
15
|
+
Record<string, ServiceConfig>,
|
|
16
|
+
Record<string, AppConfig>
|
|
17
|
+
> | null {
|
|
18
|
+
return cachedEnv;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function clearDevEnvCache(): void {
|
|
22
|
+
cachedEnv = null;
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
|
|
4
|
+
export const CONFIG_FILES = [
|
|
5
|
+
"dev.config.ts",
|
|
6
|
+
"dev.config.js",
|
|
7
|
+
"dev-tools.config.ts",
|
|
8
|
+
"dev-tools.config.js",
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export function findConfigFile(startDir: string): string | null {
|
|
12
|
+
let currentDir = startDir;
|
|
13
|
+
|
|
14
|
+
while (true) {
|
|
15
|
+
for (const file of CONFIG_FILES) {
|
|
16
|
+
const configPath = join(currentDir, file);
|
|
17
|
+
if (existsSync(configPath)) {
|
|
18
|
+
return configPath;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const parentDir = dirname(currentDir);
|
|
23
|
+
if (parentDir === currentDir) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
currentDir = parentDir;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AppConfig, DevEnvironment, ServiceConfig } from "../types";
|
|
2
|
+
import { getCachedDevEnv } from "./cache";
|
|
3
|
+
|
|
4
|
+
export { clearDevEnvCache } from "./cache";
|
|
5
|
+
export { CONFIG_FILES, findConfigFile } from "./find-config-file";
|
|
6
|
+
export { loadDevEnv } from "./load-dev-env";
|
|
7
|
+
|
|
8
|
+
export function getDevEnv(): DevEnvironment<
|
|
9
|
+
Record<string, ServiceConfig>,
|
|
10
|
+
Record<string, AppConfig>
|
|
11
|
+
> {
|
|
12
|
+
const env = getCachedDevEnv();
|
|
13
|
+
if (!env) {
|
|
14
|
+
throw new Error("Dev environment not loaded. Call loadDevEnv() first.");
|
|
15
|
+
}
|
|
16
|
+
return env;
|
|
17
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createDevEnvironment } from "../environment";
|
|
2
|
+
import type { AppConfig, DevEnvironment, ServiceConfig } from "../types";
|
|
3
|
+
import { getCachedDevEnv, setCachedDevEnv } from "./cache";
|
|
4
|
+
import { findConfigFile } from "./find-config-file";
|
|
5
|
+
|
|
6
|
+
export async function loadDevEnv(options?: {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
reload?: boolean;
|
|
9
|
+
}): Promise<
|
|
10
|
+
DevEnvironment<Record<string, ServiceConfig>, Record<string, AppConfig>>
|
|
11
|
+
> {
|
|
12
|
+
if (!options?.reload) {
|
|
13
|
+
const cached = getCachedDevEnv();
|
|
14
|
+
if (cached) return cached;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
18
|
+
const configPath = findConfigFile(cwd);
|
|
19
|
+
|
|
20
|
+
if (configPath) {
|
|
21
|
+
const mod = await import(configPath);
|
|
22
|
+
const config = mod.default;
|
|
23
|
+
|
|
24
|
+
if (!config?.projectPrefix || !config?.services) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Invalid config in "${configPath}". Use defineDevConfig() and export as default.`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const env = createDevEnvironment(config);
|
|
31
|
+
setCachedDevEnv(env);
|
|
32
|
+
return env;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
throw new Error(
|
|
36
|
+
"No config file found. Create dev.config.ts with: export default defineDevConfig({ ... })",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./prisma";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
isContainerRunning,
|
|
29
29
|
startService,
|
|
30
30
|
waitForServiceByType,
|
|
31
|
-
} from "
|
|
31
|
+
} from "../docker/runtime";
|
|
32
32
|
import type {
|
|
33
33
|
AppConfig,
|
|
34
34
|
BuiltInHealthCheck,
|
|
@@ -36,7 +36,7 @@ import type {
|
|
|
36
36
|
PrismaConfig,
|
|
37
37
|
PrismaRunner,
|
|
38
38
|
ServiceConfig,
|
|
39
|
-
} from "
|
|
39
|
+
} from "../types";
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Create a Prisma runner from config (used internally by createDevEnvironment).
|
|
@@ -80,9 +80,11 @@ export function createPrismaRunner<
|
|
|
80
80
|
|
|
81
81
|
console.log(`🐳 Starting ${service}...`);
|
|
82
82
|
|
|
83
|
+
const composeFile = env.ensureComposeFile();
|
|
83
84
|
const envVars = env.buildEnvVars();
|
|
84
85
|
startService(env.root, env.projectName, service, envVars, {
|
|
85
86
|
verbose: false,
|
|
87
|
+
composeFile,
|
|
86
88
|
});
|
|
87
89
|
|
|
88
90
|
const port = (env.ports as Record<string, number>)[service];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./typecheck";
|
|
@@ -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: {
|
|
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
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -426,6 +539,10 @@ export interface DevEnvironment<
|
|
|
426
539
|
readonly ports: ComputedPorts<TServices, TApps>;
|
|
427
540
|
/** Computed URLs for all services and apps */
|
|
428
541
|
readonly urls: ComputedUrls<TServices, TApps>;
|
|
542
|
+
/** Public tunnel URLs for exposed services/apps (when active) */
|
|
543
|
+
readonly publicUrls: ComputedPublicUrls<TServices, TApps>;
|
|
544
|
+
/** Services configuration */
|
|
545
|
+
readonly services: TServices;
|
|
429
546
|
/** Apps configuration (for CLI to build commands) */
|
|
430
547
|
readonly apps: TApps;
|
|
431
548
|
/** Port offset applied (0 for main, > 0 for worktrees) */
|
|
@@ -436,6 +553,8 @@ export interface DevEnvironment<
|
|
|
436
553
|
readonly localIp: string;
|
|
437
554
|
/** Path to monorepo root */
|
|
438
555
|
readonly root: string;
|
|
556
|
+
/** Path passed to docker compose -f */
|
|
557
|
+
readonly composeFile: string;
|
|
439
558
|
|
|
440
559
|
// ─────────────────────────────────────────────────────────────────────────
|
|
441
560
|
// Container Management
|
|
@@ -473,6 +592,12 @@ export interface DevEnvironment<
|
|
|
473
592
|
|
|
474
593
|
/** Build environment variables for shell commands */
|
|
475
594
|
buildEnvVars(production?: boolean): Record<string, string>;
|
|
595
|
+
/** Set public tunnel URLs used by envVars and *_PUBLIC_URL injection */
|
|
596
|
+
setPublicUrls(urls: ComputedPublicUrls<TServices, TApps>): void;
|
|
597
|
+
/** Clear all public tunnel URLs */
|
|
598
|
+
clearPublicUrls(): void;
|
|
599
|
+
/** Ensure generated docker compose file exists and return path used with -f */
|
|
600
|
+
ensureComposeFile(): string;
|
|
476
601
|
/** Execute a command with environment variables set */
|
|
477
602
|
exec(
|
|
478
603
|
cmd: string,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./all-types";
|