fabrica-e-commerce 0.1.1 → 0.1.2

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 (3) hide show
  1. package/package.json +1 -1
  2. package/src/deps.js +80 -10
  3. package/src/system.js +15 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabrica-e-commerce",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Orange themed CMD launcher for deploying Fabrica e-commerce stores with Supabase and Vercel.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/deps.js CHANGED
@@ -1,3 +1,5 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import process from 'node:process';
2
4
  import { commandExists, runCommand, runCommandCapture } from './system.js';
3
5
  import { kv, section, spinner } from './ui.js';
@@ -23,14 +25,14 @@ const DEPENDENCIES = [
23
25
  {
24
26
  name: 'git',
25
27
  label: 'Git',
26
- check: () => commandExists('git'),
28
+ check: () => checkWithPathRefresh('git'),
27
29
  install: installGit,
28
30
  manualUrl: 'https://git-scm.com/downloads'
29
31
  },
30
32
  {
31
33
  name: 'gh',
32
34
  label: 'GitHub CLI (gh)',
33
- check: () => commandExists('gh'),
35
+ check: () => checkWithPathRefresh('gh'),
34
36
  install: installGithubCli,
35
37
  manualUrl: 'https://github.com/cli/cli#installation'
36
38
  },
@@ -43,18 +45,69 @@ const DEPENDENCIES = [
43
45
  }
44
46
  ];
45
47
 
48
+
49
+ function addToPathIfDirectory(directory) {
50
+ if (!directory || !fs.existsSync(directory)) return;
51
+ const delimiter = path.delimiter;
52
+ const current = process.env.PATH || '';
53
+ const entries = current.split(delimiter).filter(Boolean);
54
+ if (!entries.some((entry) => entry.toLowerCase() === directory.toLowerCase())) {
55
+ process.env.PATH = `${directory}${delimiter}${current}`;
56
+ }
57
+ }
58
+
59
+ function refreshWindowsToolPaths() {
60
+ if (process.platform !== 'win32') return;
61
+ const localAppData = process.env.LOCALAPPDATA;
62
+ const programFiles = process.env.ProgramFiles;
63
+ const programFilesX86 = process.env['ProgramFiles(x86)'];
64
+ const programData = process.env.ProgramData;
65
+ addToPathIfDirectory(localAppData && path.join(localAppData, 'Microsoft', 'WinGet', 'Links'));
66
+ addToPathIfDirectory(programFiles && path.join(programFiles, 'GitHub CLI'));
67
+ addToPathIfDirectory(programFilesX86 && path.join(programFilesX86, 'GitHub CLI'));
68
+ addToPathIfDirectory(programData && path.join(programData, 'chocolatey', 'bin'));
69
+ addToPathIfDirectory(programFiles && path.join(programFiles, 'Git', 'cmd'));
70
+ addToPathIfDirectory(programFiles && path.join(programFiles, 'nodejs'));
71
+ }
72
+
73
+ async function checkWithPathRefresh(command) {
74
+ refreshWindowsToolPaths();
75
+ return commandExists(command);
76
+ }
77
+
78
+ async function runFirstSuccessful(candidates, options = {}) {
79
+ for (const [command, args] of candidates) {
80
+ const result = await runCommandCapture(command, args, options);
81
+ if (result.code === 0) return result;
82
+ }
83
+ return { code: 1, stdout: '', stderr: 'All fallback commands failed' };
84
+ }
85
+
46
86
  async function checkVercelCli() {
47
- const result = await runCommandCapture('npx', ['--yes', 'vercel@latest', '--version']);
87
+ refreshWindowsToolPaths();
88
+ const result = await runFirstSuccessful([
89
+ ['npx', ['--yes', 'vercel@latest', '--version']],
90
+ ['npm', ['exec', '--yes', 'vercel@latest', '--', '--version']],
91
+ ['vercel', ['--version']]
92
+ ]);
48
93
  return result.code === 0;
49
94
  }
50
95
 
51
96
  async function warmVercelCli() {
52
- // npx fetches vercel on first use, so "installing" it just means priming
53
- // the npm cache once so later `build`/`list` calls are instant.
54
- await runCommand('npx', ['--yes', 'vercel@latest', '--version'], { allowFailure: true });
97
+ refreshWindowsToolPaths();
98
+ const warmed = await runFirstSuccessful([
99
+ ['npx', ['--yes', 'vercel@latest', '--version']],
100
+ ['npm', ['exec', '--yes', 'vercel@latest', '--', '--version']],
101
+ ['vercel', ['--version']]
102
+ ]);
103
+ if (warmed.code === 0) return;
104
+ // Last resort: install a global Vercel binary so future invocations have a
105
+ // real `vercel` executable even when npx/npm exec cannot launch correctly.
106
+ await runCommand('npm', ['install', '-g', 'vercel@latest'], { allowFailure: true });
55
107
  }
