@ilanalimanjs/open_pack 2.4.3 → 2.4.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.
Files changed (2) hide show
  1. package/bin/index.js +143 -126
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -8,34 +8,37 @@ import { parseArgs } from 'node:util';
8
8
  import { spawn } from 'node:child_process';
9
9
  import { randomBytes } from 'node:crypto';
10
10
  import { setTimeout as sleep } from 'node:timers/promises';
11
- import { downloadTemplate } from 'giget';
12
11
  import * as prompts from '@clack/prompts';
13
12
  import fse from 'fs-extra';
14
13
  import chalk from 'chalk';
15
14
  import ora from 'ora';
16
15
 
16
+ process.noDeprecation = true;
17
+
17
18
  const { version: CLI_VERSION } = createRequire(import.meta.url)('../package.json');
18
19
 
19
20
  const TEMPLATE_SOURCE = 'github:DevIlannn/open_pack/Source';
20
21
  const REGISTRY_URL = 'https://registry.npmjs.org/@ilanalimanjs%2Fopen_pack/latest';
21
22
  const PACKAGE_COMMAND = 'npx @ilanalimanjs/open_pack@latest';
22
23
  const NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
23
- const DATABASE_URL_PATTERN = /^postgres(ql)?:\/\/.+/;
24
24
  const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
25
25
  const ENV_EXAMPLE_FILE = '.env.examples';
26
26
  const ENV_FILE = '.env';
27
+ const LINUX_CHASSIS_FILE = '/sys/class/dmi/id/chassis_type';
28
+ const LINUX_POWER_SUPPLY_DIRECTORY = '/sys/class/power_supply';
29
+ const WINDOWS_CHASSIS_SCRIPT = '(Get-CimInstance -ClassName Win32_SystemEnclosure).ChassisTypes';
27
30
  const DEFAULT_PORT = 3000;
28
- const DEFAULT_DATABASE_PORT = 5432;
29
31
  const MAX_PORT = 65535;
30
32
  const PORT_SEARCH_RANGE = 50;
31
33
  const MIN_NODE_VERSION = { major: 20, minor: 11 };
32
34
  const BANNER_DELAY_MS = 70;
33
35
  const STEP_MIN_DURATION_MS = 450;
34
36
  const DETECT_TIMEOUT_MS = 4000;
35
- const DATABASE_TIMEOUT_MS = 2500;
36
37
  const UPDATE_TIMEOUT_MS = 2500;
37
38
  const EXIT_INTERRUPTED = 130;
38
39
  const GRADIENT = ['#22d3ee', '#38bdf8', '#60a5fa', '#818cf8', '#a78bfa'];
40
+ const CHASSIS_LAPTOP = new Set([8, 9, 10, 14, 31, 32]);
41
+ const CHASSIS_PC = new Set([3, 4, 5, 6, 7, 13, 15, 16, 24, 35, 36]);
39
42
 
