@enfyra/create-app 0.1.37 → 0.1.39

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.md CHANGED
@@ -15,17 +15,22 @@ npx @enfyra/create-server my-backend
15
15
 
16
16
  šŸ‘‰ **[Backend Setup Guide](https://www.npmjs.com/package/@enfyra/create-server)** - Complete instructions for setting up your Enfyra backend
17
17
 
18
+ The frontend does not own backend secrets. For self-hosted backends, keep the server `SECRET_KEY` stable and backed up because it signs auth tokens and decrypts fields marked `isEncrypted=true`.
19
+
18
20
  ## Quick Start
19
21
 
20
22
  ```bash
21
- # Using npx (recommended)
23
+ # Using npx
22
24
  npx @enfyra/create-app
23
25
 
26
+ # Using npm
27
+ npm exec @enfyra/create-app
28
+
24
29
  # Using yarn
25
- yarn create @enfyra/app
30
+ yarn dlx @enfyra/create-app
26
31
 
27
32
  # Using pnpm
28
- pnpm create @enfyra/app
33
+ pnpm dlx @enfyra/create-app
29
34
 
30
35
  # Or install globally
31
36
  npm install -g @enfyra/create-app
@@ -49,7 +54,7 @@ create-app
49
54
  ## Requirements
50
55
 
51
56
  - **Node.js** 20.0.0 or higher
52
- - **Package manager**: npm (8+), yarn (1.22+), pnpm (7+), or bun (1+)
57
+ - **Package manager**: npm, yarn, or pnpm
53
58
 
54
59
  ## Usage
55
60
 
@@ -102,25 +107,23 @@ npm run preview # Preview production build
102
107
 
103
108
  ### Learn More
104
109
 
105
- šŸ“– **[Complete Documentation](https://github.com/dothinh115/enfyra-app#readme)** - Full guide to building with Enfyra
106
- šŸ”§ **[API Reference](https://github.com/dothinh115/enfyra-app/blob/main/docs/API.md)** - Backend integration
107
- šŸŽØ **[UI Components](https://github.com/dothinh115/enfyra-app/blob/main/docs/COMPONENTS.md)** - Pre-built components
108
- ⚔ **[Best Practices](https://github.com/dothinh115/enfyra-app/blob/main/docs/BEST_PRACTICES.md)** - Development guidelines
110
+ šŸ“– **[Complete Documentation](https://github.com/enfyra/documents)** - Full guide to building with Enfyra
111
+ šŸ”§ **[Installation Guide](https://github.com/enfyra/documents/blob/main/getting-started/installation.md)** - Backend and frontend setup
112
+ šŸŽØ **[App Documentation](https://github.com/enfyra/app#readme)** - Frontend application template
109
113
 
110
114
  ## Support
111
115
 
112
116
  Having issues? We're here to help:
113
117
 
114
- - šŸ› [Report bugs](https://github.com/dothinh115/create-enfyra-app/issues)
115
- - šŸ’¬ [Ask questions](https://github.com/dothinh115/enfyra-app/discussions)
116
- - šŸ“§ [Email support](mailto:dothinh115@gmail.com)
118
+ - šŸ› [Report bugs](https://github.com/enfyra/create-enfyra-app/issues)
119
+ - šŸ’¬ [Ask questions](https://github.com/enfyra/app/discussions)
117
120
 
118
121
  ## Related
119
122
 
120
- - **[Enfyra App](https://github.com/dothinh115/enfyra-app)** - The frontend template
121
- - **[Enfyra BE](https://github.com/dothinh115/enfyra_be)** - Backend framework
122
- - **[Create Enfyra Server](https://github.com/dothinh115/create-enfyra-server)** - Backend CLI
123
+ - **[Enfyra App](https://github.com/enfyra/app)** - The frontend template
124
+ - **[Enfyra Server](https://github.com/enfyra/server)** - Backend framework
125
+ - **[Create Enfyra Server](https://github.com/enfyra/create-enfyra-server)** - Backend CLI
123
126
 
124
127
  ---
125
128
 
126
- Built by [dothinh115](https://github.com/dothinh115) • MIT License
129
+ Built by Enfyra Team • MIT License
@@ -6,50 +6,19 @@ const { spawn, execSync } = require('child_process');
6
6
  const { downloadTemplate } = require('giget');
7
7
  const { generateEnvFile } = require('./env-builder');
8
8
 
9
- // Check available package managers with version validation
10
9
  function detectPackageManagers() {
11
10
  const managers = [];
12
-
13
- // Check npm (minimum version 8.0.0)
14
- try {
15
- const npmVersion = execSync('npm --version', {
16
- encoding: 'utf8',
17
- stdio: 'pipe',
18
- shell: true
19
- }).trim();
20
- const majorVersion = parseInt(npmVersion.split('.')[0]);
21
- if (majorVersion >= 8) {
22
- managers.push({ name: 'npm', value: 'npm', version: npmVersion });
23
- }
24
- } catch {}
25
-
26
- // Check yarn (minimum version 1.22.0)
27
- try {
28
- const yarnVersion = execSync('yarn --version', {
29
- encoding: 'utf8',
30
- stdio: 'pipe',
31
- shell: true
32
- }).trim();
33
- const [major, minor] = yarnVersion.split('.').map(Number);
34
- if (major > 1 || (major === 1 && minor >= 22)) {
35
- managers.push({ name: 'yarn', value: 'yarn', version: yarnVersion });
36
- }
37
- } catch {}
38
-
39
- // Check pnpm (minimum version 7.0.0)
40
- try {
41
- const pnpmVersion = execSync('pnpm --version', {
42
- encoding: 'utf8',
43
- stdio: 'pipe',
44
- shell: true
45
- }).trim();
46
- const majorVersion = parseInt(pnpmVersion.split('.')[0]);
47
- if (majorVersion >= 7) {
48
- managers.push({ name: 'pnpm', value: 'pnpm', version: pnpmVersion });
49
- }
50
- } catch {}
51
-
52
- // Note: bun is not supported due to native binding compatibility issues
11
+
12
+ for (const name of ['npm', 'yarn', 'pnpm']) {
13
+ try {
14
+ const version = execSync(`${name} --version`, {
15
+ encoding: 'utf8',
16
+ stdio: 'pipe',
17
+ shell: true
18
+ }).trim();
19
+ managers.push({ name, value: name, version });
20
+ } catch {}
21
+ }
53
22
 
54
23
  return managers;
55
24
  }
@@ -139,7 +108,6 @@ async function updatePackageJson(projectPath, config) {
139
108
  }
140
109
 
141
110
  async function cleanPackageManagerRestrictions(projectPath) {
142
- // List of files that can restrict package manager usage
143
111
  const restrictionFiles = [
144
112
  '.npmrc',
145
113
  '.yarnrc',
@@ -147,8 +115,7 @@ async function cleanPackageManagerRestrictions(projectPath) {
147
115
  'pnpm-workspace.yaml',
148
116
  'package-lock.json',
149
117
  'yarn.lock',
150
- 'pnpm-lock.yaml',
151
- 'bun.lockb'
118
+ 'pnpm-lock.yaml'
152
119
  ];
153
120
 
154
121
  for (const file of restrictionFiles) {
@@ -159,17 +126,25 @@ async function cleanPackageManagerRestrictions(projectPath) {
159
126
  }
160
127
  }
161
128
 
162
- // Also check package.json for packageManager field and engines restrictions
163
129
  const packageJsonPath = path.join(projectPath, 'package.json');
164
130
  if (fs.existsSync(packageJsonPath)) {
165
131
  const packageJson = await fs.readJson(packageJsonPath);
166
132
 
167
- // Remove packageManager field that locks to specific manager
168
133
  if (packageJson.packageManager) {
169
134
  delete packageJson.packageManager;
170
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
171
135
  console.log(chalk.yellow('Removed packageManager restriction from package.json'));
172
136
  }
137
+
138
+ if (packageJson.engines) {
139
+ delete packageJson.engines.npm;
140
+ delete packageJson.engines.yarn;
141
+ delete packageJson.engines.pnpm;
142
+ if (Object.keys(packageJson.engines).length === 0) {
143
+ delete packageJson.engines;
144
+ }
145
+ }
146
+
147
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
173
148
  }
174
149
  }
175
150
 
@@ -221,11 +196,9 @@ async function installDependencies(projectPath, config) {
221
196
 
222
197
 
223
198
  async function initializeGit(projectPath) {
224
- // Check if git is available
225
199
  try {
226
200
  execSync('git --version', { stdio: 'pipe', shell: true });
227
201
  } catch {
228
- // Git is not available, skip initialization
229
202
  return;
230
203
  }
231
204
 
@@ -235,43 +208,35 @@ async function initializeGit(projectPath) {
235
208
  stdio: 'pipe',
236
209
  shell: true
237
210
  });
238
-
211
+
239
212
  gitInit.on('close', (code) => {
240
- if (code === 0) {
241
- // Add initial commit
242
- const gitAdd = spawn('git', ['add', '.'], {
213
+ if (code !== 0) { resolve(); return; }
214
+
215
+ const gitAdd = spawn('git', ['add', '.'], {
216
+ cwd: projectPath,
217
+ stdio: 'pipe',
218
+ shell: true
219
+ });
220
+
221
+ gitAdd.on('close', (addCode) => {
222
+ if (addCode !== 0) { resolve(); return; }
223
+
224
+ const gitCommit = spawn('git', ['commit', '-m', 'Initial commit from create-app'], {
243
225
  cwd: projectPath,
244
226
  stdio: 'pipe',
245
227
  shell: true
246
228
  });
247
-
248
- gitAdd.on('close', (addCode) => {
249
- if (addCode === 0) {
250
- const gitCommit = spawn('git', ['commit', '-m', 'Initial commit from create-app'], {
251
- cwd: projectPath,
252
- stdio: 'pipe',
253
- shell: true
254
- });
255
-
256
- gitCommit.on('close', () => {
257
- resolve();
258
- });
259
- } else {
260
- resolve();
261
- }
262
- });
263
- } else {
264
- resolve();
265
- }
266
- });
267
-
268
- gitInit.on('error', () => {
269
- resolve();
229
+
230
+ gitCommit.on('close', () => resolve());
231
+ });
270
232
  });
233
+
234
+ gitInit.on('error', () => resolve());
271
235
  });
272
236
  }
273
237
 
274
238
  module.exports = {
275
239
  setupProject,
276
- detectPackageManagers
277
- };
240
+ detectPackageManagers,
241
+ cleanPackageManagerRestrictions
242
+ };
@@ -48,8 +48,7 @@ function getPackageManagerIcon(name) {
48
48
  const icons = {
49
49
  npm: 'šŸ“¦',
50
50
  yarn: '🧶',
51
- pnpm: '⚔',
52
- bun: 'šŸš€'
51
+ pnpm: '⚔'
53
52
  };
54
53
  return icons[name] || 'šŸ“¦';
55
54
  }
@@ -66,4 +65,4 @@ async function promptForConfiguration(initialProjectName, availableManagers) {
66
65
 
67
66
  module.exports = {
68
67
  promptForConfiguration
69
- };
68
+ };
package/index.js CHANGED
@@ -4,6 +4,7 @@ const { Command } = require('commander');
4
4
  const chalk = require('chalk');
5
5
  const fs = require('fs-extra');
6
6
  const path = require('path');
7
+ const { execSync } = require('child_process');
7
8
  const inquirer = require('inquirer');
8
9
  const { checkNodeVersion } = require('./components/validators');
9
10
  const { promptForConfiguration } = require('./components/prompts');
@@ -12,7 +13,8 @@ const { setupProject, detectPackageManagers } = require('./components/project-se
12
13
  const program = new Command();
13
14
  const packageJson = require('./package.json');
14
15
 
15
- // ASCII Art Banner
16
+ const ENFYRA_UPSTREAM = 'https://github.com/enfyra/app.git';
17
+
16
18
  const banner = `
17
19
  ${chalk.cyan.bold('╔═══════════════════════════════════════╗')}
18
20
  ${chalk.cyan.bold('ā•‘')} ${chalk.white.bold('šŸš€ Create Enfyra App')} ${chalk.cyan.bold('ā•‘')}
@@ -20,32 +22,113 @@ ${chalk.cyan.bold('ā•‘')} ${chalk.gray('Frontend scaffolding made easy')}
20
22
  ${chalk.cyan.bold('ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•')}
21
23
  `;
22
24
 
23
- async function main() {
25
+ async function upgradeProject() {
24
26
  console.log(banner);
25
-
27
+ console.log(chalk.blue.bold('⬆ Upgrade Enfyra App\n'));
28
+
29
+ checkNodeVersion();
30
+
31
+ const cwd = process.cwd();
32
+ const nuxtConfig = fs.existsSync(path.join(cwd, 'nuxt.config.ts')) || fs.existsSync(path.join(cwd, 'nuxt.config.js'));
33
+ if (!nuxtConfig) {
34
+ console.log(chalk.red('āŒ Not an Enfyra app directory. Run this command inside your Enfyra project root.'));
35
+ process.exit(1);
36
+ }
37
+
38
+ try {
39
+ execSync('git --version', { stdio: 'pipe', shell: true });
40
+ } catch {
41
+ console.log(chalk.red('āŒ Git is required for upgrade. Please install git first.'));
42
+ process.exit(1);
43
+ }
44
+
45
+ let hasUpstream = false;
46
+ try {
47
+ const remotes = execSync('git remote', { cwd, encoding: 'utf8', stdio: 'pipe', shell: true }).trim();
48
+ hasUpstream = remotes.split('\n').includes('upstream');
49
+ } catch {}
50
+
51
+ if (!hasUpstream) {
52
+ console.log(chalk.yellow('This project does not have an upstream remote configured.'));
53
+ console.log(chalk.gray(`Upstream points to the official Enfyra app repository (${ENFYRA_UPSTREAM}).`));
54
+ console.log(chalk.gray('Adding it allows you to pull the latest framework updates and merge them into your project.'));
55
+ console.log(chalk.gray('Your custom code will not be affected unless it conflicts with upstream changes.\n'));
56
+
57
+ const { confirmUpstream } = await inquirer.prompt([
58
+ {
59
+ type: 'confirm',
60
+ name: 'confirmUpstream',
61
+ message: 'Add upstream remote to this project?',
62
+ default: true
63
+ }
64
+ ]);
65
+
66
+ if (!confirmUpstream) {
67
+ console.log(chalk.gray('\nUpgrade cancelled.'));
68
+ process.exit(0);
69
+ }
70
+
71
+ execSync(`git remote add upstream ${ENFYRA_UPSTREAM}`, { cwd, stdio: 'pipe', shell: true });
72
+ console.log(chalk.green('āœ“ upstream remote added\n'));
73
+ }
74
+
75
+ console.log(chalk.gray('Fetching upstream...'));
76
+ execSync('git fetch upstream', { cwd, stdio: 'pipe', shell: true });
77
+ console.log(chalk.green('āœ“ upstream fetched'));
78
+
79
+ const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf8', shell: true }).trim();
80
+ console.log(chalk.gray(`Current branch: ${currentBranch}\n`));
81
+
82
+ console.log(chalk.gray('Merging upstream/main...'));
83
+ try {
84
+ execSync(`git merge upstream/main --no-edit`, { cwd, stdio: 'pipe', shell: true });
85
+ console.log(chalk.green.bold('\nšŸŽ‰ Upgrade completed successfully!'));
86
+ } catch {
87
+ const status = execSync('git status --porcelain', { cwd, encoding: 'utf8', shell: true });
88
+ if (status.includes('UU') || status.includes('AA')) {
89
+ console.log(chalk.yellow.bold('\n⚠ Merge conflicts detected!'));
90
+ console.log(chalk.gray('Resolve the conflicts listed below, then commit:'));
91
+ console.log(chalk.gray(' git add .'));
92
+ console.log(chalk.gray(' git commit\n'));
93
+ const lines = status.split('\n').filter(l => l.trim());
94
+ lines.forEach(l => {
95
+ if (l.startsWith('UU') || l.startsWith('AA')) {
96
+ console.log(chalk.red(` CONFLICT: ${l.slice(3)}`));
97
+ }
98
+ });
99
+ } else {
100
+ throw new Error('Merge failed');
101
+ }
102
+ }
103
+
104
+ try {
105
+ execSync('git remote remove upstream', { cwd, stdio: 'pipe', shell: true });
106
+ console.log(chalk.gray('\nāœ“ upstream remote removed'));
107
+ } catch {}
108
+ }
109
+
110
+ async function createProject() {
111
+ console.log(banner);
112
+
26
113
  try {
27
- // Check Node.js version
28
114
  checkNodeVersion();
29
-
30
- // Detect available package managers
115
+
31
116
  const availableManagers = detectPackageManagers();
32
-
117
+
33
118
  if (availableManagers.length === 0) {
34
119
  console.log(chalk.red('āŒ No compatible package managers found!'));
35
- console.log(chalk.yellow('Please install npm (v8+), yarn (v1.22+), pnpm (v7+), or bun (v1+)'));
120
+ console.log(chalk.yellow('Please install npm, yarn, or pnpm.'));
36
121
  process.exit(1);
37
122
  }
38
-
39
- // Show detected package managers with versions
123
+
40
124
  console.log(chalk.gray('Detected package managers:'));
41
125
  availableManagers.forEach(pm => {
42
126
  console.log(chalk.gray(` • ${pm.name} v${pm.version}`));
43
127
  });
44
128
  console.log('');
45
-
46
- // Get project name from command line or prompt with default
129
+
47
130
  let projectName = program.args[0];
48
-
131
+
49
132
  if (!projectName) {
50
133
  const { name } = await inquirer.prompt([
51
134
  {
@@ -64,42 +147,44 @@ async function main() {
64
147
  projectName = name;
65
148
  }
66
149
 
67
- // Validate project name and directory
68
150
  const projectPath = path.resolve(projectName);
69
-
151
+
70
152
  if (fs.existsSync(projectPath)) {
71
153
  console.log(chalk.red(`āŒ Directory ${chalk.bold(projectName)} already exists!`));
72
154
  process.exit(1);
73
155
  }
74
156
 
75
- // Prompt for configuration
76
157
  const config = await promptForConfiguration(projectName, availableManagers);
77
158
 
78
- // Setup project
79
159
  await setupProject(config, projectPath);
80
-
81
- // Success message
160
+
82
161
  console.log(chalk.green.bold('\nšŸŽ‰ Project created successfully!'));
83
162
  console.log(chalk.blue('\nšŸ“ Next steps:'));
84
163
  console.log(chalk.gray(` cd ${projectName}`));
85
164
  console.log(chalk.gray(` ${config.packageManager} run dev`));
165
+ console.log(chalk.gray(`\nšŸ’” To upgrade later: npx @enfyra/create-app@latest --upgrade`));
86
166
  console.log();
87
167
 
88
168
  } catch (error) {
89
169
  console.error(chalk.red.bold('\nāŒ Error creating project:'));
90
170
  console.error(chalk.red(error.message));
91
171
  console.error(chalk.gray(error.stack));
92
-
172
+
93
173
  process.exit(1);
94
174
  }
95
175
  }
96
176
 
97
- // Program setup
98
177
  program
99
178
  .name('create-app')
100
179
  .description('Create a new Enfyra frontend application')
101
180
  .version(packageJson.version)
181
+ .option('--upgrade', 'Upgrade existing Enfyra app from upstream')
102
182
  .argument('[project-name]', 'Name of the project to create')
103
- .action(main);
183
+ .action((projectName, options) => {
184
+ if (options.upgrade) {
185
+ return upgradeProject();
186
+ }
187
+ return createProject();
188
+ });
104
189
 
105
- program.parse();
190
+ program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enfyra/create-app",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Create Enfyra frontend applications with ease",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "repository": {
36
36
  "type": "git",
37
- "url": "https://github.com/dothinh115/create-enfyra-app.git"
37
+ "url": "https://github.com/enfyra/create-enfyra-app.git"
38
38
  },
39
39
  "bugs": {
40
- "url": "https://github.com/dothinh115/create-enfyra-app/issues"
40
+ "url": "https://github.com/enfyra/create-enfyra-app/issues"
41
41
  },
42
- "homepage": "https://github.com/dothinh115/create-enfyra-app#readme",
42
+ "homepage": "https://github.com/enfyra/create-enfyra-app#readme",
43
43
  "publishConfig": {
44
44
  "access": "public"
45
45
  }