56
108
 
57
109
  async function installGit() {
110
+ refreshWindowsToolPaths();
58
111
  const platform = process.platform;
59
112
  if (platform === 'linux') {
60
113
  if (await commandExists('apt-get')) {
@@ -70,12 +123,21 @@ async function installGit() {
70
123
  if (await commandExists('brew')) return runCommand('brew', ['install', 'git'], { allowFailure: true });
71
124
  }
72
125
  if (platform === 'win32') {
73
- if (await commandExists('winget')) return runCommand('winget', ['install', '--id', 'Git.Git', '-e', '--source', 'winget'], { allowFailure: true });
74
- if (await commandExists('choco')) return runCommand('choco', ['install', 'git', '-y'], { allowFailure: true });
126
+ if (await commandExists('winget')) {
127
+ await runCommand('winget', ['install', '--id', 'Git.Git', '-e', '--source', 'winget'], { allowFailure: true });
128
+ refreshWindowsToolPaths();
129
+ return;
130
+ }
131
+ if (await commandExists('choco')) {
132
+ await runCommand('choco', ['install', 'git', '-y'], { allowFailure: true });
133
+ refreshWindowsToolPaths();
134
+ return;
135
+ }
75
136
  }
76
137
  }
77
138
 
78
139
  async function installGithubCli() {
140
+ refreshWindowsToolPaths();
79
141
  const platform = process.platform;
80
142
  if (platform === 'linux') {
81
143
  if (await commandExists('apt-get')) {
@@ -107,8 +169,16 @@ async function installGithubCli() {
107
169
  if (await commandExists('brew')) return runCommand('brew', ['install', 'gh'], { allowFailure: true });
108
170
  }
109
171
  if (platform === 'win32') {
110
- if (await commandExists('winget')) return runCommand('winget', ['install', '--id', 'GitHub.cli', '-e', '--source', 'winget'], { allowFailure: true });
111
- if (await commandExists('choco')) return runCommand('choco', ['install', 'gh', '-y'], { allowFailure: true });
172
+ if (await commandExists('winget')) {
173
+ await runCommand('winget', ['install', '--id', 'GitHub.cli', '-e', '--source', 'winget'], { allowFailure: true });
174
+ refreshWindowsToolPaths();
175
+ return;
176
+ }
177
+ if (await commandExists('choco')) {
178
+ await runCommand('choco', ['install', 'gh', '-y'], { allowFailure: true });
179
+ refreshWindowsToolPaths();
180
+ return;
181
+ }
112
182
  }
113
183
  }
114
184
 
package/src/system.js CHANGED
@@ -7,13 +7,22 @@ function executable(command) {
7
7
  return command;
8
8
  }
9
9
 
10
+ function spawnOptions(options = {}, stdio) {
11
+ return {
12
+ stdio,
13
+ // Windows package-manager shims such as npm.cmd/npx.cmd can throw
14
+ // `spawn EINVAL` when launched directly from some terminals. Running
15
+ // through the platform shell preserves Unix behavior while making those
16
+ // Windows shim commands reliable.
17
+ shell: process.platform === 'win32',
18
+ cwd: options.cwd,
19
+ env: options.env || process.env
20
+ };
21
+ }
22
+
10
23
  export function runCommand(command, args, options = {}) {
11
24
  return new Promise((resolve, reject) => {
12
- const child = spawn(executable(command), args, {
13
- stdio: options.input ? ['pipe', 'inherit', 'inherit'] : 'inherit',
14
- shell: false,
15
- cwd: options.cwd
16
- });
25
+ const child = spawn(executable(command), args, spawnOptions(options, options.input ? ['pipe', 'inherit', 'inherit'] : 'inherit'));
17
26
  if (options.input) child.stdin.end(options.input);
18
27
  child.on('error', (error) => {
19
28
  if (options.allowFailure) resolve();
@@ -31,11 +40,7 @@ export function runCommandCapture(command, args, options = {}) {
31
40
  return new Promise((resolve) => {
32
41
  let child;
33
42
  try {
34
- child = spawn(executable(command), args, {
35
- stdio: 'pipe',
36
- shell: false,
37
- cwd: options.cwd
38
- });
43
+ child = spawn(executable(command), args, spawnOptions(options, 'pipe'));
39
44
  } catch (error) {
40
45
  resolve({ code: null, stdout: '', stderr: '', error });
41
46
  return;