@fluojs/cli 1.0.0-beta.3 → 1.0.0-beta.5
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/README.ko.md +63 -0
- package/README.md +63 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +171 -4
- package/dist/commands/diagnostics.d.ts +15 -0
- package/dist/commands/diagnostics.d.ts.map +1 -0
- package/dist/commands/diagnostics.js +163 -0
- package/dist/commands/new.js +2 -2
- package/dist/commands/package-manager.d.ts +9 -0
- package/dist/commands/package-manager.d.ts.map +1 -0
- package/dist/commands/package-manager.js +63 -0
- package/dist/commands/package-workflow.d.ts +20 -0
- package/dist/commands/package-workflow.d.ts.map +1 -0
- package/dist/commands/package-workflow.js +137 -0
- package/dist/commands/scripts.d.ts +38 -0
- package/dist/commands/scripts.d.ts.map +1 -0
- package/dist/commands/scripts.js +418 -0
- package/dist/dev-runner/node-restart-runner.d.ts +50 -0
- package/dist/dev-runner/node-restart-runner.d.ts.map +1 -0
- package/dist/dev-runner/node-restart-runner.js +248 -0
- package/dist/generators/manifest.d.ts +24 -0
- package/dist/generators/manifest.d.ts.map +1 -1
- package/dist/generators/manifest.js +9 -0
- package/dist/generators/resource.d.ts +10 -0
- package/dist/generators/resource.d.ts.map +1 -0
- package/dist/generators/resource.js +23 -0
- package/dist/generators/templates/controller.ts.ejs +5 -1
- package/dist/generators/templates/request-dto.ts.ejs +3 -0
- package/dist/new/scaffold.d.ts.map +1 -1
- package/dist/new/scaffold.js +77 -27
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +7 -5
- package/package.json +2 -2
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { delimiter, dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { SUPPORTED_PACKAGE_MANAGERS } from './package-manager.js';
|
|
6
|
+
const EMPTY_ENV = {};
|
|
7
|
+
const FAILURE_STDOUT_BUFFER_LIMIT = 16_384;
|
|
8
|
+
function getCliSourceRoot() {
|
|
9
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
|
+
}
|
|
11
|
+
function getCliEntryPoint() {
|
|
12
|
+
return join(getCliSourceRoot(), 'cli.js');
|
|
13
|
+
}
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return typeof value === 'object' && value !== null;
|
|
16
|
+
}
|
|
17
|
+
function readJsonFile(filePath) {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
20
|
+
return isRecord(parsed) ? parsed : undefined;
|
|
21
|
+
} catch (_error) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function findProjectManifest(startDirectory) {
|
|
26
|
+
let current = resolve(startDirectory);
|
|
27
|
+
while (true) {
|
|
28
|
+
const candidate = join(current, 'package.json');
|
|
29
|
+
if (existsSync(candidate)) {
|
|
30
|
+
const manifest = readJsonFile(candidate);
|
|
31
|
+
if (manifest) {
|
|
32
|
+
return {
|
|
33
|
+
directory: current,
|
|
34
|
+
manifest,
|
|
35
|
+
path: candidate
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const parent = dirname(current);
|
|
40
|
+
if (parent === current) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
current = parent;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function hasManifestDependency(manifest, packageName) {
|
|
47
|
+
for (const field of ['dependencies', 'devDependencies', 'optionalDependencies']) {
|
|
48
|
+
const entries = manifest[field];
|
|
49
|
+
if (isRecord(entries) && typeof entries[packageName] === 'string') {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function detectProjectRuntime(manifest) {
|
|
56
|
+
if (hasManifestDependency(manifest, '@fluojs/platform-bun')) {
|
|
57
|
+
return 'bun';
|
|
58
|
+
}
|
|
59
|
+
if (hasManifestDependency(manifest, '@fluojs/platform-deno')) {
|
|
60
|
+
return 'deno';
|
|
61
|
+
}
|
|
62
|
+
if (hasManifestDependency(manifest, '@fluojs/platform-cloudflare-workers')) {
|
|
63
|
+
return 'cloudflare-workers';
|
|
64
|
+
}
|
|
65
|
+
return 'node';
|
|
66
|
+
}
|
|
67
|
+
function withDefaultNodeEnv(env, defaultNodeEnv) {
|
|
68
|
+
if (env.NODE_ENV) {
|
|
69
|
+
return {
|
|
70
|
+
...env
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...env,
|
|
75
|
+
NODE_ENV: defaultNodeEnv
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function findPathEnvKey(env) {
|
|
79
|
+
return Object.keys(env).find(key => key.toLowerCase() === 'path') ?? 'PATH';
|
|
80
|
+
}
|
|
81
|
+
function withProjectLocalBin(env, projectDirectory) {
|
|
82
|
+
const pathKey = findPathEnvKey(env);
|
|
83
|
+
const existingPath = env[pathKey];
|
|
84
|
+
const localBin = join(projectDirectory, 'node_modules', '.bin');
|
|
85
|
+
return {
|
|
86
|
+
...env,
|
|
87
|
+
[pathKey]: existingPath ? `${localBin}${delimiter}${existingPath}` : localBin
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function defaultSpawnCommand(command, args, options) {
|
|
91
|
+
return new Promise((resolveExitCode, reject) => {
|
|
92
|
+
const child = spawn(command, args, options);
|
|
93
|
+
if (options.stdio === 'pipe') {
|
|
94
|
+
child.stdout?.on('data', chunk => options.stdout?.write(String(chunk)));
|
|
95
|
+
child.stderr?.on('data', chunk => options.stderr?.write(String(chunk)));
|
|
96
|
+
}
|
|
97
|
+
child.on('error', reject);
|
|
98
|
+
child.on('close', code => resolveExitCode(code ?? 1));
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function buildNativeNodeWatchStep(passThrough) {
|
|
102
|
+
return {
|
|
103
|
+
command: 'node',
|
|
104
|
+
args: ['--env-file=.env', '--watch', '--watch-preserve-output', '--import', 'tsx', 'src/main.ts', ...passThrough],
|
|
105
|
+
mode: 'native-watch'
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function buildProjectRunner(command, runtime, passThrough, options) {
|
|
109
|
+
if (command === 'build') {
|
|
110
|
+
switch (runtime) {
|
|
111
|
+
case 'bun':
|
|
112
|
+
return [{
|
|
113
|
+
command: 'bun',
|
|
114
|
+
args: ['build', './src/main.ts', '--outdir', './dist', '--target', 'bun', ...passThrough]
|
|
115
|
+
}];
|
|
116
|
+
case 'deno':
|
|
117
|
+
return [{
|
|
118
|
+
command: 'deno',
|
|
119
|
+
args: ['compile', '--allow-env', '--allow-net', '--output', join('dist', 'app'), 'src/main.ts', ...passThrough]
|
|
120
|
+
}];
|
|
121
|
+
case 'cloudflare-workers':
|
|
122
|
+
return [{
|
|
123
|
+
command: 'wrangler',
|
|
124
|
+
args: ['deploy', '--dry-run', ...passThrough]
|
|
125
|
+
}];
|
|
126
|
+
default:
|
|
127
|
+
return [{
|
|
128
|
+
command: 'vite',
|
|
129
|
+
args: ['build', ...passThrough],
|
|
130
|
+
mode: 'single-run'
|
|
131
|
+
}, {
|
|
132
|
+
command: 'tsc',
|
|
133
|
+
args: ['-p', 'tsconfig.build.json'],
|
|
134
|
+
mode: 'single-run'
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (command === 'dev') {
|
|
139
|
+
switch (runtime) {
|
|
140
|
+
case 'bun':
|
|
141
|
+
return [{
|
|
142
|
+
command: 'bun',
|
|
143
|
+
args: ['--watch', 'src/main.ts', ...passThrough]
|
|
144
|
+
}];
|
|
145
|
+
case 'deno':
|
|
146
|
+
return [{
|
|
147
|
+
command: 'deno',
|
|
148
|
+
args: ['run', '--allow-env', '--allow-net', '--watch', 'src/main.ts', ...passThrough]
|
|
149
|
+
}];
|
|
150
|
+
case 'cloudflare-workers':
|
|
151
|
+
return [{
|
|
152
|
+
command: 'wrangler',
|
|
153
|
+
args: ['dev', ...passThrough],
|
|
154
|
+
mode: 'native-watch'
|
|
155
|
+
}];
|
|
156
|
+
default:
|
|
157
|
+
if (options.rawWatch) {
|
|
158
|
+
return [buildNativeNodeWatchStep(passThrough)];
|
|
159
|
+
}
|
|
160
|
+
return [{
|
|
161
|
+
command: 'node',
|
|
162
|
+
args: ['--import', 'tsx', getCliEntryPoint(), '__node-dev-runner', '--', ...passThrough],
|
|
163
|
+
mode: 'fluo-node-restart'
|
|
164
|
+
}];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
switch (runtime) {
|
|
168
|
+
case 'bun':
|
|
169
|
+
return [{
|
|
170
|
+
command: 'bun',
|
|
171
|
+
args: ['dist/main.js', ...passThrough]
|
|
172
|
+
}];
|
|
173
|
+
case 'deno':
|
|
174
|
+
return [{
|
|
175
|
+
command: join('dist', 'app'),
|
|
176
|
+
args: [...passThrough]
|
|
177
|
+
}];
|
|
178
|
+
case 'cloudflare-workers':
|
|
179
|
+
return [{
|
|
180
|
+
command: 'wrangler',
|
|
181
|
+
args: ['dev', '--remote', ...passThrough]
|
|
182
|
+
}];
|
|
183
|
+
default:
|
|
184
|
+
return [{
|
|
185
|
+
command: 'node',
|
|
186
|
+
args: ['dist/main.js', ...passThrough],
|
|
187
|
+
mode: 'single-run'
|
|
188
|
+
}];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function runProjectRunnerSteps(steps, runtime, options) {
|
|
192
|
+
for (const step of steps) {
|
|
193
|
+
const exitCode = await runtime.spawnCommand(step.command, step.args, options);
|
|
194
|
+
if (exitCode !== 0) {
|
|
195
|
+
return exitCode;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
function parseScriptArgs(argv) {
|
|
201
|
+
let dryRun = false;
|
|
202
|
+
let packageManager;
|
|
203
|
+
let rawWatch = false;
|
|
204
|
+
let reporter = 'auto';
|
|
205
|
+
let verbose = false;
|
|
206
|
+
const passThrough = [];
|
|
207
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
208
|
+
const arg = argv[index];
|
|
209
|
+
if (arg === '--dry-run') {
|
|
210
|
+
dryRun = true;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (arg === '--verbose') {
|
|
214
|
+
verbose = true;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (arg === '--raw-watch') {
|
|
218
|
+
rawWatch = true;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (arg === '--reporter') {
|
|
222
|
+
const value = argv[index + 1];
|
|
223
|
+
if (!value || value.startsWith('-')) {
|
|
224
|
+
throw new Error('Expected --reporter to have a value.');
|
|
225
|
+
}
|
|
226
|
+
if (!(value === 'auto' || value === 'stream' || value === 'silent')) {
|
|
227
|
+
throw new Error(`Invalid --reporter value "${value}". Use one of: auto, stream, silent.`);
|
|
228
|
+
}
|
|
229
|
+
reporter = value;
|
|
230
|
+
index += 1;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (arg === '--package-manager') {
|
|
234
|
+
const value = argv[index + 1];
|
|
235
|
+
if (!value || value.startsWith('-')) {
|
|
236
|
+
throw new Error('Expected --package-manager to have a value.');
|
|
237
|
+
}
|
|
238
|
+
if (!SUPPORTED_PACKAGE_MANAGERS.has(value)) {
|
|
239
|
+
throw new Error(`Invalid --package-manager value "${value}". Use one of: pnpm, npm, yarn, bun.`);
|
|
240
|
+
}
|
|
241
|
+
packageManager = value;
|
|
242
|
+
index += 1;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (arg === '--') {
|
|
246
|
+
passThrough.push(...argv.slice(index + 1));
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
passThrough.push(arg);
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
dryRun,
|
|
253
|
+
packageManager,
|
|
254
|
+
passThrough,
|
|
255
|
+
rawWatch,
|
|
256
|
+
reporter,
|
|
257
|
+
verbose
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function isEnabledEnvironmentFlag(value) {
|
|
261
|
+
return value === '1' || value === 'true' || value === 'yes' || value === 'on';
|
|
262
|
+
}
|
|
263
|
+
function resolveReporterMode(command, parsed, runtime) {
|
|
264
|
+
if (parsed.reporter !== 'auto') {
|
|
265
|
+
return parsed.reporter;
|
|
266
|
+
}
|
|
267
|
+
if (parsed.verbose || isEnabledEnvironmentFlag(runtime.env?.FLUO_VERBOSE)) {
|
|
268
|
+
return 'stream';
|
|
269
|
+
}
|
|
270
|
+
if (runtime.ci || isEnabledEnvironmentFlag(runtime.env?.CI) || isEnabledEnvironmentFlag(runtime.env?.GITHUB_ACTIONS)) {
|
|
271
|
+
return 'stream';
|
|
272
|
+
}
|
|
273
|
+
if (command !== 'dev') {
|
|
274
|
+
return 'stream';
|
|
275
|
+
}
|
|
276
|
+
return (runtime.stdout ?? process.stdout).isTTY ? 'pretty' : 'stream';
|
|
277
|
+
}
|
|
278
|
+
function renderStep(step) {
|
|
279
|
+
return `${step.command} ${step.args.join(' ')}`.trim();
|
|
280
|
+
}
|
|
281
|
+
function createBoundedBufferStream(limit) {
|
|
282
|
+
let buffer = '';
|
|
283
|
+
return {
|
|
284
|
+
flush(target) {
|
|
285
|
+
if (buffer.length > 0) {
|
|
286
|
+
target.write(buffer);
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
hasContent() {
|
|
290
|
+
return buffer.length > 0;
|
|
291
|
+
},
|
|
292
|
+
write(message) {
|
|
293
|
+
buffer += message;
|
|
294
|
+
if (buffer.length > limit) {
|
|
295
|
+
buffer = buffer.slice(buffer.length - limit);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function createReporterStreams(mode, verbose, stdout, stderr) {
|
|
301
|
+
if (mode === 'stream') {
|
|
302
|
+
return {
|
|
303
|
+
flushBufferedStdoutOnFailure() {},
|
|
304
|
+
stdio: 'inherit'
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (mode === 'silent' || mode === 'pretty') {
|
|
308
|
+
if (verbose) {
|
|
309
|
+
return {
|
|
310
|
+
flushBufferedStdoutOnFailure() {},
|
|
311
|
+
stderr,
|
|
312
|
+
stdio: 'pipe',
|
|
313
|
+
stdout
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const bufferedStdout = createBoundedBufferStream(FAILURE_STDOUT_BUFFER_LIMIT);
|
|
317
|
+
return {
|
|
318
|
+
flushBufferedStdoutOnFailure() {
|
|
319
|
+
if (bufferedStdout.hasContent()) {
|
|
320
|
+
stderr.write('[fluo] child stdout before failure:\n');
|
|
321
|
+
bufferedStdout.flush(stderr);
|
|
322
|
+
stderr.write('\n');
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
stderr,
|
|
326
|
+
stdio: 'pipe',
|
|
327
|
+
stdout: bufferedStdout
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
flushBufferedStdoutOnFailure() {},
|
|
332
|
+
stdio: 'inherit'
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Renders lifecycle command help text.
|
|
338
|
+
*
|
|
339
|
+
* @param command Lifecycle command whose help text should be rendered.
|
|
340
|
+
* @returns Human-readable lifecycle command usage text.
|
|
341
|
+
*/
|
|
342
|
+
export function scriptUsage(command) {
|
|
343
|
+
const nodeEnv = command === 'dev' ? 'development' : 'production';
|
|
344
|
+
return [`Usage: fluo ${command} [options] [-- <args>]`, '', `Run the generated fluo project ${command} lifecycle with NODE_ENV defaulting to ${nodeEnv} when unset.`, '', 'Options', ' --dry-run Print the command without running it.', command === 'dev' ? ' --raw-watch Use the runtime-native watcher instead of the fluo Node restart runner.' : undefined, ' --reporter <auto|stream|silent> Choose lifecycle reporter output mode (default: auto).', ' --verbose Expose raw child process output; also honored by FLUO_VERBOSE=1.', ` --help Show help for the ${command} command.`].filter(line => typeof line === 'string').join('\n');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Runs one generated-project lifecycle command through the CLI-owned runtime command matrix.
|
|
349
|
+
*
|
|
350
|
+
* @param command Lifecycle command to run.
|
|
351
|
+
* @param argv Command-specific arguments after the lifecycle command name.
|
|
352
|
+
* @param runtime Runtime dependencies used by tests, sandboxes, and embedders.
|
|
353
|
+
* @returns Process-style exit code from the lifecycle command.
|
|
354
|
+
*/
|
|
355
|
+
export async function runScriptCommand(command, argv, runtime = {}) {
|
|
356
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
357
|
+
(runtime.stdout ?? process.stdout).write(`${scriptUsage(command)}\n`);
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
const env = runtime.env ?? EMPTY_ENV;
|
|
361
|
+
const stdout = runtime.stdout ?? process.stdout;
|
|
362
|
+
const stderr = runtime.stderr ?? process.stderr;
|
|
363
|
+
const project = findProjectManifest(runtime.cwd ?? process.cwd());
|
|
364
|
+
if (!project) {
|
|
365
|
+
throw new Error(`Unable to find package.json for fluo ${command}.`);
|
|
366
|
+
}
|
|
367
|
+
const parsed = parseScriptArgs(argv);
|
|
368
|
+
const projectRuntime = detectProjectRuntime(project.manifest);
|
|
369
|
+
const defaultNodeEnv = command === 'dev' ? 'development' : 'production';
|
|
370
|
+
const childEnv = withProjectLocalBin(withDefaultNodeEnv(env, defaultNodeEnv), project.directory);
|
|
371
|
+
const rawWatch = parsed.rawWatch || isEnabledEnvironmentFlag(env.FLUO_DEV_RAW_WATCH);
|
|
372
|
+
const runnerSteps = buildProjectRunner(command, projectRuntime, parsed.passThrough, {
|
|
373
|
+
rawWatch
|
|
374
|
+
});
|
|
375
|
+
const reporterMode = resolveReporterMode(command, parsed, {
|
|
376
|
+
...runtime,
|
|
377
|
+
env,
|
|
378
|
+
stdout
|
|
379
|
+
});
|
|
380
|
+
const verbose = parsed.verbose || isEnabledEnvironmentFlag(env.FLUO_VERBOSE);
|
|
381
|
+
if (parsed.dryRun) {
|
|
382
|
+
for (const step of runnerSteps) {
|
|
383
|
+
stdout.write(`Would run: ${step.command} ${step.args.join(' ')}\n`);
|
|
384
|
+
}
|
|
385
|
+
stdout.write(`Project: ${project.path}\n`);
|
|
386
|
+
stdout.write(`Runtime: ${projectRuntime}\n`);
|
|
387
|
+
stdout.write(`NODE_ENV: ${childEnv.NODE_ENV ?? ''}\n`);
|
|
388
|
+
stdout.write(`Reporter: ${reporterMode}\n`);
|
|
389
|
+
if (command === 'dev') {
|
|
390
|
+
stdout.write(`Watch mode: ${runnerSteps.map(step => step.mode ?? 'single-run').join(', ')}\n`);
|
|
391
|
+
}
|
|
392
|
+
return 0;
|
|
393
|
+
}
|
|
394
|
+
if (reporterMode === 'pretty') {
|
|
395
|
+
stdout.write(`[fluo] ${command} ${projectRuntime} lifecycle starting\n`);
|
|
396
|
+
stdout.write(`[fluo] ${runnerSteps.map(renderStep).join(' && ')}\n`);
|
|
397
|
+
}
|
|
398
|
+
const reporterStreams = createReporterStreams(reporterMode, verbose, stdout, stderr);
|
|
399
|
+
const exitCode = await runProjectRunnerSteps(runnerSteps, {
|
|
400
|
+
spawnCommand: runtime.spawnCommand ?? defaultSpawnCommand
|
|
401
|
+
}, {
|
|
402
|
+
cwd: project.directory,
|
|
403
|
+
env: childEnv,
|
|
404
|
+
...reporterStreams
|
|
405
|
+
});
|
|
406
|
+
if (reporterMode === 'pretty') {
|
|
407
|
+
if (exitCode === 0) {
|
|
408
|
+
stdout.write(`[fluo] ${command} lifecycle completed\n`);
|
|
409
|
+
} else {
|
|
410
|
+
reporterStreams.flushBufferedStdoutOnFailure();
|
|
411
|
+
stderr.write(`[fluo] ${command} lifecycle failed with exit code ${exitCode}\n`);
|
|
412
|
+
}
|
|
413
|
+
} else if (reporterMode === 'silent' && exitCode !== 0) {
|
|
414
|
+
reporterStreams.flushBufferedStdoutOnFailure();
|
|
415
|
+
stderr.write(`[fluo] ${command} lifecycle failed with exit code ${exitCode}\n`);
|
|
416
|
+
}
|
|
417
|
+
return exitCode;
|
|
418
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
import { type FSWatcher } from 'node:fs';
|
|
3
|
+
type RestartRunnerStream = {
|
|
4
|
+
write(message: string): unknown;
|
|
5
|
+
};
|
|
6
|
+
type RestartChildSpawner = (command: string, args: string[], options: {
|
|
7
|
+
cwd: string;
|
|
8
|
+
env: NodeJS.ProcessEnv;
|
|
9
|
+
stdio: 'inherit';
|
|
10
|
+
}) => ChildProcess;
|
|
11
|
+
type RestartSignal = 'SIGINT' | 'SIGTERM';
|
|
12
|
+
type RestartSignalTarget = {
|
|
13
|
+
off(signal: RestartSignal, listener: () => void): unknown;
|
|
14
|
+
once(signal: RestartSignal, listener: () => void): unknown;
|
|
15
|
+
};
|
|
16
|
+
type RestartWatcherFactory = (target: string, optionsOrListener: {
|
|
17
|
+
recursive: boolean;
|
|
18
|
+
} | ((event: string, filename: string | Buffer | null) => void), listener?: (event: string, filename: string | Buffer | null) => void) => FSWatcher;
|
|
19
|
+
type ContentChangeGate = {
|
|
20
|
+
commitBaseline(paths: Iterable<string>): void;
|
|
21
|
+
hasMeaningfulChange(paths: Iterable<string>): boolean;
|
|
22
|
+
};
|
|
23
|
+
export type NodeRestartRunnerOptions = {
|
|
24
|
+
appArgs?: string[];
|
|
25
|
+
debounceMs?: number;
|
|
26
|
+
env: NodeJS.ProcessEnv;
|
|
27
|
+
projectDirectory?: string;
|
|
28
|
+
signalTarget?: RestartSignalTarget;
|
|
29
|
+
spawnChild?: RestartChildSpawner;
|
|
30
|
+
stderr?: RestartRunnerStream;
|
|
31
|
+
stdout?: RestartRunnerStream;
|
|
32
|
+
watchTarget?: RestartWatcherFactory;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Creates a content-diff gate for fluo-owned dev restarts.
|
|
36
|
+
*
|
|
37
|
+
* @param projectDirectory Project root used for ignore matching.
|
|
38
|
+
* @param ignorePatterns Additional or default ignore patterns to apply before hashing.
|
|
39
|
+
* @returns A gate that reports whether watched paths changed by content rather than by filesystem event alone.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createContentChangeGate(projectDirectory: string, ignorePatterns?: string[]): ContentChangeGate;
|
|
42
|
+
/**
|
|
43
|
+
* Runs the Node.js development lifecycle through fluo-owned restart supervision.
|
|
44
|
+
*
|
|
45
|
+
* @param options Runner dependencies and project settings.
|
|
46
|
+
* @returns A promise that resolves with the final child exit code when the runner stops.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runNodeRestartRunner(options: NodeRestartRunnerOptions): Promise<number>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=node-restart-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-restart-runner.d.ts","sourceRoot":"","sources":["../../src/dev-runner/node-restart-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAA0D,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAGjG,KAAK,mBAAmB,GAAG;IACzB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,KAAK,YAAY,CAAC;AAEjJ,KAAK,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1C,KAAK,mBAAmB,GAAG;IACzB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAC1D,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAC5D,CAAC;AAEF,KAAK,qBAAqB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,KAAK,SAAS,CAAC;AAE1O,KAAK,iBAAiB,GAAG;IACvB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC9C,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC,CAAC;AA6FF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAoB,GAAG,iBAAiB,CAuB/H;AAYD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqJ7F"}
|