epicshop 6.89.1 → 6.89.3

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.
@@ -8,6 +8,14 @@ export type StartResult = {
8
8
  message?: string;
9
9
  error?: Error;
10
10
  };
11
+ type WorkshopAppAttempt = {
12
+ source: string;
13
+ dir: string;
14
+ };
15
+ type WorkshopAppResolution = {
16
+ appDir: string | null;
17
+ attempts: Array<WorkshopAppAttempt>;
18
+ };
11
19
  /**
12
20
  * Display help information about environment variables and debug logging
13
21
  */
@@ -16,3 +24,10 @@ export declare function displayHelp(): void;
16
24
  * Start the workshop application
17
25
  */
18
26
  export declare function start(options?: StartOptions): Promise<StartResult>;
27
+ export declare function formatWorkshopAppResolutionErrorMessage(attempts: Array<WorkshopAppAttempt>): string;
28
+ export declare function findGlobalWorkshopApp(options?: {
29
+ env?: NodeJS.ProcessEnv;
30
+ homeDir?: string;
31
+ npmRoot?: string;
32
+ }): Promise<WorkshopAppResolution>;
33
+ export {};
@@ -61,11 +61,20 @@ export function displayHelp() {
61
61
  export async function start(options = {}) {
62
62
  try {
63
63
  // Find workshop-app directory using new resolution order
64
- const appDir = await findWorkshopAppDir(options.appLocation);
65
- if (!appDir) {
66
- const errorMessage = 'Could not locate workshop-app directory. Please ensure the workshop app is installed or specify its location using:\n - Environment variable: EPICSHOP_APP_LOCATION\n - Command line flag: --app-location\n - Global installation: npm install -g @epic-web/workshop-app';
64
+ const resolution = await findWorkshopAppDir(options.appLocation);
65
+ if (!resolution.appDir) {
66
+ const errorMessage = formatWorkshopAppResolutionErrorMessage(resolution.attempts);
67
67
  if (!options.silent) {
68
68
  console.error(chalk.red('❌ Could not locate workshop-app directory'));
69
+ console.error(chalk.yellow('Tried these directories:'));
70
+ if (resolution.attempts.length > 0) {
71
+ for (const attempt of resolution.attempts) {
72
+ console.error(chalk.yellow(` - ${attempt.source}: ${attempt.dir}`));
73
+ }
74
+ }
75
+ else {
76
+ console.error(chalk.yellow(' - No candidate directories were tried'));
77
+ }
69
78
  console.error(chalk.yellow('Please ensure the workshop app is installed or specify its location using:'));
70
79
  console.error(chalk.yellow(' - Environment variable: EPICSHOP_APP_LOCATION'));
71
80
  console.error(chalk.yellow(' - Command line flag: --app-location'));
@@ -77,6 +86,7 @@ export async function start(options = {}) {
77
86
  error: new Error(errorMessage),
78
87
  };
79
88
  }
89
+ const appDir = resolution.appDir;
80
90
  const isPublished = await appIsPublished(appDir);
81
91
  const isProd = process.env.NODE_ENV === 'production' || isPublished;
82
92
  const isDeployed = process.env.EPICSHOP_DEPLOYED === 'true' ||
@@ -453,6 +463,35 @@ export async function start(options = {}) {
453
463
  };
454
464
  }
455
465
  }
466
+ const workshopAppHelpLines = [
467
+ 'Please ensure the workshop app is installed or specify its location using:',
468
+ ' - Environment variable: EPICSHOP_APP_LOCATION',
469
+ ' - Command line flag: --app-location',
470
+ ' - Global installation: npm install -g @epic-web/workshop-app',
471
+ ];
472
+ export function formatWorkshopAppResolutionErrorMessage(attempts) {
473
+ const lines = [
474
+ 'Could not locate workshop-app directory.',
475
+ 'Tried these directories:',
476
+ ];
477
+ if (attempts.length > 0) {
478
+ lines.push(...attempts.map((attempt) => ` - ${attempt.source}: ${attempt.dir}`));
479
+ }
480
+ else {
481
+ lines.push(' - No candidate directories were tried');
482
+ }
483
+ lines.push(...workshopAppHelpLines);
484
+ return lines.join('\n');
485
+ }
486
+ async function resolveWorkshopAppCandidate(candidate) {
487
+ try {
488
+ await fs.promises.access(path.join(candidate.dir, 'package.json'));
489
+ return candidate.dir;
490
+ }
491
+ catch {
492
+ return null;
493
+ }
494
+ }
456
495
  // Helper functions
457
496
  async function killChild(child) {
458
497
  if (!child)
@@ -500,43 +539,49 @@ async function killChild(child) {
500
539
  });
501
540
  }
502
541
  async function findWorkshopAppDir(appLocation) {
542
+ const attempts = [];
503
543
  // 1. Check process.env.EPICSHOP_APP_LOCATION
504
544
  if (process.env.EPICSHOP_APP_LOCATION) {
505
- const envDir = path.resolve(process.env.EPICSHOP_APP_LOCATION);
506
- try {
507
- await fs.promises.access(path.join(envDir, 'package.json'));
508
- return envDir;
509
- }
510
- catch {
511
- // Continue to next step
512
- }
545
+ const candidate = {
546
+ source: 'EPICSHOP_APP_LOCATION',
547
+ dir: path.resolve(process.env.EPICSHOP_APP_LOCATION),
548
+ };
549
+ attempts.push(candidate);
550
+ const envDir = await resolveWorkshopAppCandidate(candidate);
551
+ if (envDir)
552
+ return { appDir: envDir, attempts };
513
553
  }
514
554
  // 2. Check command line flag --app-location
515
555
  if (appLocation) {
516
- const flagDir = path.resolve(appLocation);
517
- try {
518
- await fs.promises.access(path.join(flagDir, 'package.json'));
519
- return flagDir;
520
- }
521
- catch {
522
- // Continue to next step
523
- }
556
+ const candidate = {
557
+ source: '--app-location',
558
+ dir: path.resolve(appLocation),
559
+ };
560
+ attempts.push(candidate);
561
+ const flagDir = await resolveWorkshopAppCandidate(candidate);
562
+ if (flagDir)
563
+ return { appDir: flagDir, attempts };
524
564
  }
525
565
  // 3. Node's resolution process
526
566
  try {
527
- const workshopAppPath = import.meta
528
- .resolve('@epic-web/workshop-app/package.json');
529
- const packagePath = fileURLToPath(workshopAppPath);
530
- return path.dirname(packagePath);
567
+ const candidate = {
568
+ source: 'node module resolution',
569
+ dir: path.dirname(fileURLToPath(import.meta.resolve('@epic-web/workshop-app/package.json'))),
570
+ };
571
+ attempts.push(candidate);
572
+ const packagePath = await resolveWorkshopAppCandidate(candidate);
573
+ if (packagePath)
574
+ return { appDir: packagePath, attempts };
531
575
  }
532
576
  catch {
533
577
  // Continue to next step
534
578
  }
535
579
  // 4. Global installation lookup
536
580
  try {
537
- const globalDir = await findGlobalWorkshopApp();
538
- if (globalDir) {
539
- return globalDir;
581
+ const globalResolution = await findGlobalWorkshopApp();
582
+ attempts.push(...globalResolution.attempts);
583
+ if (globalResolution.appDir) {
584
+ return { appDir: globalResolution.appDir, attempts };
540
585
  }
541
586
  }
542
587
  catch {
@@ -546,53 +591,70 @@ async function findWorkshopAppDir(appLocation) {
546
591
  try {
547
592
  const cliPkgPath = import.meta.resolve('epicshop/package.json');
548
593
  const cliPkgDir = path.dirname(fileURLToPath(cliPkgPath));
549
- const relativePath = path.resolve(cliPkgDir, '..', '..', 'workshop-app');
550
- try {
551
- await fs.promises.access(path.join(relativePath, 'package.json'));
552
- return relativePath;
553
- }
554
- catch {
555
- // Continue to final return
556
- }
594
+ const candidate = {
595
+ source: 'monorepo fallback',
596
+ dir: path.resolve(cliPkgDir, '..', '..', 'workshop-app'),
597
+ };
598
+ attempts.push(candidate);
599
+ const relativePath = await resolveWorkshopAppCandidate(candidate);
600
+ if (relativePath)
601
+ return { appDir: relativePath, attempts };
557
602
  }
558
603
  catch {
559
604
  // Continue to final return
560
605
  }
561
- return null;
606
+ return { appDir: null, attempts };
562
607
  }
563
- async function findGlobalWorkshopApp() {
564
- // Try to find globally installed workshop app
565
- try {
566
- const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
567
- const globalAppPath = path.join(npmRoot, '@epic-web/workshop-app');
568
- try {
569
- await fs.promises.access(path.join(globalAppPath, 'package.json'));
570
- return globalAppPath;
571
- }
572
- catch {
573
- // Continue to common global locations
608
+ function getGlobalNodeModulesPathFromPrefix(prefix) {
609
+ return path.join(path.resolve(prefix), process.platform === 'win32' ? 'node_modules' : 'lib', 'node_modules');
610
+ }
611
+ function getGlobalWorkshopAppCandidatePaths(env, homeDir, npmRoot) {
612
+ const candidatePaths = new Map();
613
+ const addCandidate = (source, dir) => {
614
+ const resolvedDir = path.resolve(dir);
615
+ if (!candidatePaths.has(resolvedDir)) {
616
+ candidatePaths.set(resolvedDir, { source, dir: resolvedDir });
574
617
  }
618
+ };
619
+ const addCandidateFromPrefix = (source, prefix) => {
620
+ if (!prefix)
621
+ return;
622
+ addCandidate(source, path.join(getGlobalNodeModulesPathFromPrefix(prefix), '@epic-web/workshop-app'));
623
+ };
624
+ // When `epicshop` is started through `npx --prefix`, npm rewrites
625
+ // `npm root -g` to that local prefix. The original global prefix can still
626
+ // be available via the uppercase env var, so prefer it first.
627
+ addCandidateFromPrefix('NPM_CONFIG_PREFIX', env.NPM_CONFIG_PREFIX);
628
+ if (npmRoot) {
629
+ addCandidate('npm root -g', path.join(npmRoot, '@epic-web/workshop-app'));
575
630
  }
576
- catch {
577
- // If npm root -g fails, try common global locations
578
- }
579
- // Try common global locations
580
- const commonGlobalPaths = [
581
- path.join(os.homedir(), '.npm-global/lib/node_modules/@epic-web/workshop-app'),
582
- path.join(os.homedir(), '.npm-packages/lib/node_modules/@epic-web/workshop-app'),
583
- '/usr/local/lib/node_modules/@epic-web/workshop-app',
584
- '/usr/lib/node_modules/@epic-web/workshop-app',
585
- ];
586
- for (const globalPath of commonGlobalPaths) {
631
+ addCandidateFromPrefix('npm_config_prefix', env.npm_config_prefix);
632
+ addCandidate('~/.npm-global', path.join(homeDir, '.npm-global/lib/node_modules/@epic-web/workshop-app'));
633
+ addCandidate('~/.npm-packages', path.join(homeDir, '.npm-packages/lib/node_modules/@epic-web/workshop-app'));
634
+ addCandidate('system global (/usr/local)', '/usr/local/lib/node_modules/@epic-web/workshop-app');
635
+ addCandidate('system global (/usr)', '/usr/lib/node_modules/@epic-web/workshop-app');
636
+ return [...candidatePaths.values()];
637
+ }
638
+ export async function findGlobalWorkshopApp(options) {
639
+ const env = options?.env ?? process.env;
640
+ const homeDir = options?.homeDir ?? os.homedir();
641
+ let npmRoot = options?.npmRoot;
642
+ if (!npmRoot) {
587
643
  try {
588
- await fs.promises.access(path.join(globalPath, 'package.json'));
589
- return globalPath;
644
+ npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
590
645
  }
591
646
  catch {
592
- // Continue to next path
647
+ // If npm root -g fails, continue with env-derived and common locations.
648
+ }
649
+ }
650
+ const attempts = getGlobalWorkshopAppCandidatePaths(env, homeDir, npmRoot);
651
+ for (const globalPath of attempts) {
652
+ const resolvedPath = await resolveWorkshopAppCandidate(globalPath);
653
+ if (resolvedPath) {
654
+ return { appDir: resolvedPath, attempts };
593
655
  }
594
656
  }
595
- return null;
657
+ return { appDir: null, attempts };
596
658
  }
597
659
  async function appIsPublished(appDir) {
598
660
  if (process.env.EPICSHOP_IS_PUBLISHED) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epicshop",
3
- "version": "6.89.1",
3
+ "version": "6.89.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -105,7 +105,7 @@
105
105
  "build:watch": "nx watch --projects=epicshop -- nx run \\$NX_PROJECT_NAME:build"
106
106
  },
107
107
  "dependencies": {
108
- "@epic-web/workshop-utils": "6.89.1",
108
+ "@epic-web/workshop-utils": "6.89.3",
109
109
  "@inquirer/prompts": "^8.2.0",
110
110
  "@sentry/node": "^10.38.0",
111
111
  "chalk": "^5.6.2",