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.
- 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 +317 -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 +30 -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/quick-tunnel/cloudflared-process.d.ts +10 -0
- package/dist/core/quick-tunnel/constants.d.ts +9 -0
- package/dist/core/quick-tunnel/index.d.ts +17 -0
- package/dist/core/quick-tunnel/install.d.ts +1 -0
- package/dist/core/tunnel.d.ts +34 -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/only-apps.d.ts +10 -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-3eyrdxw9.js +577 -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-5aq985p4.js +250 -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-6cmex7m5.js +72 -0
- package/dist/index-6d6x175r.js +572 -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-7v19es2e.js +666 -0
- package/dist/index-8bw1cmz4.js +531 -0
- package/dist/index-8hbbj1mp.js +120 -121
- package/dist/index-8xj2p5n5.js +118 -97
- package/dist/index-9wyhzw0h.js +574 -0
- package/dist/index-ag90ry8t.js +576 -0
- package/dist/index-bj79tw5w.js +0 -0
- package/dist/index-bnk6nr0g.js +73 -0
- package/dist/index-brbbzyks.js +72 -0
- package/dist/index-byeqyjrz.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-enj4zdma.js +574 -0
- 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-k370bech.js +72 -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-qa8akv6y.js +666 -0
- 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-vg55rq0y.js +250 -0
- package/dist/index-vhs88xhe.js +99 -95
- package/dist/index-vs81yaks.js +244 -0
- 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-x54nbgs7.js +355 -0
- package/dist/index-xkvd0nsd.js +187 -0
- package/dist/index-yedqxm1z.js +80 -0
- package/dist/index-yz4jfz7z.js +338 -0
- package/dist/index-zfjzzjkf.js +240 -199
- package/dist/index.d.ts +12 -8
- package/dist/index.js +56 -34
- 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 +544 -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 +55 -48
- package/readme.md +365 -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} +114 -10
- 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/quick-tunnel/cloudflared-process.ts +83 -0
- package/src/core/quick-tunnel/constants.ts +31 -0
- package/src/core/quick-tunnel/index.ts +96 -0
- package/src/core/quick-tunnel/install.ts +160 -0
- package/src/core/tunnel.ts +165 -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} +214 -141
- package/src/environment/index.ts +1 -0
- package/src/environment/logging.ts +115 -0
- package/src/environment/only-apps.ts +34 -0
- package/src/environment/seeding.ts +57 -0
- package/{index.ts → src/index.ts} +52 -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} +186 -8
- 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,88 @@
|
|
|
1
|
+
import type { DockerComposeNode } from "../types";
|
|
2
|
+
import type { ComposeDocument } from "./model";
|
|
3
|
+
|
|
4
|
+
function isObject(
|
|
5
|
+
value: DockerComposeNode,
|
|
6
|
+
): value is Record<string, DockerComposeNode | undefined> {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function formatScalar(value: string | number | boolean | null): string {
|
|
11
|
+
if (value === null) return "null";
|
|
12
|
+
if (typeof value === "string") {
|
|
13
|
+
return JSON.stringify(value);
|
|
14
|
+
}
|
|
15
|
+
return String(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function formatKey(key: string): string {
|
|
19
|
+
return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key) ? key : JSON.stringify(key);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function sortNode(node: DockerComposeNode): DockerComposeNode {
|
|
23
|
+
if (Array.isArray(node)) {
|
|
24
|
+
return node.map(sortNode);
|
|
25
|
+
}
|
|
26
|
+
if (isObject(node)) {
|
|
27
|
+
const sorted: Record<string, DockerComposeNode | undefined> = {};
|
|
28
|
+
for (const key of Object.keys(node).sort()) {
|
|
29
|
+
const value = node[key];
|
|
30
|
+
if (value !== undefined) {
|
|
31
|
+
sorted[key] = sortNode(value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return sorted;
|
|
35
|
+
}
|
|
36
|
+
return node;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function stringifyNode(node: DockerComposeNode, indent = 0): string {
|
|
40
|
+
const prefix = " ".repeat(indent);
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
typeof node === "string" ||
|
|
44
|
+
typeof node === "number" ||
|
|
45
|
+
typeof node === "boolean" ||
|
|
46
|
+
node === null
|
|
47
|
+
) {
|
|
48
|
+
return `${prefix}${formatScalar(node)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (Array.isArray(node)) {
|
|
52
|
+
if (node.length === 0) return `${prefix}[]`;
|
|
53
|
+
return node
|
|
54
|
+
.map((item) => {
|
|
55
|
+
const isNested = typeof item === "object" && item !== null;
|
|
56
|
+
if (!isNested) {
|
|
57
|
+
return `${prefix}- ${formatScalar(
|
|
58
|
+
item as string | number | boolean | null,
|
|
59
|
+
)}`;
|
|
60
|
+
}
|
|
61
|
+
return `${prefix}-\n${stringifyNode(item, indent + 2)}`;
|
|
62
|
+
})
|
|
63
|
+
.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const entries = Object.entries(node).filter(
|
|
67
|
+
([, value]) => value !== undefined,
|
|
68
|
+
) as Array<[string, DockerComposeNode]>;
|
|
69
|
+
if (entries.length === 0) return `${prefix}{}`;
|
|
70
|
+
|
|
71
|
+
return entries
|
|
72
|
+
.map(([key, value]) => {
|
|
73
|
+
const formattedKey = formatKey(key);
|
|
74
|
+
const isNested = typeof value === "object" && value !== null;
|
|
75
|
+
if (!isNested) {
|
|
76
|
+
return `${prefix}${formattedKey}: ${formatScalar(
|
|
77
|
+
value as string | number | boolean | null,
|
|
78
|
+
)}`;
|
|
79
|
+
}
|
|
80
|
+
return `${prefix}${formattedKey}:\n${stringifyNode(value, indent + 2)}`;
|
|
81
|
+
})
|
|
82
|
+
.join("\n");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function composeToYaml(document: ComposeDocument): string {
|
|
86
|
+
const sorted = sortNode(document as DockerComposeNode);
|
|
87
|
+
return `${stringifyNode(sorted)}\n`;
|
|
88
|
+
}
|
|
@@ -1,72 +1,61 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
areContainersRunning,
|
|
5
|
-
startContainers,
|
|
6
|
-
stopContainers,
|
|
7
|
-
} from "./core/docker";
|
|
8
|
-
import { getLocalIp, waitForDevServers, waitForServer } from "./core/network";
|
|
1
|
+
import { assertValidConfig } from "../config";
|
|
2
|
+
import { getLocalIp, waitForDevServers, waitForServer } from "../core/network";
|
|
9
3
|
import {
|
|
10
4
|
computeDevIdentity,
|
|
11
5
|
computePorts,
|
|
12
6
|
computeUrls,
|
|
13
7
|
findMonorepoRoot,
|
|
14
|
-
} from "
|
|
8
|
+
} from "../core/ports";
|
|
15
9
|
import {
|
|
16
10
|
buildApps,
|
|
17
11
|
execAsync,
|
|
18
12
|
startDevServers,
|
|
19
13
|
stopProcess as stopProcessFn,
|
|
20
|
-
} from "
|
|
21
|
-
import {
|
|
14
|
+
} from "../core/process";
|
|
15
|
+
import {
|
|
16
|
+
type PublicTunnel,
|
|
17
|
+
resolveExposeTargets,
|
|
18
|
+
startPublicTunnels,
|
|
19
|
+
stopPublicTunnels,
|
|
20
|
+
} from "../core/tunnel";
|
|
21
|
+
import { isCI as isCIEnv, logExpoApiUrl, logFrontendPort } from "../core/utils";
|
|
22
22
|
import {
|
|
23
23
|
spawnWatchdog as spawnWatchdogFn,
|
|
24
24
|
startHeartbeat as startHeartbeatFn,
|
|
25
25
|
stopHeartbeat as stopHeartbeatFn,
|
|
26
26
|
stopWatchdog as stopWatchdogFn,
|
|
27
|
-
} from "
|
|
28
|
-
import {
|
|
27
|
+
} from "../core/watchdog";
|
|
28
|
+
import {
|
|
29
|
+
areContainersRunning,
|
|
30
|
+
startContainers,
|
|
31
|
+
stopContainers,
|
|
32
|
+
} from "../docker/runtime";
|
|
33
|
+
import {
|
|
34
|
+
getGeneratedComposePath,
|
|
35
|
+
writeGeneratedComposeFile,
|
|
36
|
+
} from "../docker-compose";
|
|
37
|
+
import { createPrismaRunner } from "../prisma";
|
|
29
38
|
import type {
|
|
30
39
|
AppConfig,
|
|
31
40
|
ComputedPorts,
|
|
41
|
+
ComputedPublicUrls,
|
|
32
42
|
ComputedUrls,
|
|
33
43
|
DevConfig,
|
|
34
44
|
DevEnvironment,
|
|
45
|
+
DevEnvironmentTunnelLog,
|
|
35
46
|
DevServerPids,
|
|
36
47
|
ExecOptions,
|
|
37
48
|
HookContext,
|
|
49
|
+
OpenPublicTunnelsOptions,
|
|
50
|
+
OpenPublicTunnelsResult,
|
|
38
51
|
PrismaRunner,
|
|
39
52
|
ServiceConfig,
|
|
40
53
|
StartOptions,
|
|
41
54
|
StopOptions,
|
|
42
|
-
} from "
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Format a URL with colored port number (Vite-style).
|
|
50
|
-
*/
|
|
51
|
-
function formatUrl(url: string): string {
|
|
52
|
-
return pc.cyan(
|
|
53
|
-
url.replace(/:(\d+)(\/?)/, (_, port, slash) => `:${pc.bold(port)}${slash}`),
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Format a label with arrow prefix (Vite-style).
|
|
59
|
-
*/
|
|
60
|
-
function formatLabel(label: string, value: string, arrow = "➜"): string {
|
|
61
|
-
return ` ${pc.green(arrow)} ${pc.bold(label.padEnd(10))} ${value}`;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Format a dim label (for secondary info).
|
|
66
|
-
*/
|
|
67
|
-
function formatDimLabel(label: string, value: string): string {
|
|
68
|
-
return ` ${pc.dim("•")} ${pc.dim(label.padEnd(10))} ${pc.dim(value)}`;
|
|
69
|
-
}
|
|
55
|
+
} from "../types";
|
|
56
|
+
import { logEnvironmentInfo } from "./logging";
|
|
57
|
+
import { assertOnlyAppNames, pickApps } from "./only-apps";
|
|
58
|
+
import { createCheckTableHelper, createSeedCheckContext } from "./seeding";
|
|
70
59
|
|
|
71
60
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
72
61
|
// Environment Factory
|
|
@@ -115,6 +104,14 @@ export function createDevEnvironment<
|
|
|
115
104
|
|
|
116
105
|
const services = config.services;
|
|
117
106
|
const apps = (config.apps ?? {}) as TApps;
|
|
107
|
+
const composeFile = getGeneratedComposePath(
|
|
108
|
+
root,
|
|
109
|
+
config.docker,
|
|
110
|
+
).composeFileArg;
|
|
111
|
+
|
|
112
|
+
function ensureComposeFile(): string {
|
|
113
|
+
return writeGeneratedComposeFile(root, services, config.docker);
|
|
114
|
+
}
|
|
118
115
|
|
|
119
116
|
// Compute ports and URLs
|
|
120
117
|
const ports = computePorts(services, apps, portOffset) as ComputedPorts<
|
|
@@ -125,6 +122,22 @@ export function createDevEnvironment<
|
|
|
125
122
|
TServices,
|
|
126
123
|
TApps
|
|
127
124
|
>;
|
|
125
|
+
const publicUrls: Record<string, string> = {};
|
|
126
|
+
|
|
127
|
+
function setPublicUrls(urlsInput: Record<string, string>): void {
|
|
128
|
+
for (const key of Object.keys(publicUrls)) {
|
|
129
|
+
delete publicUrls[key];
|
|
130
|
+
}
|
|
131
|
+
for (const [key, value] of Object.entries(urlsInput)) {
|
|
132
|
+
publicUrls[key] = value;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function clearPublicUrls(): void {
|
|
137
|
+
for (const key of Object.keys(publicUrls)) {
|
|
138
|
+
delete publicUrls[key];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
128
141
|
|
|
129
142
|
// Build environment variables
|
|
130
143
|
function buildEnvVars(production = false): Record<string, string> {
|
|
@@ -145,12 +158,19 @@ export function createDevEnvironment<
|
|
|
145
158
|
baseEnv[envName] = url;
|
|
146
159
|
}
|
|
147
160
|
|
|
161
|
+
// Add public URL environment variables when tunnels are active
|
|
162
|
+
for (const [name, url] of Object.entries(publicUrls)) {
|
|
163
|
+
const envName = `${name.toUpperCase()}_PUBLIC_URL`;
|
|
164
|
+
baseEnv[envName] = url;
|
|
165
|
+
}
|
|
166
|
+
|
|
148
167
|
// Call user's envVars function if provided
|
|
149
168
|
if (config.envVars) {
|
|
150
169
|
const userEnv = config.envVars(ports, urls, {
|
|
151
170
|
projectName,
|
|
152
171
|
localIp,
|
|
153
172
|
portOffset,
|
|
173
|
+
publicUrls: publicUrls as ComputedPublicUrls<TServices, TApps>,
|
|
154
174
|
});
|
|
155
175
|
for (const [key, value] of Object.entries(userEnv)) {
|
|
156
176
|
baseEnv[key] = String(value);
|
|
@@ -169,6 +189,7 @@ export function createDevEnvironment<
|
|
|
169
189
|
projectName,
|
|
170
190
|
ports,
|
|
171
191
|
urls,
|
|
192
|
+
publicUrls: publicUrls as ComputedPublicUrls<TServices, TApps>,
|
|
172
193
|
root,
|
|
173
194
|
isCI: isCIEnv(),
|
|
174
195
|
portOffset,
|
|
@@ -202,12 +223,18 @@ export function createDevEnvironment<
|
|
|
202
223
|
startServers: shouldStartServers = true,
|
|
203
224
|
productionBuild = isCI,
|
|
204
225
|
skipSeed = false,
|
|
226
|
+
skipEnvironmentLog = false,
|
|
227
|
+
onlyApps,
|
|
205
228
|
} = startOptions;
|
|
206
229
|
|
|
230
|
+
assertOnlyAppNames(Object.keys(apps), onlyApps);
|
|
231
|
+
const appsToStart = pickApps(apps, onlyApps);
|
|
232
|
+
|
|
207
233
|
const envVars = buildEnvVars(productionBuild);
|
|
234
|
+
ensureComposeFile();
|
|
208
235
|
|
|
209
236
|
// Log environment info
|
|
210
|
-
if (verbose) {
|
|
237
|
+
if (verbose && !skipEnvironmentLog) {
|
|
211
238
|
logInfo(productionBuild ? "Production Environment" : "Dev Environment");
|
|
212
239
|
}
|
|
213
240
|
|
|
@@ -224,7 +251,7 @@ export function createDevEnvironment<
|
|
|
224
251
|
startContainers(root, projectName, envVars, {
|
|
225
252
|
verbose,
|
|
226
253
|
wait,
|
|
227
|
-
composeFile
|
|
254
|
+
composeFile,
|
|
228
255
|
});
|
|
229
256
|
}
|
|
230
257
|
|
|
@@ -258,19 +285,19 @@ export function createDevEnvironment<
|
|
|
258
285
|
}),
|
|
259
286
|
);
|
|
260
287
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
// Check for failures
|
|
289
|
+
for (const { name, result } of migrationResults) {
|
|
290
|
+
if (result.exitCode !== 0) {
|
|
291
|
+
console.error(`❌ Migration "${name}" failed`);
|
|
292
|
+
if (result.stdout) {
|
|
293
|
+
console.error(result.stdout);
|
|
294
|
+
}
|
|
295
|
+
if (result.stderr) {
|
|
296
|
+
console.error(result.stderr);
|
|
297
|
+
}
|
|
298
|
+
throw new Error(`Migration "${name}" failed`);
|
|
270
299
|
}
|
|
271
|
-
throw new Error(`Migration "${name}" failed`);
|
|
272
300
|
}
|
|
273
|
-
}
|
|
274
301
|
|
|
275
302
|
if (verbose) console.log("✓ Migrations complete");
|
|
276
303
|
}
|
|
@@ -286,35 +313,14 @@ export function createDevEnvironment<
|
|
|
286
313
|
|
|
287
314
|
// Check if seeding is needed using check function
|
|
288
315
|
if (config.seed.check) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
service?: keyof TServices,
|
|
293
|
-
): Promise<boolean> => {
|
|
294
|
-
const serviceName = (service ?? "postgres") as string;
|
|
295
|
-
const serviceUrl = (urls as Record<string, string>)[serviceName];
|
|
296
|
-
if (!serviceUrl) {
|
|
297
|
-
console.warn(`⚠️ Service "${serviceName}" not found for checkTable`);
|
|
298
|
-
return true; // Default to seeding if service not found
|
|
299
|
-
}
|
|
300
|
-
const checkResult = await exec(
|
|
301
|
-
`psql "${serviceUrl}" -tAc 'SELECT COUNT(*) FROM "${tableName}" LIMIT 1'`,
|
|
302
|
-
{ throwOnError: false },
|
|
316
|
+
const checkTable = createCheckTableHelper<TServices, TApps>(
|
|
317
|
+
urls as Record<string, string>,
|
|
318
|
+
exec,
|
|
303
319
|
);
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
if (!shouldSeed) {
|
|
307
|
-
console.log(` 📊 Table "${tableName}" has ${count} rows`);
|
|
308
|
-
}
|
|
309
|
-
return shouldSeed;
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
// Build seed check context with helpers
|
|
313
|
-
const seedCheckContext = {
|
|
314
|
-
...getHookContext(),
|
|
320
|
+
const seedCheckContext = createSeedCheckContext(
|
|
321
|
+
getHookContext(),
|
|
315
322
|
checkTable,
|
|
316
|
-
|
|
317
|
-
|
|
323
|
+
);
|
|
318
324
|
shouldSeed = await config.seed.check(seedCheckContext);
|
|
319
325
|
}
|
|
320
326
|
|
|
@@ -339,7 +345,7 @@ export function createDevEnvironment<
|
|
|
339
345
|
}
|
|
340
346
|
|
|
341
347
|
// Start servers if requested
|
|
342
|
-
if (shouldStartServers && Object.keys(
|
|
348
|
+
if (shouldStartServers && Object.keys(appsToStart).length > 0) {
|
|
343
349
|
// Run beforeServers hook
|
|
344
350
|
if (config.hooks?.beforeServers) {
|
|
345
351
|
await config.hooks.beforeServers(getHookContext());
|
|
@@ -347,11 +353,11 @@ export function createDevEnvironment<
|
|
|
347
353
|
|
|
348
354
|
// Build if production
|
|
349
355
|
if (productionBuild) {
|
|
350
|
-
buildApps(
|
|
356
|
+
buildApps(appsToStart, root, envVars, { verbose });
|
|
351
357
|
}
|
|
352
358
|
|
|
353
359
|
// Start servers
|
|
354
|
-
const pids = await startDevServers(
|
|
360
|
+
const pids = await startDevServers(appsToStart, root, envVars, ports, {
|
|
355
361
|
verbose,
|
|
356
362
|
productionBuild,
|
|
357
363
|
isCI,
|
|
@@ -359,7 +365,7 @@ export function createDevEnvironment<
|
|
|
359
365
|
|
|
360
366
|
// Wait for servers to be ready
|
|
361
367
|
if (verbose) console.log("⏳ Waiting for servers to be ready...");
|
|
362
|
-
await waitForDevServers(
|
|
368
|
+
await waitForDevServers(appsToStart, ports, {
|
|
363
369
|
timeout: isCI ? 120000 : 60000,
|
|
364
370
|
verbose,
|
|
365
371
|
productionBuild,
|
|
@@ -380,6 +386,7 @@ export function createDevEnvironment<
|
|
|
380
386
|
|
|
381
387
|
async function stop(stopOptions: StopOptions = {}): Promise<void> {
|
|
382
388
|
const { verbose = true, removeVolumes = false } = stopOptions;
|
|
389
|
+
ensureComposeFile();
|
|
383
390
|
|
|
384
391
|
// Run beforeStop hook
|
|
385
392
|
if (config.hooks?.beforeStop) {
|
|
@@ -389,7 +396,7 @@ export function createDevEnvironment<
|
|
|
389
396
|
stopContainers(root, projectName, {
|
|
390
397
|
verbose,
|
|
391
398
|
removeVolumes,
|
|
392
|
-
composeFile
|
|
399
|
+
composeFile,
|
|
393
400
|
});
|
|
394
401
|
}
|
|
395
402
|
|
|
@@ -408,84 +415,141 @@ export function createDevEnvironment<
|
|
|
408
415
|
// ─────────────────────────────────────────────────────────────────────────
|
|
409
416
|
|
|
410
417
|
async function startServersOnly(
|
|
411
|
-
options: {
|
|
418
|
+
options: {
|
|
419
|
+
productionBuild?: boolean;
|
|
420
|
+
verbose?: boolean;
|
|
421
|
+
onlyApps?: string[];
|
|
422
|
+
} = {},
|
|
412
423
|
): Promise<DevServerPids> {
|
|
413
|
-
const { productionBuild = false, verbose = true } = options;
|
|
424
|
+
const { productionBuild = false, verbose = true, onlyApps } = options;
|
|
425
|
+
assertOnlyAppNames(Object.keys(apps), onlyApps);
|
|
426
|
+
const appsToStart = pickApps(apps, onlyApps);
|
|
414
427
|
const envVars = buildEnvVars(productionBuild);
|
|
415
428
|
const isCI = process.env.CI === "true";
|
|
416
429
|
|
|
430
|
+
if (Object.keys(appsToStart).length === 0) {
|
|
431
|
+
return {};
|
|
432
|
+
}
|
|
433
|
+
|
|
417
434
|
// Build if production
|
|
418
435
|
if (productionBuild) {
|
|
419
|
-
buildApps(
|
|
436
|
+
buildApps(appsToStart, root, envVars, { verbose });
|
|
420
437
|
}
|
|
421
438
|
|
|
422
|
-
|
|
439
|
+
const pids = await startDevServers(appsToStart, root, envVars, ports, {
|
|
423
440
|
verbose,
|
|
424
441
|
productionBuild,
|
|
425
442
|
isCI,
|
|
426
443
|
});
|
|
444
|
+
|
|
445
|
+
if (verbose) console.log("⏳ Waiting for servers to be ready...");
|
|
446
|
+
await waitForDevServers(appsToStart, ports, {
|
|
447
|
+
timeout: isCI ? 120000 : 60000,
|
|
448
|
+
verbose,
|
|
449
|
+
productionBuild,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
return pids;
|
|
427
453
|
}
|
|
428
454
|
|
|
429
455
|
async function waitForServersReady(
|
|
430
|
-
options: {
|
|
456
|
+
options: {
|
|
457
|
+
timeout?: number;
|
|
458
|
+
productionBuild?: boolean;
|
|
459
|
+
onlyApps?: string[];
|
|
460
|
+
} = {},
|
|
431
461
|
): Promise<void> {
|
|
432
|
-
const { timeout = 60000, productionBuild = false } = options;
|
|
433
|
-
|
|
462
|
+
const { timeout = 60000, productionBuild = false, onlyApps } = options;
|
|
463
|
+
assertOnlyAppNames(Object.keys(apps), onlyApps);
|
|
464
|
+
const appsToWait = pickApps(apps, onlyApps);
|
|
465
|
+
await waitForDevServers(appsToWait, ports, { timeout, productionBuild });
|
|
434
466
|
}
|
|
435
467
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
console.log(` ${pc.dim("─── Services ───")}`);
|
|
452
|
-
for (const name of serviceNames) {
|
|
453
|
-
const port = (ports as Record<string, number>)[name];
|
|
454
|
-
const url = `localhost:${port}`;
|
|
455
|
-
console.log(formatLabel(`${name}:`, formatUrl(`http://${url}`)));
|
|
456
|
-
}
|
|
468
|
+
async function openPublicTunnels(
|
|
469
|
+
options: OpenPublicTunnelsOptions = {},
|
|
470
|
+
): Promise<OpenPublicTunnelsResult<TServices, TApps>> {
|
|
471
|
+
const { names, waitForHealthy } = options;
|
|
472
|
+
const exposeList = names?.length ? names.join(",") : undefined;
|
|
473
|
+
|
|
474
|
+
if (waitForHealthy?.length) {
|
|
475
|
+
assertOnlyAppNames(Object.keys(apps), waitForHealthy);
|
|
476
|
+
const appsWait = pickApps(apps, waitForHealthy);
|
|
477
|
+
const isCI = process.env.CI === "true";
|
|
478
|
+
await waitForDevServers(appsWait, ports, {
|
|
479
|
+
timeout: isCI ? 120000 : 60000,
|
|
480
|
+
verbose: config.options?.verbose ?? true,
|
|
481
|
+
productionBuild: false,
|
|
482
|
+
});
|
|
457
483
|
}
|
|
458
484
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
485
|
+
const { targets, unknownNames, notEnabledNames } = resolveExposeTargets(
|
|
486
|
+
{
|
|
487
|
+
services,
|
|
488
|
+
apps,
|
|
489
|
+
ports,
|
|
490
|
+
} as DevEnvironment<TServices, TApps>,
|
|
491
|
+
exposeList,
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
if (unknownNames.length > 0) {
|
|
495
|
+
throw new Error(`Unknown expose target(s): ${unknownNames.join(", ")}`);
|
|
496
|
+
}
|
|
497
|
+
if (notEnabledNames.length > 0) {
|
|
498
|
+
throw new Error(
|
|
499
|
+
`Target(s) missing expose: true: ${notEnabledNames.join(", ")}`,
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
if (targets.length === 0) {
|
|
503
|
+
throw new Error(
|
|
504
|
+
"No expose targets selected. Add expose: true to services/apps or pass names that have expose: true.",
|
|
505
|
+
);
|
|
472
506
|
}
|
|
473
507
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
console.log(formatDimLabel("Worktree:", worktree ? "yes" : "no"));
|
|
478
|
-
console.log(
|
|
479
|
-
formatDimLabel(
|
|
480
|
-
"Port offset:",
|
|
481
|
-
portOffset > 0 ? `+${portOffset}` : "none",
|
|
482
|
-
),
|
|
508
|
+
const tunnels = await startPublicTunnels(targets);
|
|
509
|
+
setPublicUrls(
|
|
510
|
+
Object.fromEntries(tunnels.map((t) => [t.name, t.publicUrl])),
|
|
483
511
|
);
|
|
484
|
-
|
|
485
|
-
|
|
512
|
+
|
|
513
|
+
let closed = false;
|
|
514
|
+
async function close(): Promise<void> {
|
|
515
|
+
if (closed) return;
|
|
516
|
+
closed = true;
|
|
517
|
+
await stopPublicTunnels(tunnels);
|
|
518
|
+
clearPublicUrls();
|
|
486
519
|
}
|
|
487
|
-
|
|
488
|
-
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
publicUrls: { ...publicUrls } as ComputedPublicUrls<TServices, TApps>,
|
|
523
|
+
tunnels,
|
|
524
|
+
close,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
529
|
+
// Utilities
|
|
530
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
531
|
+
|
|
532
|
+
function logInfo(label = "Docker Dev", tunnels?: PublicTunnel[]): void {
|
|
533
|
+
const tunnelRows: DevEnvironmentTunnelLog[] | undefined = tunnels?.map(
|
|
534
|
+
({ kind, name, localUrl, publicUrl }) => ({
|
|
535
|
+
kind,
|
|
536
|
+
name,
|
|
537
|
+
localUrl,
|
|
538
|
+
publicUrl,
|
|
539
|
+
}),
|
|
540
|
+
);
|
|
541
|
+
logEnvironmentInfo({
|
|
542
|
+
label,
|
|
543
|
+
projectName,
|
|
544
|
+
services,
|
|
545
|
+
apps,
|
|
546
|
+
ports: ports as Record<string, number>,
|
|
547
|
+
localIp,
|
|
548
|
+
worktree,
|
|
549
|
+
portOffset,
|
|
550
|
+
projectSuffix,
|
|
551
|
+
tunnels: tunnelRows,
|
|
552
|
+
});
|
|
489
553
|
}
|
|
490
554
|
|
|
491
555
|
async function waitForServerUrl(
|
|
@@ -511,7 +575,7 @@ export function createDevEnvironment<
|
|
|
511
575
|
await spawnWatchdogFn(projectName, root, {
|
|
512
576
|
timeoutMinutes,
|
|
513
577
|
verbose: true,
|
|
514
|
-
composeFile
|
|
578
|
+
composeFile,
|
|
515
579
|
});
|
|
516
580
|
}
|
|
517
581
|
|
|
@@ -554,11 +618,14 @@ export function createDevEnvironment<
|
|
|
554
618
|
projectName,
|
|
555
619
|
ports,
|
|
556
620
|
urls,
|
|
621
|
+
publicUrls: publicUrls as ComputedPublicUrls<TServices, TApps>,
|
|
622
|
+
services,
|
|
557
623
|
apps,
|
|
558
624
|
portOffset,
|
|
559
625
|
isWorktree: worktree,
|
|
560
626
|
localIp,
|
|
561
627
|
root,
|
|
628
|
+
composeFile,
|
|
562
629
|
|
|
563
630
|
// Container management
|
|
564
631
|
start,
|
|
@@ -573,9 +640,15 @@ export function createDevEnvironment<
|
|
|
573
640
|
|
|
574
641
|
// Utilities
|
|
575
642
|
buildEnvVars,
|
|
643
|
+
setPublicUrls: (urlsInput) => {
|
|
644
|
+
setPublicUrls(urlsInput as Record<string, string>);
|
|
645
|
+
},
|
|
646
|
+
clearPublicUrls,
|
|
647
|
+
ensureComposeFile,
|
|
576
648
|
exec,
|
|
577
649
|
waitForServer: waitForServerUrl,
|
|
578
650
|
logInfo,
|
|
651
|
+
openPublicTunnels,
|
|
579
652
|
|
|
580
653
|
// Vibe Kanban Integration
|
|
581
654
|
getExpoApiUrl,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createDevEnvironment } from "./create-dev-environment";
|