everything-dev 1.7.2 → 1.8.1
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/api.cjs +1 -1
- package/dist/api.mjs +1 -1
- package/dist/app.cjs +82 -51
- package/dist/app.cjs.map +1 -1
- package/dist/app.mjs +82 -51
- package/dist/app.mjs.map +1 -1
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/components/dev-view.cjs +6 -3
- package/dist/components/dev-view.cjs.map +1 -1
- package/dist/components/dev-view.mjs +6 -3
- package/dist/components/dev-view.mjs.map +1 -1
- package/dist/components/streaming-view.cjs +5 -2
- package/dist/components/streaming-view.cjs.map +1 -1
- package/dist/components/streaming-view.mjs +5 -2
- package/dist/components/streaming-view.mjs.map +1 -1
- package/dist/config.cjs +28 -5
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +28 -5
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs +1 -0
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +10 -2
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +10 -2
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.mjs +1 -0
- package/dist/contract.mjs.map +1 -1
- package/dist/dev-logs.cjs +6 -2
- package/dist/dev-logs.cjs.map +1 -1
- package/dist/dev-logs.mjs +7 -2
- package/dist/dev-logs.mjs.map +1 -1
- package/dist/dev-session.cjs +27 -23
- package/dist/dev-session.cjs.map +1 -1
- package/dist/dev-session.mjs +27 -24
- package/dist/dev-session.mjs.map +1 -1
- package/dist/federation.server.cjs +1 -1
- package/dist/federation.server.mjs +1 -1
- package/dist/host.cjs +4 -3
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts.map +1 -1
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +4 -3
- package/dist/host.mjs.map +1 -1
- package/dist/integrity.cjs +68 -2
- package/dist/integrity.cjs.map +1 -1
- package/dist/integrity.d.cts +14 -1
- package/dist/integrity.d.cts.map +1 -1
- package/dist/integrity.d.mts +14 -1
- package/dist/integrity.d.mts.map +1 -1
- package/dist/integrity.mjs +66 -3
- package/dist/integrity.mjs.map +1 -1
- package/dist/mf.cjs +32 -0
- package/dist/mf.cjs.map +1 -1
- package/dist/mf.d.cts +3 -1
- package/dist/mf.d.cts.map +1 -1
- package/dist/mf.d.mts +3 -1
- package/dist/mf.d.mts.map +1 -1
- package/dist/mf.mjs +32 -1
- package/dist/mf.mjs.map +1 -1
- package/dist/orchestrator.cjs +167 -317
- package/dist/orchestrator.cjs.map +1 -1
- package/dist/orchestrator.d.cts +24 -21
- package/dist/orchestrator.d.cts.map +1 -1
- package/dist/orchestrator.d.mts +24 -21
- package/dist/orchestrator.d.mts.map +1 -1
- package/dist/orchestrator.mjs +168 -316
- package/dist/orchestrator.mjs.map +1 -1
- package/dist/plugin.cjs +38 -107
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +16 -2
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +16 -2
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +39 -108
- package/dist/plugin.mjs.map +1 -1
- package/dist/service-descriptor.cjs +188 -0
- package/dist/service-descriptor.cjs.map +1 -0
- package/dist/service-descriptor.d.cts +107 -0
- package/dist/service-descriptor.d.cts.map +1 -0
- package/dist/service-descriptor.d.mts +107 -0
- package/dist/service-descriptor.d.mts.map +1 -0
- package/dist/service-descriptor.mjs +182 -0
- package/dist/service-descriptor.mjs.map +1 -0
- package/dist/types.cjs +8 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +16 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +16 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +8 -1
- package/dist/types.mjs.map +1 -1
- package/dist/ui/index.cjs +1 -0
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.mts +2 -2
- package/dist/ui/index.mjs +2 -2
- package/dist/ui/runtime.cjs +4 -0
- package/dist/ui/runtime.cjs.map +1 -1
- package/dist/ui/runtime.d.cts +2 -1
- package/dist/ui/runtime.d.cts.map +1 -1
- package/dist/ui/runtime.d.mts +2 -1
- package/dist/ui/runtime.d.mts.map +1 -1
- package/dist/ui/runtime.mjs +4 -1
- package/dist/ui/runtime.mjs.map +1 -1
- package/package.json +12 -4
- package/skills/dev-workflow/SKILL.md +105 -0
- package/skills/publish-sync/SKILL.md +130 -0
- package/src/app.ts +98 -204
- package/src/cli/upgrade.ts +20 -4
- package/src/components/dev-view.tsx +8 -3
- package/src/components/streaming-view.ts +7 -2
- package/src/config.ts +40 -8
- package/src/contract.ts +1 -0
- package/src/dev-logs.ts +8 -1
- package/src/dev-session.ts +56 -79
- package/src/host.ts +4 -3
- package/src/integrity.ts +96 -10
- package/src/mf.ts +42 -0
- package/src/orchestrator.ts +232 -411
- package/src/plugin.ts +48 -136
- package/src/service-descriptor.ts +258 -0
- package/src/types.ts +8 -1
- package/src/ui/runtime.ts +5 -0
- package/dist/process-registry.cjs +0 -120
- package/dist/process-registry.cjs.map +0 -1
- package/dist/process-registry.d.cts +0 -25
- package/dist/process-registry.d.cts.map +0 -1
- package/dist/process-registry.d.mts +0 -25
- package/dist/process-registry.d.mts.map +0 -1
- package/dist/process-registry.mjs +0 -119
- package/dist/process-registry.mjs.map +0 -1
- package/src/process-registry.ts +0 -154
package/dist/orchestrator.cjs
CHANGED
|
@@ -1,206 +1,64 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
|
-
const require_config = require('./config.cjs');
|
|
4
3
|
const require_mf = require('./mf.cjs');
|
|
4
|
+
const require_service_descriptor = require('./service-descriptor.cjs');
|
|
5
5
|
let effect = require("effect");
|
|
6
6
|
let node_net = require("node:net");
|
|
7
|
+
let _effect_platform = require("@effect/platform");
|
|
7
8
|
|
|
8
9
|
//#region src/orchestrator.ts
|
|
9
|
-
const processConfigBases = {
|
|
10
|
-
"host-build": {
|
|
11
|
-
name: "host-build",
|
|
12
|
-
command: "bun",
|
|
13
|
-
args: ["run", "build"],
|
|
14
|
-
cwd: "host",
|
|
15
|
-
readyPatterns: [/built in/i, /compiled.*successfully/i],
|
|
16
|
-
errorPatterns: [
|
|
17
|
-
/error:/i,
|
|
18
|
-
/failed/i,
|
|
19
|
-
/exception/i
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
host: {
|
|
23
|
-
name: "host",
|
|
24
|
-
command: "bun",
|
|
25
|
-
args: ["run", "dev"],
|
|
26
|
-
cwd: "host",
|
|
27
|
-
readyPatterns: [/Host (dev|production) server running at/i, /Server running at/i],
|
|
28
|
-
errorPatterns: [
|
|
29
|
-
/error:/i,
|
|
30
|
-
/failed/i,
|
|
31
|
-
/exception/i
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
ui: {
|
|
35
|
-
name: "ui",
|
|
36
|
-
command: "bun",
|
|
37
|
-
args: ["run", "dev"],
|
|
38
|
-
cwd: "ui",
|
|
39
|
-
readyPatterns: [
|
|
40
|
-
/\bready\s+built in\b/i,
|
|
41
|
-
/\bLocal:\b/i,
|
|
42
|
-
/\bcompiled\b.*successfully/i
|
|
43
|
-
],
|
|
44
|
-
errorPatterns: [/error/i, /failed to compile/i]
|
|
45
|
-
},
|
|
46
|
-
"ui-ssr": {
|
|
47
|
-
name: "ui-ssr",
|
|
48
|
-
command: "bun",
|
|
49
|
-
args: ["run", "dev:ssr"],
|
|
50
|
-
cwd: "ui",
|
|
51
|
-
readyPatterns: [/\bready\s+built in\b/i, /\bcompiled\b.*successfully/i],
|
|
52
|
-
errorPatterns: [/error/i, /failed/i]
|
|
53
|
-
},
|
|
54
|
-
api: {
|
|
55
|
-
name: "api",
|
|
56
|
-
command: "bun",
|
|
57
|
-
args: ["run", "dev"],
|
|
58
|
-
cwd: "api",
|
|
59
|
-
readyPatterns: [
|
|
60
|
-
/ready in/i,
|
|
61
|
-
/compiled.*successfully/i,
|
|
62
|
-
/listening/i,
|
|
63
|
-
/started/i
|
|
64
|
-
],
|
|
65
|
-
errorPatterns: [/error/i, /failed/i]
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
function getProcessConfig(pkg, env, portOverride, bosConfig, runtimeConfig) {
|
|
69
|
-
if (pkg === "auth") {
|
|
70
|
-
const authConfig = runtimeConfig?.auth;
|
|
71
|
-
if (!authConfig?.localPath || authConfig.source !== "local") return null;
|
|
72
|
-
const port = portOverride ?? authConfig.port ?? (authConfig.url ? require_config.parsePort(authConfig.url) : 3020);
|
|
73
|
-
return {
|
|
74
|
-
name: "auth",
|
|
75
|
-
command: "bun",
|
|
76
|
-
args: ["run", "dev"],
|
|
77
|
-
cwd: authConfig.localPath,
|
|
78
|
-
port,
|
|
79
|
-
readyPatterns: [
|
|
80
|
-
/ready in/i,
|
|
81
|
-
/compiled.*successfully/i,
|
|
82
|
-
/listening/i,
|
|
83
|
-
/started/i
|
|
84
|
-
],
|
|
85
|
-
errorPatterns: [/error/i, /failed/i],
|
|
86
|
-
env
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
if (pkg.startsWith("plugin:")) {
|
|
90
|
-
const pluginId = pkg.slice(7);
|
|
91
|
-
const pluginConfig = runtimeConfig?.plugins?.[pluginId] ?? null;
|
|
92
|
-
const localPath = pluginConfig?.localPath;
|
|
93
|
-
if (!localPath || pluginConfig?.source !== "local") return null;
|
|
94
|
-
return {
|
|
95
|
-
name: pkg,
|
|
96
|
-
command: "bun",
|
|
97
|
-
args: ["run", "dev"],
|
|
98
|
-
cwd: localPath,
|
|
99
|
-
port: portOverride ?? pluginConfig?.port ?? (pluginConfig?.url ? require_config.parsePort(pluginConfig.url) : 0),
|
|
100
|
-
readyPatterns: [
|
|
101
|
-
/ready in/i,
|
|
102
|
-
/compiled.*successfully/i,
|
|
103
|
-
/listening/i,
|
|
104
|
-
/started/i
|
|
105
|
-
],
|
|
106
|
-
errorPatterns: [/error/i, /failed/i],
|
|
107
|
-
env
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
const base = processConfigBases[pkg];
|
|
111
|
-
if (!base) return null;
|
|
112
|
-
let port;
|
|
113
|
-
if (pkg === "host") port = portOverride ?? (runtimeConfig?.hostUrl ? require_config.parsePort(runtimeConfig.hostUrl) : bosConfig ? require_config.getHostDevelopmentPort(bosConfig.app.host.development) : 3e3);
|
|
114
|
-
else if (pkg === "ui") port = runtimeConfig?.ui.port ?? (runtimeConfig?.ui.url ? require_config.parsePort(runtimeConfig.ui.url) : 3002);
|
|
115
|
-
else if (pkg === "ui-ssr") port = runtimeConfig?.ui.ssrUrl ? require_config.parsePort(runtimeConfig.ui.ssrUrl) : runtimeConfig?.ui.port ? runtimeConfig.ui.port + 1 : 3003;
|
|
116
|
-
else if (pkg === "api") port = runtimeConfig?.api.port ?? (runtimeConfig?.api.url ? require_config.parsePort(runtimeConfig.api.url) : 3014);
|
|
117
|
-
else port = 0;
|
|
118
|
-
const cwd = pkg === "ui" ? runtimeConfig?.ui.localPath ?? base.cwd : pkg === "api" ? runtimeConfig?.api.localPath ?? base.cwd : base.cwd;
|
|
119
|
-
return {
|
|
120
|
-
...base,
|
|
121
|
-
cwd,
|
|
122
|
-
port,
|
|
123
|
-
env
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
10
|
const stripAnsi = (input) => {
|
|
127
11
|
const ESC = String.fromCharCode(27);
|
|
128
12
|
const BEL = String.fromCharCode(7);
|
|
129
13
|
return input.replace(new RegExp(`${ESC}\\][^${BEL}]*${BEL}`, "g"), "").replace(new RegExp(`${ESC}\\[[0-?]*[ -/]*[@-~]`, "g"), "");
|
|
130
14
|
};
|
|
131
|
-
const probeHttpOk =
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
const probeTcpOpen = async (port, timeoutMs = 250) => {
|
|
143
|
-
return new Promise((resolve) => {
|
|
144
|
-
const socket = (0, node_net.createConnection)({
|
|
145
|
-
host: "127.0.0.1",
|
|
146
|
-
port
|
|
147
|
-
});
|
|
148
|
-
const timer = setTimeout(() => {
|
|
149
|
-
socket.destroy();
|
|
150
|
-
resolve(false);
|
|
151
|
-
}, timeoutMs);
|
|
152
|
-
socket.once("connect", () => {
|
|
15
|
+
const probeHttpOk = (url, timeoutMs = 400) => effect.Effect.tryPromise({
|
|
16
|
+
try: async () => {
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
19
|
+
try {
|
|
20
|
+
return (await fetch(url, { signal: controller.signal })).ok;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
} finally {
|
|
153
24
|
clearTimeout(timer);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
catch: () => false
|
|
28
|
+
});
|
|
29
|
+
const probeTcpOpen = (port, timeoutMs = 250) => effect.Effect.async((resume) => {
|
|
30
|
+
const socket = (0, node_net.createConnection)({
|
|
31
|
+
host: "127.0.0.1",
|
|
32
|
+
port
|
|
161
33
|
});
|
|
162
|
-
|
|
163
|
-
|
|
34
|
+
const timer = setTimeout(() => {
|
|
35
|
+
socket.destroy();
|
|
36
|
+
resume(effect.Effect.succeed(false));
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
socket.once("connect", () => {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
socket.destroy();
|
|
41
|
+
resume(effect.Effect.succeed(true));
|
|
42
|
+
});
|
|
43
|
+
socket.once("error", () => {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
resume(effect.Effect.succeed(false));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
const detectStatus = (line, descriptor) => {
|
|
164
49
|
const cleanLine = stripAnsi(line);
|
|
165
|
-
|
|
50
|
+
const errorPatterns = descriptor.errorPatterns ?? [];
|
|
51
|
+
const readyPatterns = descriptor.readyPatterns ?? [];
|
|
52
|
+
for (const pattern of errorPatterns) if (pattern.test(cleanLine)) return {
|
|
166
53
|
status: "error",
|
|
167
54
|
isError: true
|
|
168
55
|
};
|
|
169
|
-
for (const pattern of
|
|
56
|
+
for (const pattern of readyPatterns) if (pattern.test(cleanLine)) return {
|
|
170
57
|
status: "ready",
|
|
171
58
|
isError: false
|
|
172
59
|
};
|
|
173
60
|
return null;
|
|
174
61
|
};
|
|
175
|
-
const killProcessTree = (pid) => effect.Effect.gen(function* () {
|
|
176
|
-
const killSignal = (signal) => effect.Effect.try({
|
|
177
|
-
try: () => {
|
|
178
|
-
process.kill(-pid, signal);
|
|
179
|
-
},
|
|
180
|
-
catch: () => null
|
|
181
|
-
}).pipe(effect.Effect.ignore);
|
|
182
|
-
const killDirect = (signal) => effect.Effect.try({
|
|
183
|
-
try: () => {
|
|
184
|
-
process.kill(pid, signal);
|
|
185
|
-
},
|
|
186
|
-
catch: () => null
|
|
187
|
-
}).pipe(effect.Effect.ignore);
|
|
188
|
-
const isRunning = () => effect.Effect.try({
|
|
189
|
-
try: () => {
|
|
190
|
-
process.kill(pid, 0);
|
|
191
|
-
return true;
|
|
192
|
-
},
|
|
193
|
-
catch: () => false
|
|
194
|
-
});
|
|
195
|
-
yield* killSignal("SIGTERM");
|
|
196
|
-
yield* killDirect("SIGTERM");
|
|
197
|
-
yield* effect.Effect.sleep("200 millis");
|
|
198
|
-
if (yield* isRunning()) {
|
|
199
|
-
yield* killSignal("SIGKILL");
|
|
200
|
-
yield* killDirect("SIGKILL");
|
|
201
|
-
yield* effect.Effect.sleep("100 millis");
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
62
|
const patchConsole = (name, callbacks) => {
|
|
205
63
|
const originalLog = console.log;
|
|
206
64
|
const originalError = console.error;
|
|
@@ -228,14 +86,14 @@ const patchConsole = (name, callbacks) => {
|
|
|
228
86
|
console.info = originalInfo;
|
|
229
87
|
};
|
|
230
88
|
};
|
|
231
|
-
const spawnRemoteHost = (
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
if (
|
|
235
|
-
callbacks.onStatus(
|
|
236
|
-
callbacks.onLog(
|
|
237
|
-
const restoreConsole = patchConsole(
|
|
238
|
-
callbacks.onLog(
|
|
89
|
+
const spawnRemoteHost = (descriptor, callbacks) => effect.Effect.gen(function* () {
|
|
90
|
+
const runtimeConfig = yield* require_service_descriptor.DevRuntimeConfig;
|
|
91
|
+
const remoteUrl = descriptor.remoteUrl;
|
|
92
|
+
if (!remoteUrl) return yield* effect.Effect.fail(/* @__PURE__ */ new Error("remoteUrl not provided on host descriptor"));
|
|
93
|
+
callbacks.onStatus(descriptor.key, "starting");
|
|
94
|
+
callbacks.onLog(descriptor.key, `Remote: ${remoteUrl}`);
|
|
95
|
+
const restoreConsole = patchConsole(descriptor.key, callbacks);
|
|
96
|
+
callbacks.onLog(descriptor.key, "Loading Module Federation runtime...");
|
|
239
97
|
const mfRuntime = yield* effect.Effect.tryPromise({
|
|
240
98
|
try: () => import("@module-federation/enhanced/runtime"),
|
|
241
99
|
catch: (e) => /* @__PURE__ */ new Error(`Failed to load MF runtime: ${e}`)
|
|
@@ -272,24 +130,24 @@ const spawnRemoteHost = (config, callbacks, runtimeConfig) => effect.Effect.gen(
|
|
|
272
130
|
name: "host",
|
|
273
131
|
entry: entryUrl
|
|
274
132
|
}]);
|
|
275
|
-
callbacks.onLog(
|
|
133
|
+
callbacks.onLog(descriptor.key, `Loading host from ${entryUrl}...`);
|
|
276
134
|
const hostModule = yield* effect.Effect.tryPromise({
|
|
277
135
|
try: () => mf.loadRemote("host/Server"),
|
|
278
136
|
catch: (e) => /* @__PURE__ */ new Error(`Failed to load host module: ${e}`)
|
|
279
137
|
});
|
|
280
138
|
if (!hostModule?.runServer) return yield* effect.Effect.fail(/* @__PURE__ */ new Error("Host module does not export runServer function"));
|
|
281
|
-
callbacks.onLog(
|
|
139
|
+
callbacks.onLog(descriptor.key, "Starting server...");
|
|
282
140
|
const serverHandle = hostModule.runServer({ config: runtimeConfig });
|
|
283
141
|
yield* effect.Effect.tryPromise({
|
|
284
142
|
try: () => serverHandle.ready,
|
|
285
143
|
catch: (e) => /* @__PURE__ */ new Error(`Server failed to start: ${e}`)
|
|
286
144
|
});
|
|
287
|
-
callbacks.onStatus(
|
|
145
|
+
callbacks.onStatus(descriptor.key, "ready");
|
|
288
146
|
return {
|
|
289
|
-
name:
|
|
147
|
+
name: descriptor.key,
|
|
290
148
|
pid: process.pid,
|
|
291
149
|
kill: effect.Effect.gen(function* () {
|
|
292
|
-
callbacks.onLog(
|
|
150
|
+
callbacks.onLog(descriptor.key, "Shutting down remote host...");
|
|
293
151
|
restoreConsole();
|
|
294
152
|
yield* effect.Effect.tryPromise({
|
|
295
153
|
try: () => serverHandle.shutdown(),
|
|
@@ -300,56 +158,44 @@ const spawnRemoteHost = (config, callbacks, runtimeConfig) => effect.Effect.gen(
|
|
|
300
158
|
waitForExit: effect.Effect.never
|
|
301
159
|
};
|
|
302
160
|
});
|
|
303
|
-
const spawnDevProcess = (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const
|
|
161
|
+
const spawnDevProcess = (descriptor, callbacks) => effect.Effect.gen(function* () {
|
|
162
|
+
const runtimeConfig = yield* require_service_descriptor.DevRuntimeConfig;
|
|
163
|
+
if (!descriptor.localPath) return yield* effect.Effect.fail(/* @__PURE__ */ new Error(`No localPath for local service: ${descriptor.key}`));
|
|
164
|
+
const fullCwd = descriptor.localPath;
|
|
165
|
+
const command = descriptor.command ?? "bun";
|
|
166
|
+
const args = descriptor.args ?? ["run", "dev"];
|
|
167
|
+
const port = descriptor.port ?? descriptor.defaultPort;
|
|
168
|
+
const name = descriptor.key;
|
|
311
169
|
const readyDeferred = yield* effect.Deferred.make();
|
|
312
170
|
const statusRef = yield* effect.Ref.make("starting");
|
|
313
|
-
callbacks.onStatus(
|
|
171
|
+
callbacks.onStatus(name, "starting");
|
|
314
172
|
const envVars = {
|
|
315
173
|
...process.env,
|
|
316
|
-
...config.env,
|
|
317
174
|
FORCE_COLOR: "1",
|
|
318
|
-
...
|
|
175
|
+
...port > 0 ? { PORT: String(port) } : {}
|
|
319
176
|
};
|
|
320
|
-
if (
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
cwd: fullCwd,
|
|
324
|
-
env: envVars,
|
|
325
|
-
stdio: [
|
|
326
|
-
"inherit",
|
|
327
|
-
"pipe",
|
|
328
|
-
"pipe"
|
|
329
|
-
]
|
|
330
|
-
});
|
|
177
|
+
if (name === "host") envVars.BOS_RUNTIME_CONFIG = JSON.stringify(runtimeConfig);
|
|
178
|
+
const cmd = _effect_platform.Command.make(command, ...args).pipe(_effect_platform.Command.workingDirectory(fullCwd), _effect_platform.Command.env(envVars));
|
|
179
|
+
const proc = yield* _effect_platform.Command.start(cmd);
|
|
331
180
|
const markReady = effect.Effect.gen(function* () {
|
|
332
181
|
const currentStatus = yield* effect.Ref.get(statusRef);
|
|
333
182
|
if (currentStatus === "ready" || currentStatus === "error") return;
|
|
334
183
|
yield* effect.Ref.set(statusRef, "ready");
|
|
335
|
-
callbacks.onStatus(
|
|
184
|
+
callbacks.onStatus(name, "ready");
|
|
336
185
|
yield* effect.Deferred.succeed(readyDeferred, void 0).pipe(effect.Effect.ignore);
|
|
337
186
|
});
|
|
338
|
-
if (
|
|
339
|
-
const
|
|
340
|
-
const url = `http://127.0.0.1:${config.port}${readinessPath}`;
|
|
187
|
+
if (port > 0) {
|
|
188
|
+
const url = `http://127.0.0.1:${port}${descriptor.readinessPath}`;
|
|
341
189
|
yield* effect.Effect.forkScoped(effect.Effect.gen(function* () {
|
|
342
190
|
const deadline = Date.now() + 9e4;
|
|
343
191
|
while (Date.now() < deadline) {
|
|
344
192
|
const status = yield* effect.Ref.get(statusRef);
|
|
345
193
|
if (status === "ready" || status === "error") return;
|
|
346
|
-
if (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
catch: () => false
|
|
352
|
-
})) {
|
|
194
|
+
if (yield* probeHttpOk(url)) {
|
|
195
|
+
yield* markReady;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (yield* probeTcpOpen(port)) {
|
|
353
199
|
yield* markReady;
|
|
354
200
|
return;
|
|
355
201
|
}
|
|
@@ -357,120 +203,124 @@ const spawnDevProcess = (config, callbacks, runtimeConfig, registry) => effect.E
|
|
|
357
203
|
}
|
|
358
204
|
}));
|
|
359
205
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
port: config.port,
|
|
364
|
-
startedAt: Date.now(),
|
|
365
|
-
command: [config.command, ...config.args].join(" ")
|
|
366
|
-
});
|
|
367
|
-
yield* effect.Effect.forkScoped(effect.Effect.promise(() => proc.exited).pipe(effect.Effect.andThen((code) => effect.Effect.gen(function* () {
|
|
368
|
-
if (registry && proc.pid) yield* registry.untrack(proc.pid).pipe(effect.Effect.ignore);
|
|
206
|
+
const pid = Number(proc.pid);
|
|
207
|
+
yield* effect.Effect.forkScoped(effect.Effect.gen(function* () {
|
|
208
|
+
const exitCode = yield* proc.exitCode;
|
|
369
209
|
if ((yield* effect.Ref.get(statusRef)) === "ready") return;
|
|
370
|
-
callbacks.onLog(
|
|
210
|
+
callbacks.onLog(name, `Process exited before ready (exit code: ${exitCode})`, true);
|
|
371
211
|
yield* effect.Ref.set(statusRef, "error");
|
|
372
|
-
callbacks.onStatus(
|
|
373
|
-
yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error(`Process exited before ready: ${
|
|
374
|
-
}))
|
|
212
|
+
callbacks.onStatus(name, "error");
|
|
213
|
+
yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error(`Process exited before ready: ${name}`)).pipe(effect.Effect.ignore);
|
|
214
|
+
}));
|
|
375
215
|
const handleLine = (line, isStderr) => effect.Effect.gen(function* () {
|
|
376
216
|
if (!line.trim()) return;
|
|
377
|
-
|
|
217
|
+
const cleanLine = stripAnsi(line);
|
|
218
|
+
const looksLikeError = isStderr && /^(error|fail|fatal|exception|unhandled|reject)/i.test(cleanLine) && !/^\$/.test(cleanLine);
|
|
219
|
+
callbacks.onLog(name, line, looksLikeError);
|
|
378
220
|
if ((yield* effect.Ref.get(statusRef)) === "ready") return;
|
|
379
|
-
const detected = detectStatus(line,
|
|
221
|
+
const detected = detectStatus(line, descriptor);
|
|
380
222
|
if (detected) {
|
|
381
223
|
yield* effect.Ref.set(statusRef, detected.status);
|
|
382
|
-
callbacks.onStatus(
|
|
224
|
+
callbacks.onStatus(name, detected.status);
|
|
383
225
|
if (detected.status === "ready" || detected.status === "error") if (detected.status === "ready") yield* effect.Deferred.succeed(readyDeferred, void 0).pipe(effect.Effect.ignore);
|
|
384
|
-
else yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error(`Process failed: ${
|
|
226
|
+
else yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error(`Process failed: ${name}`)).pipe(effect.Effect.ignore);
|
|
385
227
|
}
|
|
386
228
|
});
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
229
|
+
yield* effect.Effect.forkScoped(effect.Stream.runForEach((line) => handleLine(line, false))(effect.Stream.splitLines(effect.Stream.decodeText(proc.stdout, "utf-8"))));
|
|
230
|
+
yield* effect.Effect.forkScoped(effect.Stream.runForEach((line) => handleLine(line, true))(effect.Stream.splitLines(effect.Stream.decodeText(proc.stderr, "utf-8"))));
|
|
231
|
+
return {
|
|
232
|
+
name,
|
|
233
|
+
pid,
|
|
234
|
+
kill: effect.Effect.gen(function* () {
|
|
235
|
+
const result = yield* proc.kill("SIGTERM").pipe(effect.Effect.timeout("3 seconds"), effect.Effect.option);
|
|
236
|
+
if (effect.Option.isNone(result)) {
|
|
237
|
+
const pid = Number(proc.pid);
|
|
238
|
+
yield* effect.Effect.try(() => process.kill(-pid, "SIGKILL")).pipe(effect.Effect.ignore);
|
|
239
|
+
yield* effect.Effect.sleep("250 millis");
|
|
240
|
+
}
|
|
241
|
+
}).pipe(effect.Effect.ignore),
|
|
242
|
+
waitForReady: effect.Deferred.await(readyDeferred),
|
|
243
|
+
waitForExit: proc.exitCode
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
const spawnRemoteProbe = (pkg, descriptor, callbacks) => effect.Effect.gen(function* () {
|
|
247
|
+
callbacks.onStatus(pkg, "starting");
|
|
248
|
+
const readyDeferred = yield* effect.Deferred.make();
|
|
249
|
+
const statusRef = yield* effect.Ref.make("starting");
|
|
250
|
+
const markReady = effect.Effect.gen(function* () {
|
|
251
|
+
yield* effect.Ref.set(statusRef, "ready");
|
|
252
|
+
yield* effect.Deferred.succeed(readyDeferred, void 0);
|
|
253
|
+
callbacks.onStatus(pkg, "ready", "loaded");
|
|
254
|
+
});
|
|
255
|
+
const markError = effect.Effect.gen(function* () {
|
|
256
|
+
yield* effect.Ref.set(statusRef, "error");
|
|
257
|
+
yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error(`Remote ${pkg} unreachable`));
|
|
258
|
+
callbacks.onStatus(pkg, "error", "unreachable");
|
|
259
|
+
});
|
|
260
|
+
const baseUrl = descriptor.url.replace(/\/$/, "");
|
|
261
|
+
const manifestUrl = `${baseUrl}/mf-manifest.json`;
|
|
262
|
+
const entryUrl = `${baseUrl}${descriptor.readinessPath}`;
|
|
263
|
+
const probeUrl = descriptor.readinessPath === "/health" ? `${baseUrl}/health` : manifestUrl;
|
|
264
|
+
yield* effect.Effect.forkScoped(effect.Effect.gen(function* () {
|
|
265
|
+
const deadline = Date.now() + 6e4;
|
|
266
|
+
while (Date.now() < deadline) {
|
|
267
|
+
const status = yield* effect.Ref.get(statusRef);
|
|
268
|
+
if (status === "ready" || status === "error") return;
|
|
269
|
+
if (yield* probeHttpOk(probeUrl, 400)) {
|
|
270
|
+
yield* markReady;
|
|
400
271
|
return;
|
|
401
272
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
buffer = lines.pop() ?? "";
|
|
405
|
-
for (const line of lines) effect.Effect.runSync(handleLine(line, false));
|
|
406
|
-
return pump();
|
|
407
|
-
});
|
|
408
|
-
pump().then(() => {
|
|
409
|
-
if (active) resume(effect.Effect.void);
|
|
410
|
-
});
|
|
411
|
-
return effect.Effect.sync(() => {
|
|
412
|
-
active = false;
|
|
413
|
-
reader.cancel();
|
|
414
|
-
});
|
|
415
|
-
}));
|
|
416
|
-
const stderrFiber = yield* effect.Effect.forkScoped(effect.Effect.async((resume) => {
|
|
417
|
-
if (!proc.stderr) {
|
|
418
|
-
resume(effect.Effect.void);
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
const reader = proc.stderr.getReader();
|
|
422
|
-
let buffer = "";
|
|
423
|
-
let active = true;
|
|
424
|
-
const pump = () => reader.read().then(({ done, value }) => {
|
|
425
|
-
if (!active) return;
|
|
426
|
-
if (done) {
|
|
427
|
-
if (buffer) effect.Effect.runSync(handleLine(buffer, true));
|
|
273
|
+
if (yield* probeHttpOk(entryUrl, 400)) {
|
|
274
|
+
yield* markReady;
|
|
428
275
|
return;
|
|
429
276
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
for (const line of lines) effect.Effect.runSync(handleLine(line, true));
|
|
434
|
-
return pump();
|
|
435
|
-
});
|
|
436
|
-
pump().then(() => {
|
|
437
|
-
if (active) resume(effect.Effect.void);
|
|
438
|
-
});
|
|
439
|
-
return effect.Effect.sync(() => {
|
|
440
|
-
active = false;
|
|
441
|
-
reader.cancel();
|
|
442
|
-
});
|
|
277
|
+
yield* effect.Effect.sleep("500 millis");
|
|
278
|
+
}
|
|
279
|
+
if ((yield* effect.Ref.get(statusRef)) !== "ready") yield* markError;
|
|
443
280
|
}));
|
|
444
281
|
return {
|
|
445
|
-
name:
|
|
446
|
-
pid:
|
|
447
|
-
kill:
|
|
448
|
-
|
|
449
|
-
yield* effect.
|
|
450
|
-
try {
|
|
451
|
-
proc.kill("SIGKILL");
|
|
452
|
-
} catch {}
|
|
282
|
+
name: pkg,
|
|
283
|
+
pid: void 0,
|
|
284
|
+
kill: effect.Effect.gen(function* () {
|
|
285
|
+
yield* effect.Ref.set(statusRef, "error");
|
|
286
|
+
yield* effect.Deferred.fail(readyDeferred, /* @__PURE__ */ new Error("Killed")).pipe(effect.Effect.ignore);
|
|
453
287
|
}),
|
|
454
288
|
waitForReady: effect.Deferred.await(readyDeferred),
|
|
455
|
-
waitForExit: effect.Effect.
|
|
456
|
-
yield* effect.Fiber.joinAll([stdoutFiber, stderrFiber]);
|
|
457
|
-
return yield* effect.Effect.promise(() => proc.exited);
|
|
458
|
-
})
|
|
289
|
+
waitForExit: effect.Effect.never
|
|
459
290
|
};
|
|
460
291
|
});
|
|
461
|
-
const makeDevProcess = (pkg,
|
|
462
|
-
const
|
|
463
|
-
if (!
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
292
|
+
const makeDevProcess = (pkg, callbacks, portOverride) => effect.Effect.gen(function* () {
|
|
293
|
+
const descriptor = (yield* require_service_descriptor.ServiceDescriptorMap).get(pkg);
|
|
294
|
+
if (!descriptor) {
|
|
295
|
+
callbacks.onStatus(pkg, "ready", "Remote");
|
|
296
|
+
return {
|
|
297
|
+
name: pkg,
|
|
298
|
+
pid: void 0,
|
|
299
|
+
kill: effect.Effect.void,
|
|
300
|
+
waitForReady: effect.Effect.void,
|
|
301
|
+
waitForExit: effect.Effect.never
|
|
302
|
+
};
|
|
467
303
|
}
|
|
468
|
-
return yield*
|
|
304
|
+
if (pkg === "host" && descriptor.source === "remote") return yield* spawnRemoteHost(descriptor, callbacks);
|
|
305
|
+
if (descriptor.source === "remote" || !descriptor.localPath) return yield* spawnRemoteProbe(pkg, descriptor, callbacks);
|
|
306
|
+
return yield* spawnDevProcess(portOverride ? {
|
|
307
|
+
...descriptor,
|
|
308
|
+
port: portOverride
|
|
309
|
+
} : descriptor, callbacks);
|
|
469
310
|
});
|
|
311
|
+
function getProcessStates(packages, services, portOverride) {
|
|
312
|
+
return packages.map((pkg) => {
|
|
313
|
+
const descriptor = services.get(pkg);
|
|
314
|
+
return {
|
|
315
|
+
name: pkg,
|
|
316
|
+
status: "pending",
|
|
317
|
+
port: portOverride && pkg === "host" ? portOverride : descriptor?.port ?? descriptor?.defaultPort ?? 0,
|
|
318
|
+
source: descriptor?.source
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
}
|
|
470
322
|
|
|
471
323
|
//#endregion
|
|
472
|
-
exports.
|
|
324
|
+
exports.getProcessStates = getProcessStates;
|
|
473
325
|
exports.makeDevProcess = makeDevProcess;
|
|
474
|
-
exports.spawnDevProcess = spawnDevProcess;
|
|
475
|
-
exports.spawnRemoteHost = spawnRemoteHost;
|
|
476
326
|
//# sourceMappingURL=orchestrator.cjs.map
|