40
43
  const GLYPHS = [
41
44
  [String.raw` ___ `, String.raw` / _ \ `, String.raw`| | | |`, String.raw`| |_| |`, String.raw` \___/ `],
@@ -60,7 +63,15 @@ const PACKAGE_MANAGERS = {
60
63
  const PLATFORM_LABELS = {
61
64
  darwin: 'macOS',
62
65
  win32: 'Windows',
63
- linux: 'Linux'
66
+ linux: 'Linux',
67
+ android: 'Android'
68
+ };
69
+
70
+ const DEVICE_TYPES = {
71
+ phone: 'Phone',
72
+ laptop: 'Laptop',
73
+ pc: 'PC',
74
+ other: 'Other'
64
75
  };
65
76
 
66
77
  const MODES = {
@@ -72,11 +83,9 @@ const MODES = {
72
83
  const CLI_OPTIONS = {
73
84
  yes: { type: 'boolean', short: 'y' },
74
85
  pm: { type: 'string' },
75
- 'database-url': { type: 'string' },
76
86
  port: { type: 'string' },
77
87
  'no-install': { type: 'boolean' },
78
88
  'no-run': { type: 'boolean' },
79
- 'no-db-check': { type: 'boolean' },
80
89
  'no-update-check': { type: 'boolean' },
81
90
  help: { type: 'boolean', short: 'h' },
82
91
  version: { type: 'boolean', short: 'v' }
@@ -85,11 +94,9 @@ const CLI_OPTIONS = {
85
94
  const HELP_OPTIONS = [
86
95
  ['-y, --yes', 'Skip prompts and use defaults'],
87
96
  ['--pm <name>', 'Package manager: npm, pnpm, yarn, bun'],
88
- ['--database-url <url>', 'PostgreSQL connection string'],
89
97
  ['--port <number>', `Development server port (default ${DEFAULT_PORT})`],
90
98
  ['--no-install', 'Create the project without installing dependencies'],
91
99
  ['--no-run', 'Install dependencies without starting the server'],
92
- ['--no-db-check', 'Skip the database reachability check'],
93
100
  ['--no-update-check', 'Skip the CLI update check'],
94
101
  ['-h, --help', 'Show this help'],
95
102
  ['-v, --version', 'Show the CLI version']
@@ -99,20 +106,33 @@ const accent = chalk.hex('#38bdf8');
99
106
  const muted = chalk.gray;
100
107
  const isWindows = process.platform === 'win32';
101
108
  const isTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);
109
+ const SHELL_TOOLS = new Set(Object.keys(PACKAGE_MANAGERS));
102
110
 
103
111
  const STATE_ICONS = {
104
- done: chalk.green('✔'),
105
- warning: chalk.yellow('!'),
106
- failed: chalk.red('✖'),
112
+ done: chalk.green('●'),
113
+ warning: chalk.yellow('●'),
114
+ failed: chalk.red('●'),
107
115
  pending: muted('○')
108
116
  };
109
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
+ };
124
+
110
125
  class UsageError extends Error {}
111
126
 
112
127
  const pause = (ms) => (isTTY ? sleep(ms) : Promise.resolve());
113
128
 
114
129
  const visibleLength = (value) => value.replace(ANSI_PATTERN, '').length;
115
130
 
131
+ const spawnTool = (command, args, options) =>
132
+ isWindows && SHELL_TOOLS.has(command)
133
+ ? spawn([command, ...args].join(' '), { ...options, shell: true })
134
+ : spawn(command, args, options);
135
+
116
136
  const renderCard = (title, rows) => {
117
137
  const labelWidth = Math.max(...rows.map((row) => visibleLength(row.label)));
118
138
  const lines = rows.map((row) => `${row.label}${' '.repeat(labelWidth - visibleLength(row.label))} ${row.value}`);
@@ -141,9 +161,6 @@ const validateProjectName = (value) => {
141
161
  return undefined;
142
162
  };
143
163
 
144
- const validateDatabaseUrl = (value) =>
145
- DATABASE_URL_PATTERN.test(value ?? '') ? undefined : 'Use the format postgresql://user:password@host:port/db';
146
-
147
164
  const validatePort = (value) => {
148
165
  const port = Number(value);
149
166
  return /^\d+$/.test(String(value ?? '')) && port >= 1 && port <= MAX_PORT
@@ -155,8 +172,7 @@ const validateFlags = ({ values, positionals }) => {
155
172
  const checks = [
156
173
  positionals[0] === undefined ? undefined : validateProjectName(positionals[0]),
157
174
  values.pm === undefined || PACKAGE_MANAGERS[values.pm] ? undefined : '--pm must be one of npm, pnpm, yarn, bun',
158
- values.port === undefined ? undefined : validatePort(values.port),
159
- values['database-url'] === undefined ? undefined : validateDatabaseUrl(values['database-url'])
175
+ values.port === undefined ? undefined : validatePort(values.port)
160
176
  ];
161
177
  return checks.find(Boolean);
162
178
  };
@@ -170,26 +186,23 @@ const resolveFixedMode = (values) => {
170
186
  const readFixedOptions = ({ values, positionals }) => ({
171
187
  name: positionals[0],
172
188
  packageManager: values.pm,
173
- databaseUrl: values['database-url'],
174
189
  port: values.port === undefined ? undefined : Number(values.port),
175
190
  mode: resolveFixedMode(values)
176
191
  });
177
192
 
178
193
  const captureCommand = (command, args) =>
179
194
  new Promise((resolve) => {
180
- const child = spawn(command, args, {
181
- shell: isWindows,
182
- stdio: ['ignore', 'pipe', 'ignore'],
183
- timeout: DETECT_TIMEOUT_MS
184
- });
195
+ const child = spawnTool(command, args, { stdio: ['ignore', 'pipe', 'ignore'], timeout: DETECT_TIMEOUT_MS });
185
196
  let output = '';
186
197
  child.stdout.on('data', (chunk) => {
187
198
  output += chunk.toString();
188
199
  });
189
200
  child.on('error', () => resolve(null));
190
- child.on('close', (code) => resolve(code === 0 ? (output.trim().split('\n')[0] ?? null) : null));
201
+ child.on('close', (code) => resolve(code === 0 ? output.trim() : null));
191
202
  });
192
203
 
204
+ const captureFirstLine = async (command, args) => (await captureCommand(command, args))?.split('\n')[0].trim() ?? null;
205
+
193
206
  const isPortFree = (port) =>
194
207
  new Promise((resolve) => {
195
208
  const server = net.createServer();
@@ -205,20 +218,6 @@ const findFreePort = async (start) => {
205
218
  throw new Error(`No free port found from ${start}`);
206
219
  };
207
220
 
208
- const isTcpReachable = (host, port) =>
209
- new Promise((resolve) => {
210
- const socket = net.connect({ host, port, timeout: DATABASE_TIMEOUT_MS });
211
- socket.once('connect', () => {
212
- socket.destroy();
213
- resolve(true);
214
- });
215
- socket.once('timeout', () => {
216
- socket.destroy();
217
- resolve(false);
218
- });
219
- socket.once('error', () => resolve(false));
220
- });
221
-
222
221
  const fetchLatestVersion = async () => {
223
222
  try {
224
223
  const response = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(UPDATE_TIMEOUT_MS) });
@@ -241,27 +240,82 @@ const isNodeSupported = () => {
241
240
  return major > MIN_NODE_VERSION.major || (major === MIN_NODE_VERSION.major && minor >= MIN_NODE_VERSION.minor);
242
241
  };
243
242
 
243
+ const classifyChassis = (code) => {
244
+ if (CHASSIS_LAPTOP.has(code)) return DEVICE_TYPES.laptop;
245
+ if (CHASSIS_PC.has(code)) return DEVICE_TYPES.pc;
246
+ return DEVICE_TYPES.other;
247
+ };
248
+
249
+ const isAndroid = () =>
250
+ process.platform === 'android' || Boolean(process.env.TERMUX_VERSION) || (process.env.PREFIX ?? '').includes('com.termux');
251
+
252
+ const readLinuxChassis = async () => {
253
+ try {
254
+ return Number((await fse.readFile(LINUX_CHASSIS_FILE, 'utf8')).trim());
255
+ } catch {
256
+ return null;
257
+ }
258
+ };
259
+
260
+ const hasLinuxBattery = async () => {
261
+ try {
262
+ return (await fse.readdir(LINUX_POWER_SUPPLY_DIRECTORY)).some((entry) => /^BAT/i.test(entry));
263
+ } catch {
264
+ return false;
265
+ }
266
+ };
267
+
268
+ const detectDeviceType = async () => {
269
+ if (isAndroid()) return DEVICE_TYPES.phone;
270
+
271
+ if (process.platform === 'win32') {
272
+ const output = await captureCommand('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', WINDOWS_CHASSIS_SCRIPT]);
273
+ return classifyChassis(Number((output ?? '').split(/\s+/).find((token) => /^\d+$/.test(token))));
274
+ }
275
+
276
+ if (process.platform === 'darwin') {
277
+ const output = await captureCommand('pmset', ['-g', 'batt']);
278
+ return output?.includes('InternalBattery') ? DEVICE_TYPES.laptop : DEVICE_TYPES.pc;
279
+ }
280
+
281
+ if (process.platform === 'linux') {
282
+ const code = await readLinuxChassis();
283
+ if (code !== null) return classifyChassis(code);
284
+ return (await hasLinuxBattery()) ? DEVICE_TYPES.laptop : DEVICE_TYPES.other;
285
+ }
286
+
287
+ return DEVICE_TYPES.other;
288
+ };
289
+
290
+ const detectIpAddress = () => {
291
+ const [entry] = Object.values(os.networkInterfaces())
292
+ .flat()
293
+ .filter((item) => item && item.family === 'IPv4' && !item.internal);
294
+ return entry?.address ?? null;
295
+ };
296
+
244
297
  const detectEnvironment = async ({ port, checkUpdate }) => {
245
298
  const managerNames = Object.keys(PACKAGE_MANAGERS);
246
- const [gitOutput, portFree, latestVersion, ...managerVersions] = await Promise.all([
247
- captureCommand('git', ['--version']),
299
+ const [gitVersion, portFree, latestVersion, device, ...managerVersions] = await Promise.all([
300
+ captureFirstLine('git', ['--version']),
248
301
  isPortFree(port),
249
302
  checkUpdate ? fetchLatestVersion() : Promise.resolve(null),
250
- ...managerNames.map((name) => captureCommand(name, ['--version']))
303
+ detectDeviceType(),
304
+ ...managerNames.map((name) => captureFirstLine(name, ['--version']))
251
305
  ]);
252
306
  const managers = Object.fromEntries(
253
307
  managerNames.map((name, index) => [name, managerVersions[index]]).filter(([, version]) => version)
254
308
  );
255
- const cpus = os.cpus();
256
309
 
257
310
  return {
258
311
  system: `${PLATFORM_LABELS[process.platform] ?? process.platform} ${os.release()} (${os.arch()})`,
259
- device: `${(cpus[0]?.model ?? 'Unknown CPU').replace(/\s+/g, ' ').trim()} (${cpus.length} cores, ${Math.round(os.totalmem() / 1024 ** 3)} GB RAM)`,
312
+ device,
313
+ ipAddress: detectIpAddress(),
260
314
  node: process.versions.node,
261
315
  nodeSupported: isNodeSupported(),
262
316
  launcher: parseLauncher(),
263
317
  managers,
264
- git: gitOutput ? gitOutput.replace(/^git version\s*/, '') : null,
318
+ git: gitVersion ? gitVersion.replace(/^git version\s*/, '') : null,
265
319
  port,
266
320
  portFree,
267
321
  latestVersion
@@ -269,36 +323,25 @@ const detectEnvironment = async ({ port, checkUpdate }) => {
269
323
  };
270
324
 
271
325
  const printEnvironmentCard = (environment) => {
272
- const managerList = Object.entries(environment.managers).map(([name, version]) => `${name} ${version}`);
273
- const nodeStatus = environment.nodeSupported
274
- ? chalk.green('✔')
275
- : chalk.red(`✖ requires >=${MIN_NODE_VERSION.major}.${MIN_NODE_VERSION.minor}`);
276
326
  const hasUpdate = environment.latestVersion && compareVersions(environment.latestVersion, CLI_VERSION) > 0;
327
+ const nodeValue = environment.nodeSupported
328
+ ? `v${environment.node}`
329
+ : chalk.red(`v${environment.node} (requires >=${MIN_NODE_VERSION.major}.${MIN_NODE_VERSION.minor})`);
330
+ const portValue = environment.portFree
331
+ ? `${environment.port} available`
332
+ : chalk.yellow(`${environment.port} in use`);
277
333
  const rows = [
278
334
  { label: muted('System'), value: environment.system },
279
335
  { label: muted('Device'), value: environment.device },
280
- { label: muted('Node.js'), value: `v${environment.node} ${nodeStatus}` },
281
- {
282
- label: muted('Launched with'),
283
- value: environment.launcher ? `${environment.launcher.name} ${environment.launcher.version}` : 'node (direct)'
284
- },
285
- {
286
- label: muted('Package managers'),
287
- value: managerList.length ? managerList.join(', ') : chalk.yellow('none detected')
288
- },
289
- {
290
- label: muted('Git'),
291
- value: environment.git ? `${environment.git} ${chalk.green('✔')}` : muted('not found')
292
- },
293
- {
294
- label: muted('Port'),
295
- value: `${environment.port} ${environment.portFree ? `${chalk.green('✔')} free` : chalk.yellow('in use')}`
296
- },
336
+ { label: muted('IP address'), value: environment.ipAddress ?? muted('unavailable') },
337
+ { label: muted('Node.js'), value: nodeValue },
338
+ { label: muted('Git'), value: environment.git ?? muted('not found') },
339
+ { label: muted('Port'), value: portValue },
297
340
  {
298
341
  label: muted('Openpack'),
299
342
  value: hasUpdate
300
- ? `v${CLI_VERSION} ${chalk.yellow(`update available: ${environment.latestVersion}`)}`
301
- : `v${CLI_VERSION} ${chalk.green('✔')}`
343
+ ? `v${CLI_VERSION} ${chalk.yellow(`(update available: ${environment.latestVersion})`)}`
344
+ : `v${CLI_VERSION}`
302
345
  }
303
346
  ];
304
347
  console.log(renderCard('Environment', rows));
@@ -308,7 +351,7 @@ const printEnvironmentCard = (environment) => {
308
351
  const printStatusCard = (results) => {
309
352
  const rows = results.map((result) => ({
310
353
  label: `${STATE_ICONS[result.state]} ${result.label}`,
311
- value: result.duration === null ? muted('pending') : muted(`${(result.duration / 1000).toFixed(1)}s`)
354
+ value: STATUS_VALUES[result.state](result)
312
355
  }));
313
356
  console.log();
314
357
  console.log(renderCard('Build status', rows));
@@ -339,13 +382,13 @@ const printHelp = () => {
339
382
  });
340
383
  console.log();
341
384
  console.log(` ${muted('Example')}`);
342
- console.log(` ${PACKAGE_COMMAND} ${accent('my-project --yes --pm pnpm --database-url postgresql://user:pass@localhost:5432/db --no-run')}`);
385
+ console.log(` ${PACKAGE_COMMAND} ${accent('my-project --yes --pm pnpm --no-run')}`);
343
386
  console.log();
344
387
  };
345
388
 
346
389
  const printFailure = (title, detail) => {
347
390
  console.log();
348
- console.log(` ${chalk.red('✖')} ${chalk.bold(title)}`);
391
+ console.log(` ${chalk.red('●')} ${chalk.bold(title)}`);
349
392
  if (detail) console.log(` ${muted(detail)}`);
350
393
  console.log();
351
394
  process.exitCode = 1;
@@ -353,7 +396,7 @@ const printFailure = (title, detail) => {
353
396
 
354
397
  const runCommand = (command, args, cwd) =>
355
398
  new Promise((resolve, reject) => {
356
- const child = spawn(command, args, { cwd, shell: isWindows, stdio: ['ignore', 'ignore', 'pipe'] });
399
+ const child = spawnTool(command, args, { cwd, stdio: ['ignore', 'ignore', 'pipe'] });
357
400
  const errors = [];
358
401
  child.stderr.on('data', (chunk) => errors.push(chunk.toString()));
359
402
  child.on('error', reject);
@@ -366,7 +409,7 @@ const runCommand = (command, args, cwd) =>
366
409
 
367
410
  const runInteractive = (command, args, cwd) =>
368
411
  new Promise((resolve, reject) => {
369
- const child = spawn(command, args, { cwd, shell: isWindows, stdio: 'inherit' });
412
+ const child = spawnTool(command, args, { cwd, stdio: 'inherit' });
370
413
  child.on('error', reject);
371
414
  child.on('close', () => resolve());
372
415
  });
@@ -421,26 +464,19 @@ const askOptions = async (cli, environment) => {
421
464
  placeholder: 'my-project',
422
465
  validate: validateProjectName
423
466
  }),
424
- packageManager: () =>
425
- fixed.packageManager !== undefined
426
- ? Promise.resolve(fixed.packageManager)
427
- : prompts.select({
428
- message: 'Choose a package manager',
429
- initialValue: managers.initial,
430
- options: managers.names.map((value) => ({
431
- value,
432
- label: PACKAGE_MANAGERS[value].label,
433
- hint: environment.managers[value] ? `v${environment.managers[value]}` : undefined
434
- }))
435
- }),
436
- databaseUrl: () =>
437
- fixed.databaseUrl !== undefined
438
- ? Promise.resolve(fixed.databaseUrl)
439
- : prompts.text({
440
- message: 'PostgreSQL DATABASE_URL',
441
- placeholder: 'postgresql://user:password@localhost:5432/mydb',
442
- validate: validateDatabaseUrl
443
- }),
467
+ packageManager: () => {
468
+ if (fixed.packageManager !== undefined) return Promise.resolve(fixed.packageManager);
469
+ if (managers.names.length === 1) return Promise.resolve(managers.names[0]);
470
+ return prompts.select({
471
+ message: 'Choose a package manager',
472
+ initialValue: managers.initial,
473
+ options: managers.names.map((value) => ({
474
+ value,
475
+ label: PACKAGE_MANAGERS[value].label,
476
+ hint: environment.managers[value] ? `v${environment.managers[value]}` : undefined
477
+ }))
478
+ });
479
+ },
444
480
  mode: () =>
445
481
  fixed.mode !== undefined
446
482
  ? Promise.resolve(fixed.mode)
@@ -477,7 +513,6 @@ const askOptions = async (cli, environment) => {
477
513
  const resolveDefaultOptions = async (cli, environment) => {
478
514
  const fixed = readFixedOptions(cli);
479
515
  if (fixed.name === undefined) throw new UsageError('Project name is required in non-interactive mode');
480
- if (fixed.databaseUrl === undefined) throw new UsageError('--database-url is required in non-interactive mode');
481
516
 
482
517
  const mode = fixed.mode ?? (process.stdout.isTTY ? MODES.run : MODES.install);
483
518
  const desired = fixed.port ?? DEFAULT_PORT;
@@ -491,23 +526,12 @@ const resolveDefaultOptions = async (cli, environment) => {
491
526
  return {
492
527
  name: fixed.name,
493
528
  packageManager: fixed.packageManager ?? resolveManagerChoices(environment).initial,
494
- databaseUrl: fixed.databaseUrl,
495
529
  mode,
496
530
  port
497
531
  };
498
532
  };
499
533
 
500
- const checkDatabase = async (databaseUrl) => {
501
- const url = new URL(databaseUrl);
502
- const host = url.hostname.replace(/^\[|\]$/g, '');
503
- const port = Number(url.port) || DEFAULT_DATABASE_PORT;
504
- const target = `${host}:${port}`;
505
- return (await isTcpReachable(host, port))
506
- ? { label: `Database reachable at ${target}` }
507
- : { state: 'warning', label: `Database unreachable at ${target}` };
508
- };
509
-
510
- const buildSteps = ({ name, packageManager, databaseUrl, mode, port }, { dbCheck }) => {
534
+ const buildSteps = ({ name, packageManager, mode, port }) => {
511
535
  const targetDirectory = path.resolve(process.cwd(), name);
512
536
  const manager = PACKAGE_MANAGERS[packageManager];
513
537
  const customPort = port !== DEFAULT_PORT;
@@ -515,7 +539,10 @@ const buildSteps = ({ name, packageManager, databaseUrl, mode, port }, { dbCheck
515
539
  {
516
540
  active: 'Fetching template',
517
541
  done: 'Template fetched',
518
- task: () => downloadTemplate(TEMPLATE_SOURCE, { dir: targetDirectory })
542
+ task: async () => {
543
+ const { downloadTemplate } = await import('giget');
544
+ await downloadTemplate(TEMPLATE_SOURCE, { dir: targetDirectory });
545
+ }
519
546
  },
520
547
  {
521
548
  active: 'Preparing environment',
@@ -528,31 +555,21 @@ const buildSteps = ({ name, packageManager, databaseUrl, mode, port }, { dbCheck
528
555
  },
529
556
  {
530
557
  active: 'Injecting template configuration',
531
- done: customPort ? 'DATABASE_URL, SESSION_SECRET, and PORT injected' : 'DATABASE_URL and SESSION_SECRET injected',
558
+ done: customPort ? 'SESSION_SECRET and PORT injected' : 'SESSION_SECRET injected',
532
559
  task: async () => {
533
560
  const envPath = path.join(targetDirectory, ENV_FILE);
534
561
  const current = await fse.readFile(envPath, 'utf8');
535
- const withDatabase = setEnvValue(current, 'DATABASE_URL', databaseUrl);
536
- const withSecret = setEnvValue(withDatabase, 'SESSION_SECRET', randomBytes(32).toString('hex'));
562
+ const withSecret = setEnvValue(current, 'SESSION_SECRET', randomBytes(32).toString('hex'));
537
563
  await fse.writeFile(envPath, customPort ? setEnvValue(withSecret, 'PORT', String(port)) : withSecret);
538
564
  }
565
+ },
566
+ {
567
+ active: 'Entering project directory',
568
+ done: `Entered ${name}`,
569
+ task: async () => process.chdir(targetDirectory)
539
570
  }
540
571
  ];
541
572
 
542
- if (dbCheck) {
543
- steps.push({
544
- active: 'Checking database connection',
545
- done: 'Database reachable',
546
- task: () => checkDatabase(databaseUrl)
547
- });
548
- }
549
-
550
- steps.push({
551
- active: 'Entering project directory',
552
- done: `Entered ${name}`,
553
- task: async () => process.chdir(targetDirectory)
554
- });
555
-
556
573
  if (mode !== MODES.none) {
557
574
  steps.push({
558
575
  active: `Installing dependencies with ${manager.label}`,
@@ -589,7 +606,7 @@ const runSteps = async (steps, results) => {
589
606
  spinner.stopAndPersist({ symbol: STATE_ICONS[state], text: `${prefix} ${label}` });
590
607
  } catch (error) {
591
608
  results[index] = { label: step.active, state: 'failed', duration: Date.now() - startedAt };
592
- spinner.stopAndPersist({ symbol: STATE_ICONS.failed, text: `${prefix} ${step.active}` });
609
+ spinner.stopAndPersist({ symbol: STATE_ICONS.failed, text: `${prefix} ${step.active} ${chalk.red('failed')}` });
593
610
  throw error;
594
611
  }
595
612
  }
@@ -604,7 +621,7 @@ const printSummary = ({ name, packageManager, mode, port, startedAt }) => {
604
621
  if (mode !== MODES.run) pending.push(devCommand);
605
622
 
606
623
  console.log();
607
- console.log(` ${chalk.green('✔')} ${chalk.bold(name)} is ready ${muted(`in ${duration}s`)}`);
624
+ console.log(` ${chalk.green('●')} ${chalk.bold(name)} is ready ${muted(`in ${duration}s`)}`);
608
625
  console.log();
609
626
  if (mode === MODES.run) {
610
627
  console.log(` ${muted('Server')} ${accent(devUrl)}`);
@@ -663,7 +680,7 @@ async function main() {
663
680
 
664
681
  const options = interactive ? await askOptions(cli, environment) : await resolveDefaultOptions(cli, environment);
665
682
  const originalCwd = process.cwd();
666
- const { steps, targetDirectory, manager } = buildSteps(options, { dbCheck: !cli.values['no-db-check'] });
683
+ const { steps, targetDirectory, manager } = buildSteps(options);
667
684
  const rollback = createRollback(targetDirectory, originalCwd, !(await fse.pathExists(targetDirectory)));
668
685
  const results = steps.map((step) => ({ label: step.done, state: 'pending', duration: null }));
669
686
  const startedAt = performance.now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilanalimanjs/open_pack",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
4
4
  "description": "Open Pack CLI: create a new project from the Open Pack source template",
5
5
  "type": "module",
6
6
  "bin": {