@ilanalimanjs/open_pack 2.4.6 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +45 -82
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -108,19 +108,10 @@ const isWindows = process.platform === 'win32';
|
|
|
108
108
|
const isTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
109
109
|
const SHELL_TOOLS = new Set(Object.keys(PACKAGE_MANAGERS));
|
|
110
110
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
pending: muted('○')
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const STATUS_VALUES = {
|
|
119
|
-
done: (result) => muted(`${(result.duration / 1000).toFixed(1)}s`),
|
|
120
|
-
warning: (result) => chalk.yellow(`${(result.duration / 1000).toFixed(1)}s`),
|
|
121
|
-
failed: () => chalk.red('failed'),
|
|
122
|
-
pending: () => muted('pending')
|
|
123
|
-
};
|
|
111
|
+
const BAR = muted('│');
|
|
112
|
+
const END = muted('└');
|
|
113
|
+
const SPINNER = { interval: 80, frames: ['◒', '◐', '◓', '◑'] };
|
|
114
|
+
const activity = { spinner: null };
|
|
124
115
|
|
|
125
116
|
class UsageError extends Error {}
|
|
126
117
|
|
|
@@ -294,6 +285,13 @@ const detectIpAddress = () => {
|
|
|
294
285
|
return entry?.address ?? null;
|
|
295
286
|
};
|
|
296
287
|
|
|
288
|
+
const formatSystem = () => {
|
|
289
|
+
const release = os.release().split('-')[0];
|
|
290
|
+
const arch = os.arch();
|
|
291
|
+
if (isAndroid()) return `Android (kernel ${release}, ${arch})`;
|
|
292
|
+
return `${PLATFORM_LABELS[process.platform] ?? process.platform} ${release} (${arch})`;
|
|
293
|
+
};
|
|
294
|
+
|
|
297
295
|
const detectEnvironment = async ({ port, checkUpdate }) => {
|
|
298
296
|
const managerNames = Object.keys(PACKAGE_MANAGERS);
|
|
299
297
|
const [gitVersion, portFree, latestVersion, device, ...managerVersions] = await Promise.all([
|
|
@@ -308,7 +306,7 @@ const detectEnvironment = async ({ port, checkUpdate }) => {
|
|
|
308
306
|
);
|
|
309
307
|
|
|
310
308
|
return {
|
|
311
|
-
system:
|
|
309
|
+
system: formatSystem(),
|
|
312
310
|
device,
|
|
313
311
|
ipAddress: detectIpAddress(),
|
|
314
312
|
node: process.versions.node,
|
|
@@ -348,15 +346,6 @@ const printEnvironmentCard = (environment) => {
|
|
|
348
346
|
console.log();
|
|
349
347
|
};
|
|
350
348
|
|
|
351
|
-
const printStatusCard = (results) => {
|
|
352
|
-
const rows = results.map((result) => ({
|
|
353
|
-
label: `${STATE_ICONS[result.state]} ${result.label}`,
|
|
354
|
-
value: STATUS_VALUES[result.state](result)
|
|
355
|
-
}));
|
|
356
|
-
console.log();
|
|
357
|
-
console.log(renderCard('Build status', rows));
|
|
358
|
-
};
|
|
359
|
-
|
|
360
349
|
const printBanner = async () => {
|
|
361
350
|
console.log();
|
|
362
351
|
for (const [index, line] of BANNER_LINES.entries()) {
|
|
@@ -534,7 +523,6 @@ const resolveDefaultOptions = async (cli, environment) => {
|
|
|
534
523
|
const buildSteps = ({ name, packageManager, mode, port }) => {
|
|
535
524
|
const targetDirectory = path.resolve(process.cwd(), name);
|
|
536
525
|
const manager = PACKAGE_MANAGERS[packageManager];
|
|
537
|
-
const customPort = port !== DEFAULT_PORT;
|
|
538
526
|
const steps = [
|
|
539
527
|
{
|
|
540
528
|
active: 'Fetching template',
|
|
@@ -545,28 +533,20 @@ const buildSteps = ({ name, packageManager, mode, port }) => {
|
|
|
545
533
|
}
|
|
546
534
|
},
|
|
547
535
|
{
|
|
548
|
-
active: '
|
|
549
|
-
done:
|
|
536
|
+
active: 'Configuring environment',
|
|
537
|
+
done: 'Environment configured',
|
|
550
538
|
task: async () => {
|
|
551
539
|
const source = path.join(targetDirectory, ENV_EXAMPLE_FILE);
|
|
552
540
|
if (!(await fse.pathExists(source))) throw new Error(`${ENV_EXAMPLE_FILE} not found in the template`);
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const current = await fse.readFile(envPath, 'utf8');
|
|
562
|
-
const withSecret = setEnvValue(current, 'SESSION_SECRET', randomBytes(32).toString('hex'));
|
|
563
|
-
await fse.writeFile(envPath, customPort ? setEnvValue(withSecret, 'PORT', String(port)) : withSecret);
|
|
541
|
+
const withSecret = setEnvValue(
|
|
542
|
+
await fse.readFile(source, 'utf8'),
|
|
543
|
+
'SESSION_SECRET',
|
|
544
|
+
randomBytes(32).toString('hex')
|
|
545
|
+
);
|
|
546
|
+
const content = port === DEFAULT_PORT ? withSecret : setEnvValue(withSecret, 'PORT', String(port));
|
|
547
|
+
await fse.writeFile(path.join(targetDirectory, ENV_FILE), content);
|
|
548
|
+
process.chdir(targetDirectory);
|
|
564
549
|
}
|
|
565
|
-
},
|
|
566
|
-
{
|
|
567
|
-
active: 'Entering project directory',
|
|
568
|
-
done: `Entered ${name}`,
|
|
569
|
-
task: async () => process.chdir(targetDirectory)
|
|
570
550
|
}
|
|
571
551
|
];
|
|
572
552
|
|
|
@@ -579,35 +559,25 @@ const buildSteps = ({ name, packageManager, mode, port }) => {
|
|
|
579
559
|
});
|
|
580
560
|
}
|
|
581
561
|
|
|
582
|
-
if (mode === MODES.run) {
|
|
583
|
-
steps.push({
|
|
584
|
-
active: 'Starting template',
|
|
585
|
-
done: 'Template ready to run',
|
|
586
|
-
task: async () => undefined
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
|
|
590
562
|
return { steps, targetDirectory, manager };
|
|
591
563
|
};
|
|
592
564
|
|
|
593
|
-
const runSteps = async (steps
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
|
|
565
|
+
const runSteps = async (steps) => {
|
|
566
|
+
for (const step of steps) {
|
|
567
|
+
console.log(BAR);
|
|
568
|
+
const spinner = ora({ text: ` ${step.active}`, spinner: SPINNER, color: 'magenta' }).start();
|
|
569
|
+
activity.spinner = spinner;
|
|
598
570
|
const startedAt = Date.now();
|
|
599
571
|
try {
|
|
600
|
-
|
|
572
|
+
await step.task();
|
|
601
573
|
const remaining = (step.minDuration ?? STEP_MIN_DURATION_MS) - (Date.now() - startedAt);
|
|
602
574
|
if (remaining > 0) await pause(remaining);
|
|
603
|
-
|
|
604
|
-
const label = outcome.label ?? step.done;
|
|
605
|
-
results[index] = { label, state, duration: Date.now() - startedAt };
|
|
606
|
-
spinner.stopAndPersist({ symbol: STATE_ICONS[state], text: `${prefix} ${label}` });
|
|
575
|
+
spinner.stopAndPersist({ symbol: chalk.green('◇'), text: ` ${step.done}` });
|
|
607
576
|
} catch (error) {
|
|
608
|
-
|
|
609
|
-
spinner.stopAndPersist({ symbol: STATE_ICONS.failed, text: `${prefix} ${step.active} ${chalk.red('failed')}` });
|
|
577
|
+
spinner.stopAndPersist({ symbol: chalk.red('■'), text: ` ${step.active} ${chalk.red('failed')}` });
|
|
610
578
|
throw error;
|
|
579
|
+
} finally {
|
|
580
|
+
activity.spinner = null;
|
|
611
581
|
}
|
|
612
582
|
}
|
|
613
583
|
};
|
|
@@ -620,20 +590,17 @@ const printSummary = ({ name, packageManager, mode, port, startedAt }) => {
|
|
|
620
590
|
if (mode === MODES.none) pending.push(`${packageManager} install`);
|
|
621
591
|
if (mode !== MODES.run) pending.push(devCommand);
|
|
622
592
|
|
|
623
|
-
console.log();
|
|
624
|
-
console.log(
|
|
625
|
-
console.log();
|
|
593
|
+
console.log(BAR);
|
|
594
|
+
console.log(`${chalk.green('◇')} ${chalk.bold(name)} is ready ${muted(`in ${duration}s`)}`);
|
|
626
595
|
if (mode === MODES.run) {
|
|
627
|
-
console.log(
|
|
628
|
-
console.log(
|
|
629
|
-
console.log(
|
|
596
|
+
console.log(`${BAR} ${muted('Server')} ${accent(devUrl)}`);
|
|
597
|
+
console.log(`${BAR} ${muted('Health')} ${accent(`${devUrl}/api/health`)}`);
|
|
598
|
+
console.log(`${END} ${muted('Press Ctrl+C to stop')}`);
|
|
630
599
|
console.log();
|
|
631
600
|
return;
|
|
632
601
|
}
|
|
633
|
-
console.log(
|
|
634
|
-
|
|
635
|
-
console.log();
|
|
636
|
-
console.log(` ${muted('Health check')} ${accent(`${devUrl}/api/health`)}`);
|
|
602
|
+
pending.forEach((step) => console.log(`${BAR} ${accent(step)}`));
|
|
603
|
+
console.log(`${END} ${muted('Health')} ${accent(`${devUrl}/api/health`)}`);
|
|
637
604
|
console.log();
|
|
638
605
|
};
|
|
639
606
|
|
|
@@ -656,7 +623,7 @@ async function main() {
|
|
|
656
623
|
const flagError = validateFlags(cli);
|
|
657
624
|
if (flagError) throw new UsageError(flagError);
|
|
658
625
|
|
|
659
|
-
const inspector = ora({ text: 'Inspecting your environment', indent: 2, spinner:
|
|
626
|
+
const inspector = ora({ text: 'Inspecting your environment', indent: 2, spinner: SPINNER, color: 'magenta' }).start();
|
|
660
627
|
const environment = await detectEnvironment({
|
|
661
628
|
port: cli.values.port === undefined ? DEFAULT_PORT : Number(cli.values.port),
|
|
662
629
|
checkUpdate: !cli.values['no-update-check']
|
|
@@ -676,33 +643,30 @@ async function main() {
|
|
|
676
643
|
}
|
|
677
644
|
|
|
678
645
|
const interactive = isTTY && !cli.values.yes;
|
|
679
|
-
if (!interactive) console.log(` ${muted('Non-interactive mode')}
|
|
646
|
+
if (!interactive) console.log(` ${muted('Non-interactive mode')}`);
|
|
680
647
|
|
|
681
648
|
const options = interactive ? await askOptions(cli, environment) : await resolveDefaultOptions(cli, environment);
|
|
682
649
|
const originalCwd = process.cwd();
|
|
683
650
|
const { steps, targetDirectory, manager } = buildSteps(options);
|
|
684
651
|
const rollback = createRollback(targetDirectory, originalCwd, !(await fse.pathExists(targetDirectory)));
|
|
685
|
-
const results = steps.map((step) => ({ label: step.done, state: 'pending', duration: null }));
|
|
686
652
|
const startedAt = performance.now();
|
|
687
653
|
|
|
688
654
|
const handleInterrupt = async () => {
|
|
655
|
+
activity.spinner?.stop();
|
|
689
656
|
const removed = await rollback.run();
|
|
690
|
-
console.log();
|
|
691
|
-
console.log(` ${chalk.yellow('!')} Interrupted${removed ? ', partial project removed' : ''}`);
|
|
657
|
+
console.log(`${chalk.yellow('■')} Interrupted${removed ? ', partial project removed' : ''}`);
|
|
692
658
|
console.log();
|
|
693
659
|
process.exit(EXIT_INTERRUPTED);
|
|
694
660
|
};
|
|
695
661
|
|
|
696
|
-
console.log();
|
|
697
662
|
process.once('SIGINT', handleInterrupt);
|
|
698
663
|
|
|
699
664
|
try {
|
|
700
|
-
await runSteps(steps
|
|
665
|
+
await runSteps(steps);
|
|
701
666
|
rollback.disarm();
|
|
702
667
|
} catch (error) {
|
|
703
668
|
const removed = await rollback.run();
|
|
704
|
-
|
|
705
|
-
if (removed) console.log(`\n ${muted('Partial project removed')}`);
|
|
669
|
+
if (removed) console.log(`${BAR} ${muted('Partial project removed')}`);
|
|
706
670
|
const alreadyExists = /already exists/i.test(error.message);
|
|
707
671
|
printFailure(
|
|
708
672
|
alreadyExists ? 'Directory already exists' : 'Failed to create project',
|
|
@@ -713,7 +677,6 @@ async function main() {
|
|
|
713
677
|
process.removeListener('SIGINT', handleInterrupt);
|
|
714
678
|
}
|
|
715
679
|
|
|
716
|
-
printStatusCard(results);
|
|
717
680
|
printSummary({ ...options, startedAt });
|
|
718
681
|
|
|
719
682
|
if (options.mode === MODES.run) {
|