create-vitnode-app 1.2.0-canary.5 → 1.2.0-canary.51

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 (50) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +14 -5
  3. package/copy-of-vitnode-app/.vscode/settings.json +6 -0
  4. package/copy-of-vitnode-app/api/.gitignore_template +29 -0
  5. package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
  6. package/copy-of-vitnode-app/api/package.json +43 -0
  7. package/copy-of-vitnode-app/api/src/index.ts +27 -0
  8. package/copy-of-vitnode-app/api/src/locales/@vitnode/blog/en.json +70 -0
  9. package/copy-of-vitnode-app/api/src/locales/@vitnode/core/en.json +217 -0
  10. package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +33 -0
  11. package/copy-of-vitnode-app/api/tsconfig.json +16 -0
  12. package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
  13. package/copy-of-vitnode-app/api-single-app/.env.example +8 -0
  14. package/copy-of-vitnode-app/api-single-app/.gitignore_template +37 -0
  15. package/copy-of-vitnode-app/{root → api-single-app}/src/app/api/[...route]/route.ts +0 -2
  16. package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +19 -0
  17. package/copy-of-vitnode-app/docker/docker-compose.yml +20 -0
  18. package/copy-of-vitnode-app/eslint/.prettierrc.mjs +1 -1
  19. package/copy-of-vitnode-app/eslint/eslint.config.mjs +16 -2
  20. package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
  21. package/copy-of-vitnode-app/monorepo/apps/api/.env.example +8 -0
  22. package/copy-of-vitnode-app/monorepo/apps/web/.env.example +1 -0
  23. package/copy-of-vitnode-app/monorepo/turbo.json +47 -0
  24. package/copy-of-vitnode-app/root/.env.example +9 -0
  25. package/copy-of-vitnode-app/root/.gitignore_template +37 -0
  26. package/copy-of-vitnode-app/root/README.md +48 -0
  27. package/copy-of-vitnode-app/root/global.d.ts +9 -0
  28. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/layout.tsx +6 -1
  29. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/page.tsx +9 -17
  30. package/copy-of-vitnode-app/root/src/app/[locale]/layout.tsx +11 -7
  31. package/copy-of-vitnode-app/root/src/app/global.css +61 -62
  32. package/copy-of-vitnode-app/root/src/middleware.ts +24 -0
  33. package/copy-of-vitnode-app/root/src/vitnode.config.ts +32 -0
  34. package/copy-of-vitnode-app/root/tsconfig.json +1 -1
  35. package/dist/src/create/create-package-json.js +231 -40
  36. package/dist/src/create/create-vitnode.js +142 -9
  37. package/dist/src/helpers/init-vitnode.js +21 -0
  38. package/dist/src/helpers/install-dependencies.js +42 -4
  39. package/dist/src/helpers/is-online.js +1 -1
  40. package/dist/src/helpers/is-writeable.js +1 -1
  41. package/dist/src/index.js +4 -1
  42. package/dist/src/prepare/prepare.js +1 -1
  43. package/dist/src/questions.js +44 -6
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +7 -7
  46. package/copy-of-vitnode-app/root/.prettierrc.mjs +0 -11
  47. package/copy-of-vitnode-app/root/src/app/[locale]/admin/not-found.tsx +0 -5
  48. package/copy-of-vitnode-app/root/src/app/not-found.tsx +0 -13
  49. package/copy-of-vitnode-app/root/src/vitnode.api.config.ts +0 -5
  50. /package/copy-of-vitnode-app/{root → api-single-app}/drizzle.config.ts +0 -0
@@ -1,63 +1,254 @@
1
1
  import { readFile, writeFile } from 'fs/promises';
