@holo-js/cli 0.1.9 → 0.2.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/bin/holo.mjs +179 -81
- package/dist/broadcast-III5MB3R.mjs +203 -0
- package/dist/broadcast-ZIFYFOUQ.mjs +203 -0
- package/dist/{cache-ETOIQ5IG.mjs → cache-634WUR3T.mjs} +6 -6
- package/dist/cache-7J7DIOP6.mjs +66 -0
- package/dist/{cache-migrations-2GGI4TJK.mjs → cache-migrations-2NBEUF2T.mjs} +50 -30
- package/dist/cache-migrations-S2LJMDOQ.mjs +173 -0
- package/dist/{chunk-WRZFATUT.mjs → chunk-4OHJC3GL.mjs} +232 -143
- package/dist/{chunk-ASTSSSL2.mjs → chunk-5TEH2QPK.mjs} +99 -122
- package/dist/{chunk-F4MT6GBK.mjs → chunk-FGQ2I2YH.mjs} +1 -1
- package/dist/chunk-I7QBCEV7.mjs +33 -0
- package/dist/{chunk-R6BWRY3E.mjs → chunk-ILU426CF.mjs} +3 -1
- package/dist/{chunk-IMOGEKB4.mjs → chunk-J76GH2DR.mjs} +229 -119
- package/dist/{chunk-HB4Q7VYK.mjs → chunk-KS5TWO75.mjs} +30 -273
- package/dist/{chunk-57SJ566R.mjs → chunk-LBJAJLKU.mjs} +1 -1
- package/dist/{chunk-BAFQ2GOA.mjs → chunk-LXGQCG56.mjs} +1 -1
- package/dist/chunk-MCVRN7KX.mjs +3308 -0
- package/dist/chunk-SFRAGRHY.mjs +472 -0
- package/dist/{chunk-7JR73TOH.mjs → chunk-VP2E62DF.mjs} +36 -25
- package/dist/{chunk-5EU32E7X.mjs → chunk-VRGB6DIS.mjs} +116 -12
- package/dist/{chunk-SRPGIWCF.mjs → chunk-YEFJBN56.mjs} +2 -2
- package/dist/{config-ARLE6PKR.mjs → config-MD27U4FM.mjs} +3 -3
- package/dist/{dev-6RG5SSZ7.mjs → dev-M2GGURAX.mjs} +9 -7
- package/dist/dev-PBNFQK6Y.mjs +44 -0
- package/dist/{discovery-FCVGQQVD.mjs → discovery-GWTBF5RZ.mjs} +3 -3
- package/dist/{generators-UI2LJK3O.mjs → generators-BZJ53PUU.mjs} +13 -36
- package/dist/generators-DEPLONDJ.mjs +520 -0
- package/dist/index.mjs +181 -83
- package/dist/{media-migrations-JQSDCC7S.mjs → media-migrations-5EISZBSD.mjs} +9 -20
- package/dist/media-migrations-NMUWBEKE.mjs +106 -0
- package/dist/{queue-BY3PLH4I.mjs → queue-FRAVPNFJ.mjs} +12 -12
- package/dist/queue-GY7BWGTX.mjs +625 -0
- package/dist/{queue-migrations-YZUKEZK7.mjs → queue-migrations-J7YPIKRB.mjs} +13 -12
- package/dist/queue-migrations-O24ERNFF.mjs +167 -0
- package/dist/{runtime-BI343WHS.mjs → runtime-2AA7ZLJ6.mjs} +9 -9
- package/dist/{runtime-ZKD6URAV.mjs → runtime-GSXF4NB3.mjs} +1 -1
- package/dist/runtime-HGK2MWSC.mjs +57 -0
- package/dist/runtime-worker.d.ts +2 -0
- package/dist/runtime-worker.mjs +276 -0
- package/dist/{scaffold-UBOS2NZR.mjs → scaffold-DEOTRALR.mjs} +9 -5
- package/dist/scaffold-Y232IGYS.mjs +139 -0
- package/dist/{security-TYPVOYGF.mjs → security-MZW2CJKS.mjs} +6 -6
- package/dist/security-XVG673UR.mjs +71 -0
- package/package.json +9 -7
- package/dist/broadcast-VR46UZEL.mjs +0 -84
- package/dist/chunk-ZXDU7RHU.mjs +0 -9
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import {
|
|
2
|
+
prepareProjectDiscovery
|
|
3
|
+
} from "./chunk-VP2E62DF.mjs";
|
|
4
|
+
import {
|
|
5
|
+
syncManagedDriverDependencies
|
|
6
|
+
} from "./chunk-MCVRN7KX.mjs";
|
|
7
|
+
import {
|
|
8
|
+
ensureGeneratedSchemaPlaceholder,
|
|
9
|
+
ensureProjectConfig
|
|
10
|
+
} from "./chunk-YEFJBN56.mjs";
|
|
11
|
+
import {
|
|
12
|
+
renderFrameworkRunner
|
|
13
|
+
} from "./chunk-J76GH2DR.mjs";
|
|
14
|
+
import {
|
|
15
|
+
readTextFile,
|
|
16
|
+
writeTextFile
|
|
17
|
+
} from "./chunk-ILU426CF.mjs";
|
|
18
|
+
|
|
19
|
+
// src/dev.ts
|
|
20
|
+
import { spawnSync, spawn } from "child_process";
|
|
21
|
+
import { watch } from "fs";
|
|
22
|
+
import { readdir, stat } from "fs/promises";
|
|
23
|
+
import { join, dirname, relative, resolve } from "path";
|
|
24
|
+
import { readFile } from "fs/promises";
|
|
25
|
+
async function fileExists(path) {
|
|
26
|
+
try {
|
|
27
|
+
await stat(path);
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function resolveProjectPackageManager(projectRoot) {
|
|
34
|
+
const packageJsonPath = join(projectRoot, "package.json");
|
|
35
|
+
const packageJson = await readTextFile(packageJsonPath);
|
|
36
|
+
if (packageJson) {
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(packageJson);
|
|
39
|
+
const packageManager = typeof parsed.packageManager === "string" ? parsed.packageManager.split("@")[0] : void 0;
|
|
40
|
+
if (packageManager === "bun" || packageManager === "npm" || packageManager === "pnpm" || packageManager === "yarn") {
|
|
41
|
+
return packageManager;
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (await fileExists(join(projectRoot, "bun.lock"))) {
|
|
47
|
+
return "bun";
|
|
48
|
+
}
|
|
49
|
+
if (await fileExists(join(projectRoot, "pnpm-lock.yaml"))) {
|
|
50
|
+
return "pnpm";
|
|
51
|
+
}
|
|
52
|
+
if (await fileExists(join(projectRoot, "yarn.lock"))) {
|
|
53
|
+
return "yarn";
|
|
54
|
+
}
|
|
55
|
+
if (await fileExists(join(projectRoot, "package-lock.json"))) {
|
|
56
|
+
return "npm";
|
|
57
|
+
}
|
|
58
|
+
return "bun";
|
|
59
|
+
}
|
|
60
|
+
async function resolvePackageManagerCommand(projectRoot, scriptName) {
|
|
61
|
+
const packageManager = await resolveProjectPackageManager(projectRoot);
|
|
62
|
+
return {
|
|
63
|
+
command: packageManager,
|
|
64
|
+
args: ["run", scriptName]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function resolvePackageManagerInstallInvocation(projectRoot) {
|
|
68
|
+
const packageManager = await resolveProjectPackageManager(projectRoot);
|
|
69
|
+
return {
|
|
70
|
+
command: packageManager,
|
|
71
|
+
args: ["install"]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function runProjectLifecycleScript(io, projectRoot, scriptName, spawn2 = spawnSync) {
|
|
75
|
+
const invocation = await resolvePackageManagerCommand(projectRoot, scriptName);
|
|
76
|
+
const result = spawn2(invocation.command, [...invocation.args], {
|
|
77
|
+
cwd: projectRoot,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
env: process.env
|
|
80
|
+
});
|
|
81
|
+
if (result.stdout) {
|
|
82
|
+
io.stdout.write(result.stdout);
|
|
83
|
+
}
|
|
84
|
+
if (result.stderr) {
|
|
85
|
+
io.stderr.write(result.stderr);
|
|
86
|
+
}
|
|
87
|
+
if (result.status !== 0) {
|
|
88
|
+
throw new Error(result.stderr?.trim() || result.stdout?.trim() || `Project script "${scriptName}" failed.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function runProjectStartServer(io, projectRoot, spawnProcess = spawn) {
|
|
92
|
+
const runnerPath = join(projectRoot, ".holo-js/framework/run.mjs");
|
|
93
|
+
const child = spawnProcess(process.execPath, [runnerPath, "start"], {
|
|
94
|
+
cwd: projectRoot,
|
|
95
|
+
env: process.env,
|
|
96
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
97
|
+
});
|
|
98
|
+
child.stdout?.on("data", (chunk) => io.stdout.write(chunk));
|
|
99
|
+
child.stderr?.on("data", (chunk) => io.stderr.write(chunk));
|
|
100
|
+
if (child.stdin) {
|
|
101
|
+
io.stdin.pipe(child.stdin);
|
|
102
|
+
}
|
|
103
|
+
const result = await new Promise((resolvePromise) => {
|
|
104
|
+
child.on("error", (error) => resolvePromise({ kind: "error", error }));
|
|
105
|
+
child.on("close", (code) => resolvePromise({ kind: "close", code }));
|
|
106
|
+
});
|
|
107
|
+
if (result.kind === "error") {
|
|
108
|
+
throw result.error;
|
|
109
|
+
}
|
|
110
|
+
if (result.code !== 0) {
|
|
111
|
+
throw new Error(`Project production server failed with exit code ${result.code ?? "unknown"}.`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function runProjectDependencyInstall(io, projectRoot, spawn2 = spawnSync) {
|
|
115
|
+
const invocation = await resolvePackageManagerInstallInvocation(projectRoot);
|
|
116
|
+
const result = spawn2(invocation.command, [...invocation.args], {
|
|
117
|
+
cwd: projectRoot,
|
|
118
|
+
encoding: "utf8",
|
|
119
|
+
env: process.env
|
|
120
|
+
});
|
|
121
|
+
if (result.stdout) {
|
|
122
|
+
io.stdout.write(result.stdout);
|
|
123
|
+
}
|
|
124
|
+
if (result.stderr) {
|
|
125
|
+
io.stderr.write(result.stderr);
|
|
126
|
+
}
|
|
127
|
+
if (result.status !== 0) {
|
|
128
|
+
throw new Error(result.stderr?.trim() || result.stdout?.trim() || "Project dependency installation failed.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
var FRAMEWORK_SYNC_DEFINITIONS = [
|
|
132
|
+
{
|
|
133
|
+
framework: "nuxt",
|
|
134
|
+
commands: {
|
|
135
|
+
bun: ["bun", "x", "nuxt", "prepare"],
|
|
136
|
+
npm: ["npm", "exec", "--", "nuxt", "prepare"],
|
|
137
|
+
pnpm: ["pnpm", "exec", "nuxt", "prepare"],
|
|
138
|
+
yarn: ["yarn", "run", "nuxt", "prepare"]
|
|
139
|
+
},
|
|
140
|
+
errorLabel: "nuxt prepare"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
framework: "sveltekit",
|
|
144
|
+
commands: {
|
|
145
|
+
bun: ["bun", "x", "svelte-kit", "sync"],
|
|
146
|
+
npm: ["npm", "exec", "--", "svelte-kit", "sync"],
|
|
147
|
+
pnpm: ["pnpm", "exec", "svelte-kit", "sync"],
|
|
148
|
+
yarn: ["yarn", "run", "svelte-kit", "sync"]
|
|
149
|
+
},
|
|
150
|
+
errorLabel: "svelte-kit sync"
|
|
151
|
+
}
|
|
152
|
+
];
|
|
153
|
+
async function runProjectPrepare(projectRoot, io, options = {}) {
|
|
154
|
+
const project = await ensureProjectConfig(projectRoot);
|
|
155
|
+
await ensureGeneratedSchemaPlaceholder(projectRoot, project.config);
|
|
156
|
+
await prepareProjectDiscovery(projectRoot, project.config);
|
|
157
|
+
await refreshFrameworkRunner(projectRoot);
|
|
158
|
+
const syncFramework = options.syncFramework ?? true;
|
|
159
|
+
if (syncFramework) {
|
|
160
|
+
await runFrameworkSync(projectRoot, FRAMEWORK_SYNC_DEFINITIONS[0]);
|
|
161
|
+
await runFrameworkSync(projectRoot, FRAMEWORK_SYNC_DEFINITIONS[1]);
|
|
162
|
+
}
|
|
163
|
+
const updatedDependencies = await syncManagedDriverDependencies(projectRoot);
|
|
164
|
+
if (updatedDependencies && io) {
|
|
165
|
+
await runProjectDependencyInstall(io, projectRoot);
|
|
166
|
+
await prepareProjectDiscovery(projectRoot, project.config);
|
|
167
|
+
await refreshFrameworkRunner(projectRoot);
|
|
168
|
+
if (syncFramework) {
|
|
169
|
+
await runFrameworkSync(projectRoot, FRAMEWORK_SYNC_DEFINITIONS[0]);
|
|
170
|
+
await runFrameworkSync(projectRoot, FRAMEWORK_SYNC_DEFINITIONS[1]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function runProjectHotPrepare(projectRoot, io) {
|
|
175
|
+
await runProjectPrepare(projectRoot, io, { syncFramework: false });
|
|
176
|
+
}
|
|
177
|
+
async function refreshFrameworkRunner(projectRoot) {
|
|
178
|
+
const frameworkProjectPath = resolve(projectRoot, ".holo-js/framework/project.json");
|
|
179
|
+
const frameworkRunnerPath = resolve(projectRoot, ".holo-js/framework/run.mjs");
|
|
180
|
+
let framework;
|
|
181
|
+
try {
|
|
182
|
+
const content = await readFile(frameworkProjectPath, "utf8");
|
|
183
|
+
const manifest = JSON.parse(content);
|
|
184
|
+
if (manifest.framework !== "next" && manifest.framework !== "nuxt" && manifest.framework !== "sveltekit") {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
framework = manifest.framework;
|
|
188
|
+
} catch {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
await writeTextFile(frameworkRunnerPath, renderFrameworkRunner({ framework }));
|
|
192
|
+
}
|
|
193
|
+
async function runFrameworkSync(projectRoot, definition) {
|
|
194
|
+
const frameworkProjectPath = resolve(projectRoot, ".holo-js/framework/project.json");
|
|
195
|
+
try {
|
|
196
|
+
const content = await readFile(frameworkProjectPath, "utf8");
|
|
197
|
+
const manifest = JSON.parse(content);
|
|
198
|
+
if (manifest.framework !== definition.framework) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const manager = await resolveProjectPackageManager(projectRoot);
|
|
205
|
+
const invocation = definition.commands[manager];
|
|
206
|
+
const command = invocation[0];
|
|
207
|
+
const args = invocation.slice(1);
|
|
208
|
+
await new Promise((resolve2, reject) => {
|
|
209
|
+
const child = spawn(command, args, {
|
|
210
|
+
cwd: projectRoot,
|
|
211
|
+
stdio: "inherit"
|
|
212
|
+
});
|
|
213
|
+
child.on("close", (code) => {
|
|
214
|
+
if (code === 0) {
|
|
215
|
+
resolve2(void 0);
|
|
216
|
+
} else {
|
|
217
|
+
reject(new Error(`${definition.errorLabel} exited with ${code}`));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
child.on("error", reject);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function toPosixSlashes(value) {
|
|
224
|
+
return value.replaceAll("\\", "/");
|
|
225
|
+
}
|
|
226
|
+
var PACKAGE_MANIFEST_DISCOVERY_PATHS = /* @__PURE__ */ new Set([
|
|
227
|
+
"package.json",
|
|
228
|
+
"bun.lock",
|
|
229
|
+
"package-lock.json",
|
|
230
|
+
"pnpm-lock.yaml",
|
|
231
|
+
"yarn.lock"
|
|
232
|
+
]);
|
|
233
|
+
function resolveConfiguredBroadcastPath(project) {
|
|
234
|
+
const configuredPaths = project.config.paths;
|
|
235
|
+
return configuredPaths.broadcast ?? "server/broadcast";
|
|
236
|
+
}
|
|
237
|
+
function resolveConfiguredChannelsPath(project) {
|
|
238
|
+
const configuredPaths = project.config.paths;
|
|
239
|
+
return configuredPaths.channels ?? "server/channels";
|
|
240
|
+
}
|
|
241
|
+
function resolveConfiguredRealtimePath(project) {
|
|
242
|
+
const configuredPaths = project.config.paths;
|
|
243
|
+
return configuredPaths.realtime ?? "server/realtime";
|
|
244
|
+
}
|
|
245
|
+
function resolveConfiguredDiscoveryRoots(project) {
|
|
246
|
+
const authorizationPoliciesPath = project.config.paths.authorizationPolicies || "server/policies";
|
|
247
|
+
const authorizationAbilitiesPath = project.config.paths.authorizationAbilities || "server/abilities";
|
|
248
|
+
return [
|
|
249
|
+
project.config.paths.models,
|
|
250
|
+
project.config.paths.migrations,
|
|
251
|
+
project.config.paths.seeders,
|
|
252
|
+
project.config.paths.commands,
|
|
253
|
+
project.config.paths.jobs,
|
|
254
|
+
project.config.paths.events,
|
|
255
|
+
project.config.paths.listeners,
|
|
256
|
+
authorizationPoliciesPath,
|
|
257
|
+
authorizationAbilitiesPath,
|
|
258
|
+
resolveConfiguredBroadcastPath(project),
|
|
259
|
+
resolveConfiguredChannelsPath(project),
|
|
260
|
+
resolveConfiguredRealtimePath(project),
|
|
261
|
+
"config"
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
function isDiscoveryRelevantPath(filePath, project) {
|
|
265
|
+
const normalized = toPosixSlashes(filePath);
|
|
266
|
+
if (PACKAGE_MANIFEST_DISCOVERY_PATHS.has(normalized)) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
const generatedSchemaPath = toPosixSlashes(project.config.paths.generatedSchema ?? ".holo-js/generated/schema.generated.ts");
|
|
270
|
+
if (normalized === generatedSchemaPath) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
if (normalized === ".holo-js/generated" || normalized.startsWith(".holo-js/generated/")) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
if (normalized === ".env" || normalized.startsWith(".env.")) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return resolveConfiguredDiscoveryRoots(project).some((root) => normalized === root || normalized.startsWith(`${toPosixSlashes(root)}/`));
|
|
280
|
+
}
|
|
281
|
+
function isRecursiveWatchUnsupported(error) {
|
|
282
|
+
return error instanceof Error && (error.message.includes("recursive") || "code" in error && error.code === "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM");
|
|
283
|
+
}
|
|
284
|
+
function isIgnorableWatchError(error) {
|
|
285
|
+
return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "EPERM");
|
|
286
|
+
}
|
|
287
|
+
async function collectDirectoryTree(rootPath, directories) {
|
|
288
|
+
const rootStats = await stat(rootPath).catch(() => void 0);
|
|
289
|
+
if (!rootStats?.isDirectory()) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
directories.add(rootPath);
|
|
293
|
+
const entries = await readdir(rootPath, { withFileTypes: true }).catch(() => []);
|
|
294
|
+
for (const entry of entries) {
|
|
295
|
+
if (!entry.isDirectory()) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
await collectDirectoryTree(join(rootPath, entry.name), directories);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async function collectDiscoveryWatchRoots(projectRoot, project) {
|
|
302
|
+
const directories = /* @__PURE__ */ new Set();
|
|
303
|
+
const roots = [
|
|
304
|
+
projectRoot,
|
|
305
|
+
...resolveConfiguredDiscoveryRoots(project).map((root) => resolve(projectRoot, root)),
|
|
306
|
+
resolve(projectRoot, dirname(project.config.paths.generatedSchema ?? ".holo-js/generated/schema.generated.ts"))
|
|
307
|
+
];
|
|
308
|
+
for (const rootPath of roots) {
|
|
309
|
+
await collectDirectoryTree(rootPath, directories);
|
|
310
|
+
}
|
|
311
|
+
return [...directories];
|
|
312
|
+
}
|
|
313
|
+
function normalizeWatchedFilePath(projectRoot, watchedRoot, fileName) {
|
|
314
|
+
return toPosixSlashes(relative(projectRoot, resolve(watchedRoot, fileName)));
|
|
315
|
+
}
|
|
316
|
+
async function runProjectDevServer(io, projectRoot, spawnProcess = spawn, createWatcher = watch, prepare = runProjectPrepare) {
|
|
317
|
+
let project = await ensureProjectConfig(projectRoot);
|
|
318
|
+
let refreshNonRecursiveWatchers;
|
|
319
|
+
let requestChildRestart;
|
|
320
|
+
const hotPrepare = prepare === runProjectPrepare ? runProjectHotPrepare : prepare;
|
|
321
|
+
const prepareDiscovery = async (syncFramework = false) => {
|
|
322
|
+
await (syncFramework ? prepare : hotPrepare)(projectRoot, io);
|
|
323
|
+
project = await ensureProjectConfig(projectRoot);
|
|
324
|
+
await refreshNonRecursiveWatchers?.();
|
|
325
|
+
};
|
|
326
|
+
await prepareDiscovery(true);
|
|
327
|
+
let pendingPrepare;
|
|
328
|
+
let queued = false;
|
|
329
|
+
let shuttingDown = false;
|
|
330
|
+
const rerunPrepare = () => {
|
|
331
|
+
if (shuttingDown) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (pendingPrepare) {
|
|
335
|
+
queued = true;
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
pendingPrepare = prepareDiscovery().then(() => {
|
|
339
|
+
requestChildRestart?.();
|
|
340
|
+
}).catch((error) => {
|
|
341
|
+
io.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
342
|
+
`);
|
|
343
|
+
}).finally(() => {
|
|
344
|
+
pendingPrepare = void 0;
|
|
345
|
+
if (queued) {
|
|
346
|
+
queued = false;
|
|
347
|
+
rerunPrepare();
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
const closeWatchers = (() => {
|
|
352
|
+
try {
|
|
353
|
+
const watcher = createWatcher(projectRoot, { recursive: true }, (_eventType, fileName) => {
|
|
354
|
+
if (shuttingDown || typeof fileName !== "string" || !isDiscoveryRelevantPath(fileName, project)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
rerunPrepare();
|
|
358
|
+
});
|
|
359
|
+
return () => watcher.close();
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (!isRecursiveWatchUnsupported(error)) {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
const watchers = [];
|
|
365
|
+
const closeAllWatchers = () => {
|
|
366
|
+
while (watchers.length > 0) {
|
|
367
|
+
watchers.pop()?.close();
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
refreshNonRecursiveWatchers = async () => {
|
|
371
|
+
closeAllWatchers();
|
|
372
|
+
const watchRoots = await collectDiscoveryWatchRoots(projectRoot, project);
|
|
373
|
+
for (const watchRoot of watchRoots) {
|
|
374
|
+
try {
|
|
375
|
+
watchers.push(createWatcher(watchRoot, { recursive: false }, (_eventType, fileName) => {
|
|
376
|
+
if (shuttingDown || typeof fileName !== "string") {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const normalizedPath = normalizeWatchedFilePath(projectRoot, watchRoot, fileName);
|
|
380
|
+
if (!isDiscoveryRelevantPath(normalizedPath, project)) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
rerunPrepare();
|
|
384
|
+
}));
|
|
385
|
+
} catch (watchError) {
|
|
386
|
+
if (!isIgnorableWatchError(watchError)) {
|
|
387
|
+
throw watchError;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
return () => closeAllWatchers();
|
|
393
|
+
}
|
|
394
|
+
})();
|
|
395
|
+
await refreshNonRecursiveWatchers?.();
|
|
396
|
+
const invocation = await resolvePackageManagerCommand(projectRoot, "holo:dev");
|
|
397
|
+
while (!shuttingDown) {
|
|
398
|
+
const child = spawnProcess(invocation.command, [...invocation.args], {
|
|
399
|
+
cwd: projectRoot,
|
|
400
|
+
env: process.env,
|
|
401
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
402
|
+
});
|
|
403
|
+
child.stdout?.on("data", (chunk) => io.stdout.write(chunk));
|
|
404
|
+
child.stderr?.on("data", (chunk) => io.stderr.write(chunk));
|
|
405
|
+
if (child.stdin) {
|
|
406
|
+
io.stdin.pipe(child.stdin);
|
|
407
|
+
}
|
|
408
|
+
const result = await new Promise((resolvePromise) => {
|
|
409
|
+
let restartRequested = false;
|
|
410
|
+
requestChildRestart = () => {
|
|
411
|
+
if (restartRequested || shuttingDown || typeof child.kill !== "function") {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
restartRequested = true;
|
|
415
|
+
child.kill("SIGTERM");
|
|
416
|
+
};
|
|
417
|
+
child.on("error", (error) => {
|
|
418
|
+
if (child.stdin) {
|
|
419
|
+
io.stdin.unpipe(child.stdin);
|
|
420
|
+
}
|
|
421
|
+
requestChildRestart = void 0;
|
|
422
|
+
if (restartRequested) {
|
|
423
|
+
resolvePromise({ kind: "restart" });
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
resolvePromise({ kind: "error", error });
|
|
427
|
+
});
|
|
428
|
+
child.on("close", (code) => {
|
|
429
|
+
if (child.stdin) {
|
|
430
|
+
io.stdin.unpipe(child.stdin);
|
|
431
|
+
}
|
|
432
|
+
requestChildRestart = void 0;
|
|
433
|
+
if (restartRequested) {
|
|
434
|
+
resolvePromise({ kind: "restart" });
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
resolvePromise({ kind: "close", code });
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
if (result.kind === "restart") {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
shuttingDown = true;
|
|
444
|
+
closeWatchers();
|
|
445
|
+
await Promise.resolve(pendingPrepare);
|
|
446
|
+
if (result.kind === "error") {
|
|
447
|
+
throw result.error;
|
|
448
|
+
}
|
|
449
|
+
if (result.code === 0) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
throw new Error(`Project script "holo:dev" failed with exit code ${result.code ?? "unknown"}.`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export {
|
|
457
|
+
resolveProjectPackageManager,
|
|
458
|
+
resolvePackageManagerCommand,
|
|
459
|
+
resolvePackageManagerInstallInvocation,
|
|
460
|
+
runProjectLifecycleScript,
|
|
461
|
+
runProjectStartServer,
|
|
462
|
+
runProjectDependencyInstall,
|
|
463
|
+
runProjectPrepare,
|
|
464
|
+
toPosixSlashes,
|
|
465
|
+
isDiscoveryRelevantPath,
|
|
466
|
+
isRecursiveWatchUnsupported,
|
|
467
|
+
isIgnorableWatchError,
|
|
468
|
+
collectDirectoryTree,
|
|
469
|
+
collectDiscoveryWatchRoots,
|
|
470
|
+
normalizeWatchedFilePath,
|
|
471
|
+
runProjectDevServer
|
|
472
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadGeneratedProjectRegistry,
|
|
3
3
|
writeGeneratedProjectRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-J76GH2DR.mjs";
|
|
5
5
|
import {
|
|
6
6
|
COMMAND_FILE_PATTERN,
|
|
7
7
|
MIGRATION_NAME_PATTERN,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
pathExists,
|
|
18
18
|
readTextFile,
|
|
19
19
|
toPosixPath
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ILU426CF.mjs";
|
|
21
21
|
|
|
22
22
|
// src/project/discovery.ts
|
|
23
23
|
import { resolve as resolve2 } from "path";
|
|
@@ -55,37 +55,25 @@ function deriveJobNameFromPath(jobsRoot, sourcePath) {
|
|
|
55
55
|
const relativePath = toPosixPath(relative(jobsRoot, sourcePath));
|
|
56
56
|
return relativePath.replace(COMMAND_FILE_PATTERN, "").split("/").filter(Boolean).join(".");
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
const relativePath = toPosixPath(relative(
|
|
58
|
+
function deriveDottedNameFromPath(root, sourcePath, emptyMessage) {
|
|
59
|
+
const relativePath = toPosixPath(relative(root, sourcePath)).replace(COMMAND_FILE_PATTERN, "");
|
|
60
60
|
const derived = relativePath.split("/").map((part) => part.trim()).filter(Boolean).join(".");
|
|
61
61
|
if (!derived) {
|
|
62
|
-
throw new Error(
|
|
62
|
+
throw new Error(emptyMessage);
|
|
63
63
|
}
|
|
64
64
|
return derived;
|
|
65
65
|
}
|
|
66
|
+
function deriveEventNameFromPath(eventsRoot, sourcePath) {
|
|
67
|
+
return deriveDottedNameFromPath(eventsRoot, sourcePath, "[Holo Events] Derived event names require a non-empty source path.");
|
|
68
|
+
}
|
|
66
69
|
function deriveListenerIdFromPath(listenersRoot, sourcePath) {
|
|
67
|
-
|
|
68
|
-
const derived = relativePath.replace(COMMAND_FILE_PATTERN, "").split("/").map((part) => part.trim()).filter(Boolean).join(".");
|
|
69
|
-
if (!derived) {
|
|
70
|
-
throw new Error("[Holo Events] Derived listener identifiers require a non-empty source path.");
|
|
71
|
-
}
|
|
72
|
-
return derived;
|
|
70
|
+
return deriveDottedNameFromPath(listenersRoot, sourcePath, "[Holo Events] Derived listener identifiers require a non-empty source path.");
|
|
73
71
|
}
|
|
74
72
|
function deriveBroadcastNameFromPath(root, sourcePath) {
|
|
75
|
-
|
|
76
|
-
const derived = relativePath.split("/").map((part) => part.trim()).filter(Boolean).join(".");
|
|
77
|
-
if (!derived) {
|
|
78
|
-
throw new Error("[Holo Broadcast] Derived broadcast names require a non-empty source path.");
|
|
79
|
-
}
|
|
80
|
-
return derived;
|
|
73
|
+
return deriveDottedNameFromPath(root, sourcePath, "[Holo Broadcast] Derived broadcast names require a non-empty source path.");
|
|
81
74
|
}
|
|
82
75
|
function deriveChannelPatternFromPath(root, sourcePath) {
|
|
83
|
-
|
|
84
|
-
const derived = relativePath.split("/").map((part) => part.trim()).filter(Boolean).join(".");
|
|
85
|
-
if (!derived) {
|
|
86
|
-
throw new Error("[Holo Broadcast] Derived channel patterns require a non-empty source path.");
|
|
87
|
-
}
|
|
88
|
-
return derived;
|
|
76
|
+
return deriveDottedNameFromPath(root, sourcePath, "[Holo Broadcast] Derived channel patterns require a non-empty source path.");
|
|
89
77
|
}
|
|
90
78
|
function resolveDiscoveredJobMetadata(job, sourcePath, derivedName, queueConfig) {
|
|
91
79
|
const connection = job.connection ?? queueConfig.default;
|
|
@@ -356,6 +344,28 @@ function validateMigrationName(name, message) {
|
|
|
356
344
|
}
|
|
357
345
|
|
|
358
346
|
// src/project/discovery.ts
|
|
347
|
+
function resolveBroadcastExportEntry(moduleValue, discovery) {
|
|
348
|
+
if (!moduleValue || typeof moduleValue !== "object") {
|
|
349
|
+
return void 0;
|
|
350
|
+
}
|
|
351
|
+
const entries = Object.entries(moduleValue);
|
|
352
|
+
const orderedEntries = "default" in moduleValue ? [
|
|
353
|
+
["default", moduleValue.default],
|
|
354
|
+
...entries.filter(([exportName]) => exportName !== "default")
|
|
355
|
+
] : entries;
|
|
356
|
+
for (const [exportName, value] of orderedEntries) {
|
|
357
|
+
if (discovery.isBroadcastDefinition(value)) {
|
|
358
|
+
return { exportName, value };
|
|
359
|
+
}
|
|
360
|
+
if (typeof value === "function") {
|
|
361
|
+
const resolved = value(...Array.from({ length: value.length }, () => "__holo_discovery__"));
|
|
362
|
+
if (discovery.isBroadcastDefinition(resolved)) {
|
|
363
|
+
return { exportName, value: resolved };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return void 0;
|
|
368
|
+
}
|
|
359
369
|
async function prepareProjectDiscovery(projectRoot, config = normalizeHoloProjectConfig()) {
|
|
360
370
|
const loadedConfig = await loadConfigDirectory(projectRoot, {
|
|
361
371
|
processEnv: process.env
|
|
@@ -565,9 +575,9 @@ async function prepareProjectDiscovery(projectRoot, config = normalizeHoloProjec
|
|
|
565
575
|
const broadcast = [];
|
|
566
576
|
for (const filePath of broadcastFiles) {
|
|
567
577
|
const relativePath = makeProjectRelativePath(projectRoot, filePath);
|
|
568
|
-
const exportedBroadcast =
|
|
578
|
+
const exportedBroadcast = resolveBroadcastExportEntry(
|
|
569
579
|
await importProjectModule(projectRoot, filePath),
|
|
570
|
-
|
|
580
|
+
broadcastDiscovery
|
|
571
581
|
);
|
|
572
582
|
if (!exportedBroadcast) {
|
|
573
583
|
throw new Error(`Discovered broadcast "${relativePath}" does not export a Holo broadcast definition.`);
|
|
@@ -601,6 +611,7 @@ async function prepareProjectDiscovery(projectRoot, config = normalizeHoloProjec
|
|
|
601
611
|
sourcePath: relativePath,
|
|
602
612
|
pattern,
|
|
603
613
|
exportName: exportedChannel.exportName,
|
|
614
|
+
...typeof normalizedChannel.guard === "string" ? { guard: normalizedChannel.guard } : {},
|
|
604
615
|
type: normalizedChannel.type,
|
|
605
616
|
params: broadcastDiscovery.broadcastInternals.extractChannelPatternParamNames(pattern),
|
|
606
617
|
whispers: Object.freeze(Object.keys(normalizedChannel.whispers))
|