2
- import { join } from 'path';
3
- export const createPackageJSON = async ({ appName, packageManager, root, eslint, }) => {
4
- const pkg = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'));
5
- const packageJson = {
6
- name: appName,
2
+ import { dirname, join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { getAvailablePackageManagers } from '../helpers/get-available-package-managers.js';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ export const createPackageJSON = async ({ appName, packageManager, root, eslint, docker, mode, monorepo, }) => {
8
+ const availablePackageManagers = await getAvailablePackageManagers();
9
+ const pkg = JSON.parse(await readFile(join(__dirname, '..', '..', '..', 'package.json'), 'utf-8'));
10
+ const pkgVitNodeVersion = `^${pkg.version}`;
11
+ const monorepoStructure = {
12
+ api: join(root, 'apps', 'api'),
13
+ web: join(root, 'apps', 'web'),
14
+ };
15
+ if (mode === 'apiMonorepo' || monorepo) {
16
+ const rootPackageJson = {
17
+ name: appName,
18
+ private: true,
19
+ scripts: {
20
+ 'db:migrate': 'turbo db:migrate',
21
+ 'db:push': 'turbo db:push',
22
+ init: 'turbo init',
23
+ dev: 'turbo dev',
24
+ build: 'turbo build',
25
+ start: 'turbo start',
26
+ ...(eslint
27
+ ? {
28
+ lint: 'eslint .',
29
+ 'lint:fix': 'eslint . --fix',
30
+ }
31
+ : {}),
32
+ ...(docker
33
+ ? {
34
+ 'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
35
+ }
36
+ : {}),
37
+ },
38
+ devDependencies: {
39
+ '@types/node': '^24',
40
+ '@vitnode/eslint-config': pkgVitNodeVersion,
41
+ ...(eslint
42
+ ? {
43
+ 'prettier-plugin-tailwindcss': '^0.6.14',
44
+ prettier: '^3.6.2',
45
+ }
46
+ : {}),
47
+ turbo: '^2.5.5',
48
+ typescript: '^5.8.3',
49
+ zod: '^4.0.5',
50
+ },
51
+ packageManager: `${packageManager}@${availablePackageManagers[packageManager]}`,
52
+ workspaces: ['apps/*', 'plugins/*'],
53
+ };
54
+ await writeFile(join(root, 'package.json'), JSON.stringify(rootPackageJson, null, 2));
55
+ }
56
+ const apiPackageJson = {
57
+ name: mode === 'apiMonorepo' || monorepo ? 'api' : appName,
7
58
  version: '0.1.0',
8
59
  private: true,
9
60
  type: 'module',
10
61
  scripts: {
11
- 'drizzle-kit': 'drizzle-kit',
12
- 'db:push': 'drizzle-kit push',
13
- 'db:migrate': 'drizzle-kit up && drizzle-kit generate && drizzle-kit migrate',
14
- dev: 'vitnode init && next dev --turbopack',
15
- build: 'next build --turbopack',
16
- start: 'next start',
62
+ 'db:push': 'vitnode push',
63
+ 'db:migrate': 'vitnode migrate',
64
+ init: 'vitnode init --api',
65
+ ...(packageManager === 'bun'
66
+ ? {
67
+ dev: 'vitnode init --api && bun run --hot src/index.ts',
68
+ start: 'NODE_ENV=production bun run src/index.ts',
69
+ }
70
+ : {
71
+ dev: 'vitnode init --api && tsx watch src/index.ts',
72
+ build: 'tsc && tsc-alias -p tsconfig.json',
73
+ start: 'node dist/index.js',
74
+ }),
17
75
  ...(eslint
18
76
  ? {
19
77
  lint: 'eslint .',
20
78
  'lint:fix': 'eslint . --fix',
21
79
  }
22
80
  : {}),
81
+ ...(docker && mode === 'onlyApi'
82
+ ? {
83
+ 'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
84
+ }
85
+ : {}),
86
+ 'drizzle-kit': 'drizzle-kit',
23
87
  },
24
88
  dependencies: {
25
- '@hono/zod-openapi': '^0.19.8',
26
- '@hono/zod-validator': '^0.7.0',
27
- '@hookform/resolvers': '^5.0.1',
28
- '@react-email/components': '^0.0.41',
29
- '@vitnode/core': `^${pkg.version}`,
30
- 'babel-plugin-react-compiler': '19.1.0-rc.2',
31
- 'drizzle-kit': '^0.31.1',
32
- 'drizzle-orm': '^0.44.1',
33
- hono: '^4.7.10',
34
- 'lucide-react': '^0.511.0',
35
- next: '^15.3.3',
36
- 'next-intl': '^4.1.0',
37
- react: '^19.1.0',
38
- 'react-dom': '^19.1.0',
39
- 'react-hook-form': '^7.56.4',
40
- sonner: '^2.0.3',
41
- zod: '^3.25.42',
89
+ '@hono/zod-openapi': '^1.0.2',
90
+ '@hono/zod-validator': '^0.7.2',
91
+ '@react-email/components': '^0.3.2',
92
+ '@vitnode/core': pkgVitNodeVersion,
93
+ 'drizzle-kit': '^0.31.3',
94
+ 'drizzle-orm': '^0.44.3',
95
+ hono: '^4.8.5',
96
+ 'next-intl': '^4.3.1',
97
+ react: '^19.1',
98
+ 'react-dom': '^19.1',
99
+ zod: '^4.0.5',
42
100
  },
43
101
  devDependencies: {
44
- '@tailwindcss/postcss': '^4.1.8',
45
- '@types/node': '^22.15.29',
46
- '@types/react': '^19.1.6',
47
- '@types/react-dom': '^19.1.5',
102
+ '@hono/node-server': '^1.17.1',
103
+ ...(packageManager === 'bun'
104
+ ? {
105
+ '@types/bun': 'latest',
106
+ }
107
+ : {}),
108
+ '@types/node': '^24',
109
+ '@types/react': '^19.1',
110
+ '@types/react-dom': '^19.1',
111
+ '@vitnode/eslint-config': pkgVitNodeVersion,
112
+ dotenv: '^17.2.0',
48
113
  ...(eslint
49
114
  ? {
50
- eslint: '^9.27.0',
51
- 'eslint-config-typescript-vitnode': `^${pkg.version}`,
52
- prettier: '^3.5.3',
115
+ eslint: '^9.31.0',
116
+ ...(mode === 'onlyApi'
117
+ ? {
118
+ 'prettier-plugin-tailwindcss': '^0.6.14',
119
+ prettier: '^3.6.2',
120
+ }
121
+ : {}),
53
122
  }
54
123
  : {}),
55
- 'react-email': '^4.0.15',
56
- tailwindcss: '^4.1.8',
57
- 'tw-animate-css': '^1.3.2',
124
+ 'react-email': '^4.2.3',
125
+ 'tsc-alias': '^1.8.16',
126
+ tsx: '^4.20.3',
58
127
  typescript: '^5.8.3',
59
128
  },
60
- packageManager,
61
129
  };
62
- await writeFile(join(root, 'apps', 'frontend', 'package.json'), JSON.stringify(packageJson, null, 2));
130
+ if (mode === 'singleApp') {
131
+ const packageJson = {
132
+ name: monorepo ? 'web' : appName,
133
+ version: '0.1.0',
134
+ private: true,
135
+ type: 'module',
136
+ scripts: {
137
+ 'db:push': 'vitnode push',
138
+ 'db:migrate': 'vitnode migrate',
139
+ init: 'vitnode init',
140
+ dev: 'vitnode init && next dev --turbopack',
141
+ build: 'next build',
142
+ start: 'next start',
143
+ ...(eslint
144
+ ? {
145
+ lint: 'eslint .',
146
+ 'lint:fix': 'eslint . --fix',
147
+ }
148
+ : {}),
149
+ ...(docker
150
+ ? {
151
+ 'docker:dev': `docker compose -f ./docker-compose.yml -p ${appName}-vitnode-dev up -d`,
152
+ }
153
+ : {}),
154
+ 'drizzle-kit': 'drizzle-kit',
155
+ },
156
+ dependencies: {
157
+ '@hono/zod-openapi': '^1.0.2',
158
+ '@hono/zod-validator': '^0.7.2',
159
+ '@hookform/resolvers': '^5.1.1',
160
+ '@react-email/components': '^0.3.2',
161
+ '@vitnode/core': pkgVitNodeVersion,
162
+ 'babel-plugin-react-compiler': '19.1.0-rc.2',
163
+ 'drizzle-kit': '^0.31.4',
164
+ 'drizzle-orm': '^0.44.3',
165
+ hono: '^4.8.5',
166
+ 'lucide-react': '^0.525.0',
167
+ next: '^15.4.2',
168
+ 'next-intl': '^4.3.4',
169
+ react: '^19.1',
170
+ 'react-dom': '^19.1',
171
+ 'react-hook-form': '^7.60.0',
172
+ sonner: '^2.0.6',
173
+ zod: '^4.0.5',
174
+ },
175
+ devDependencies: {
176
+ '@tailwindcss/postcss': '^4.1.11',
177
+ '@types/node': '^24',
178
+ '@types/react': '^19.1',
179
+ '@types/react-dom': '^19.1',
180
+ '@vitnode/eslint-config': pkgVitNodeVersion,
181
+ ...(eslint
182
+ ? {
183
+ eslint: '^9.31.0',
184
+ 'prettier-plugin-tailwindcss': '^0.6.14',
185
+ prettier: '^3.6.2',
186
+ }
187
+ : {}),
188
+ 'react-email': '^4.2.3',
189
+ turbo: '^2.5.5',
190
+ tailwindcss: '^4.1.11',
191
+ 'tw-animate-css': '^1.3.5',
192
+ typescript: '^5.8.3',
193
+ },
194
+ packageManager: `${packageManager}@${availablePackageManagers[packageManager]}`,
195
+ };
196
+ await writeFile(join(monorepo ? monorepoStructure.web : root, 'package.json'), JSON.stringify(packageJson, null, 2));
197
+ }
198
+ else if (mode === 'apiMonorepo') {
199
+ await writeFile(join(root, 'apps', 'api', 'package.json'), JSON.stringify(apiPackageJson, null, 2));
200
+ const webPackageJson = {
201
+ name: 'web',
202
+ version: '0.1.0',
203
+ private: true,
204
+ type: 'module',
205
+ scripts: {
206
+ init: 'vitnode init --web',
207
+ dev: 'vitnode init --web && next dev --turbopack',
208
+ build: 'next build',
209
+ start: 'next start',
210
+ ...(eslint
211
+ ? {
212
+ lint: 'eslint .',
213
+ 'lint:fix': 'eslint . --fix',
214
+ }
215
+ : {}),
216
+ },
217
+ dependencies: {
218
+ '@vitnode/core': pkgVitNodeVersion,
219
+ 'babel-plugin-react-compiler': '19.1.0-rc.2',
220
+ 'lucide-react': '^0.525.0',
221
+ next: '^15.4.2',
222
+ 'next-intl': '^4.3.4',
223
+ react: '^19.1',
224
+ 'react-dom': '^19.1',
225
+ 'react-hook-form': '^7.60.0',
226
+ sonner: '^2.0.6',
227
+ },
228
+ devDependencies: {
229
+ '@hookform/resolvers': '^5.1.1',
230
+ '@tailwindcss/postcss': '^4.1.11',
231
+ '@types/mdx': '^2.0.13',
232
+ '@types/node': '^24',
233
+ '@types/react': '^19.1',
234
+ '@types/react-dom': '^19.1',
235
+ '@vitnode/eslint-config': pkgVitNodeVersion,
236
+ 'class-variance-authority': '^0.7.1',
237
+ ...(eslint
238
+ ? {
239
+ eslint: '^9.31.0',
240
+ }
241
+ : {}),
242
+ postcss: '^8.5.6',
243
+ tailwindcss: '^4.1.11',
244
+ 'tw-animate-css': '^1.3.5',
245
+ typescript: '^5.8.3',
246
+ zod: '^4.0.5',
247
+ },
248
+ };
249
+ await writeFile(join(root, 'apps', 'web', 'package.json'), JSON.stringify(webPackageJson, null, 2));
250
+ }
251
+ else if (mode === 'onlyApi') {
252
+ await writeFile(join(monorepo ? monorepoStructure.api : root, 'package.json'), JSON.stringify(apiPackageJson, null, 2));
253
+ }
63
254
  };
@@ -1,14 +1,14 @@
1
- import { randomBytes } from 'crypto';
2
1
  import { existsSync } from 'fs';
3
- import { copyFile, cp, mkdir, readFile, writeFile } from 'fs/promises';
2
+ import { copyFile, cp, mkdir, readFile, rename, writeFile } from 'fs/promises';
4
3
  import ora from 'ora';
5
4
  import { dirname, join } from 'path';
6
5
  import color from 'picocolors';
7
6
  import { fileURLToPath } from 'url';
7
+ import { generateMigrationsVitnode, initFilesVitnode, } from '../helpers/init-vitnode.js';
8
8
  import { installDependencies } from '../helpers/install-dependencies.js';
9
9
  import { isFolderEmpty } from '../helpers/is-folder-empty.js';
10
10
  import { createPackageJSON } from './create-package-json.js';
11
- export const createVitNode = async ({ root, appName, packageManager, eslint, install, }) => {
11
+ export const createVitNode = async ({ root, appName, packageManager, eslint, install, docker, mode, monorepo, }) => {
12
12
  const spinner = ora(`Creating a new VitNode app in ${color.green(root)}. Using ${color.green(packageManager)}...`).start();
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = dirname(__filename);
@@ -21,32 +21,165 @@ export const createVitNode = async ({ root, appName, packageManager, eslint, ins
21
21
  if (!isFolderEmpty(root, appName)) {
22
22
  process.exit(1);
23
23
  }
24
+ const monorepoStructure = {
25
+ api: join(root, 'apps', 'api'),
26
+ web: join(root, 'apps', 'web'),
27
+ };
28
+ spinner.text = 'Preparing the project structure...';
29
+ if (monorepo || mode === 'apiMonorepo') {
30
+ const dirsToCreate = [];
31
+ if (mode === 'apiMonorepo' || (monorepo && mode === 'onlyApi')) {
32
+ dirsToCreate.push(monorepoStructure.api);
33
+ }
34
+ if (mode === 'apiMonorepo' || (monorepo && mode === 'singleApp')) {
35
+ dirsToCreate.push(monorepoStructure.web);
36
+ }
37
+ await Promise.all(dirsToCreate.map(async (dir) => mkdir(dir, { recursive: true })));
38
+ }
24
39
  spinner.text = 'Copying files...';
25
- await cp(join(templatePath, 'root'), root, {
40
+ await cp(join(templatePath, '.vscode'), join(root, '.vscode'), {
26
41
  recursive: true,
27
42
  });
43
+ if (mode === 'singleApp') {
44
+ await Promise.all([
45
+ cp(join(templatePath, 'root'), monorepo ? monorepoStructure.web : root, {
46
+ recursive: true,
47
+ }),
48
+ cp(join(templatePath, 'api-single-app'), monorepo ? monorepoStructure.web : root, {
49
+ recursive: true,
50
+ }),
51
+ ]);
52
+ }
53
+ else if (mode === 'apiMonorepo') {
54
+ await Promise.all([
55
+ cp(join(templatePath, 'root'), monorepoStructure.web, {
56
+ recursive: true,
57
+ }),
58
+ cp(join(templatePath, 'api'), monorepoStructure.api, {
59
+ recursive: true,
60
+ }),
61
+ ]);
62
+ if (packageManager === 'bun') {
63
+ await cp(join(templatePath, 'api-bun'), monorepoStructure.api, {
64
+ recursive: true,
65
+ });
66
+ }
67
+ }
68
+ else if (mode === 'onlyApi') {
69
+ await cp(join(templatePath, 'api'), monorepo ? monorepoStructure.api : root, {
70
+ recursive: true,
71
+ });
72
+ if (packageManager === 'bun') {
73
+ await cp(join(templatePath, 'api-bun'), monorepo ? monorepoStructure.api : root, {
74
+ recursive: true,
75
+ });
76
+ }
77
+ }
78
+ if (mode === 'apiMonorepo' || monorepo) {
79
+ await cp(join(templatePath, 'monorepo'), root, {
80
+ recursive: true,
81
+ });
82
+ }
28
83
  if (eslint) {
29
84
  spinner.text = 'Copying eslint files...';
30
85
  await cp(join(templatePath, 'eslint'), root, {
31
86
  recursive: true,
32
87
  });
33
88
  }
89
+ spinner.text = 'Renaming special files...';
90
+ await rename(join(root, '.gitignore_template'), join(root, '.gitignore'));
91
+ if (mode === 'apiMonorepo' || monorepo) {
92
+ if (existsSync(join(monorepoStructure.api, '.gitignore_template'))) {
93
+ await rename(join(monorepoStructure.api, '.gitignore_template'), join(monorepoStructure.api, '.gitignore'));
94
+ }
95
+ if (existsSync(join(monorepoStructure.web, '.gitignore_template'))) {
96
+ await rename(join(monorepoStructure.web, '.gitignore_template'), join(monorepoStructure.web, '.gitignore'));
97
+ }
98
+ }
34
99
  spinner.text = 'Creating package.json...';
35
100
  await createPackageJSON({
36
101
  root,
37
102
  appName,
38
103
  packageManager,
39
104
  eslint,
105
+ docker,
106
+ mode,
107
+ monorepo,
40
108
  });
41
- spinner.text = 'Changing .env file...';
42
- await copyFile(join(root, '.env.template'), join(root, '.env'));
43
- const envPath = join(root, '.env');
44
- const newEnv = (await readFile(envPath, 'utf-8')).replace('LOGIN_TOKEN_SECRET=vitnode_secret', `LOGIN_TOKEN_SECRET=${randomBytes(32).toString('hex')}`);
45
- await writeFile(envPath, newEnv);
109
+ if ((mode === 'apiMonorepo' || monorepo) && packageManager === 'pnpm') {
110
+ spinner.text = 'Creating pnpm-workspace.yaml...';
111
+ const pnpmWorkspaceContent = `packages:\n - 'apps/*'\n - 'plugins/*'\n`;
112
+ await writeFile(join(root, 'pnpm-workspace.yaml'), pnpmWorkspaceContent);
113
+ }
114
+ if (docker) {
115
+ spinner.text = 'Copying docker files...';
116
+ await copyFile(join(templatePath, 'docker', 'docker-compose.yml'), join(root, 'docker-compose.yml'));
117
+ const dockerComposePath = join(root, 'docker-compose.yml');
118
+ const dockerComposeContent = await readFile(dockerComposePath, 'utf-8');
119
+ const updatedContent = dockerComposeContent.replace(/vitnode_postgres_dev/g, `${appName}_vitnode_postgres_dev`);
120
+ await writeFile(dockerComposePath, updatedContent);
121
+ }
122
+ spinner.text = 'Updating VitNode paths...';
123
+ if ((mode === 'apiMonorepo' || monorepo) &&
124
+ packageManager !== 'pnpm' &&
125
+ mode !== 'onlyApi') {
126
+ const globalCssPath = join(monorepoStructure.web, 'src', 'app', 'global.css');
127
+ const globalCssContent = await readFile(globalCssPath, 'utf-8');
128
+ const updatedGlobalCssContent = globalCssContent.replaceAll('@source "../../node_modules/@vitnode/', '@source "../../../../node_modules/@vitnode/');
129
+ await writeFile(globalCssPath, updatedGlobalCssContent);
130
+ }
131
+ if (mode === 'apiMonorepo') {
132
+ spinner.text = 'Setting up environment variables...';
133
+ const envExamplePath = join(monorepoStructure.web, '.env.example');
134
+ if (existsSync(envExamplePath)) {
135
+ await rename(envExamplePath, join(monorepoStructure.web, '.env'));
136
+ }
137
+ }
46
138
  if (install) {
47
139
  spinner.text = 'Installing dependencies...';
48
140
  await installDependencies({
49
141
  packageManager,
142
+ cwd: root,
143
+ });
144
+ spinner.text = 'Initializing VitNode files...';
145
+ if (mode === 'apiMonorepo') {
146
+ await Promise.all([
147
+ initFilesVitnode({
148
+ packageManager,
149
+ cwd: monorepoStructure.web,
150
+ flag: 'web',
151
+ }),
152
+ initFilesVitnode({
153
+ packageManager,
154
+ cwd: monorepoStructure.api,
155
+ flag: 'api',
156
+ }),
157
+ initFilesVitnode({
158
+ packageManager,
159
+ cwd: root,
160
+ }),
161
+ ]);
162
+ }
163
+ else {
164
+ initFilesVitnode({
165
+ packageManager,
166
+ cwd: root,
167
+ });
168
+ }
169
+ spinner.text = 'Generating migrations...';
170
+ let migrationsCwd;
171
+ if (mode === 'apiMonorepo' || (monorepo && mode !== 'singleApp')) {
172
+ migrationsCwd = monorepoStructure.api;
173
+ }
174
+ else if (mode === 'singleApp' && monorepo) {
175
+ migrationsCwd = monorepoStructure.web;
176
+ }
177
+ else {
178
+ migrationsCwd = root;
179
+ }
180
+ generateMigrationsVitnode({
181
+ packageManager,
182
+ cwd: migrationsCwd,
50
183
  });
51
184
  }
52
185
  spinner.succeed(`${color.green('Success!')} Created ${color.cyan(appName)} at ${color.cyan(root)}`);
@@ -0,0 +1,21 @@
1
+ import { spawn } from 'child_process';
2
+ export const initFilesVitnode = ({ packageManager: pm, cwd, flag, }) => {
3
+ const packageManager = pm.split('@')[0];
4
+ const args = [
5
+ 'vitnode',
6
+ 'prepare-plugins',
7
+ flag ? `--${flag}` : '',
8
+ ];
9
+ spawn(packageManager, args, {
10
+ cwd,
11
+ shell: true,
12
+ });
13
+ };
14
+ export const generateMigrationsVitnode = ({ packageManager: pm, cwd, }) => {
15
+ const packageManager = pm.split('@')[0];
16
+ const args = ['vitnode', 'migrate', '--generate'];
17
+ spawn(packageManager, args, {
18
+ cwd,
19
+ shell: true,
20
+ });
21
+ };
@@ -1,17 +1,21 @@
1
1
  import { spawn } from 'child_process';
2
2
  import color from 'picocolors';
3
3
  import { getOnline } from './is-online.js';
4
- export const installDependencies = async ({ packageManager: pm, }) => {
4
+ export const installDependencies = async ({ packageManager: pm, cwd, }) => {
5
5
  const packageManager = pm.split('@')[0];
6
6
  const isOnline = await getOnline();
7
- const args = packageManager === 'npm' ? ['install', '--force'] : ['install'];
7
+ const args = ['install'];
8
8
  if (!isOnline) {
9
9
  console.log(color.yellow('You appear to be offline.\nFalling back to the local cache.'));
10
10
  args.push('--offline');
11
11
  }
12
12
  return new Promise((resolve, reject) => {
13
+ let stdout = '';
14
+ let stderr = '';
13
15
  const child = spawn(packageManager, args, {
14
- stdio: 'ignore',
16
+ stdio: 'pipe',
17
+ cwd,
18
+ shell: true,
15
19
  env: {
16
20
  ...process.env,
17
21
  ADBLOCK: '1',
@@ -19,12 +23,46 @@ export const installDependencies = async ({ packageManager: pm, }) => {
19
23
  DISABLE_OPENCOLLECTIVE: '1',
20
24
  },
21
25
  });
26
+ child.stdout?.on('data', (data) => {
27
+ const output = data.toString();
28
+ stdout += output;
29
+ });
30
+ child.stderr?.on('data', (data) => {
31
+ const output = data.toString();
32
+ stderr += output;
33
+ });
22
34
  child.on('close', code => {
23
35
  if (code !== 0) {
24
- reject({ command: `${packageManager} ${args.join(' ')}` });
36
+ console.error(color.red(`\n❌ Installation failed with exit code: ${code}`));
37
+ if (stderr) {
38
+ console.error(color.red('Error output:'));
39
+ console.error(stderr);
40
+ }
41
+ if (stdout) {
42
+ console.log(color.yellow('Standard output:'));
43
+ console.log(stdout);
44
+ }
45
+ if (stderr.includes('ENOTFOUND') || stderr.includes('network')) {
46
+ console.error(color.yellow('💡 Network error detected. Please check your internet connection.'));
47
+ }
48
+ else if (stderr.includes('EACCES') ||
49
+ stderr.includes('permission denied')) {
50
+ console.error(color.yellow('💡 Permission error detected. Try running with elevated privileges or check file permissions.'));
51
+ }
52
+ else if (stderr.includes('ENOSPC')) {
53
+ console.error(color.yellow('💡 Disk space error detected. Please free up some disk space.'));
54
+ }
55
+ else if (stderr.includes('ERR_PNPM_PEER_DEP_ISSUES')) {
56
+ console.error(color.yellow('💡 Peer dependency issues detected. Consider using --force flag or resolve conflicts manually.'));
57
+ }
58
+ reject(new Error(`Failed to install dependencies using ${packageManager}. Exit code: ${code}\n${stderr || stdout}`));
25
59
  return;
26
60
  }
27
61
  resolve();
28
62
  });
63
+ child.on('error', error => {
64
+ console.error(color.red(`❌ Failed to start ${packageManager}:`), error.message);
65
+ reject(new Error(`Failed to start ${packageManager}: ${error.message}`));
66
+ });
29
67
  });
30
68
  };
@@ -32,7 +32,7 @@ function getProxy() {
32
32
  const httpsProxy = execSync('npm config get https-proxy').toString().trim();
33
33
  return httpsProxy !== 'null' ? httpsProxy : undefined;
34
34
  }
35
- catch (_) {
35
+ catch {
36
36
  return;
37
37
  }
38
38
  }
@@ -5,7 +5,7 @@ export async function isWriteable(directory) {
5
5
  await access(directory, W_OK);
6
6
  return true;
7
7
  }
8
- catch (_) {
8
+ catch {
9
9
  return false;
10
10
  }
11
11
  }
package/dist/src/index.js CHANGED
@@ -26,7 +26,7 @@ process.on('uncaughtException', (error) => {
26
26
  const init = async () => {
27
27
  let projectPath = '';
28
28
  const program = new Command()
29
- .version(packageJson.version)
29
+ .version(packageJson.version ?? '0.1.0')
30
30
  .argument('[project-directory]')
31
31
  .usage(`${color.green('[project-directory]')} [options]`)
32
32
  .action(name => {
@@ -36,6 +36,9 @@ const init = async () => {
36
36
  program.option('--eslint', 'Initialize with eslint config.');
37
37
  program.option('--skip-install', 'Skip installing packages after initializing the project.');
38
38
  program.option('--plugin', 'Enable plugin mode.');
39
+ program.addOption(new Option('--mode <mode>', 'What type of app do you want to create?').choices(['singleApp', 'apiMonorepo', 'onlyApi']));
40
+ program.option('--monorepo', 'Create project with monorepo structure.');
41
+ program.option('--docker', 'Initialize with Docker support.');
39
42
  program.parse(process.argv);
40
43
  const opts = program.opts();
41
44
  if (opts.plugin) {
@@ -6,7 +6,7 @@ const prepare = async () => {
6
6
  if (!existsSync(toRootPath)) {
7
7
  await mkdir(toRootPath);
8
8
  }
9
- const fromRootPath = join(process.cwd(), '..', '..', 'apps', 'web');
9
+ const fromRootPath = join(process.cwd(), '..', '..', 'apps', 'docs');
10
10
  if (!existsSync(fromRootPath)) {
11
11
  console.error(`\x1b[31mThe path ${fromRootPath} does not exist. Please check the directory structure.\x1b[0m`);
12
12
  process.exit(1);