@idealyst/cli 1.0.24 → 1.0.26

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 (48) hide show
  1. package/README.md +109 -109
  2. package/dist/index.js +233 -36
  3. package/dist/types/generators/api.d.ts +2 -0
  4. package/dist/types/generators/index.d.ts +1 -0
  5. package/dist/types/generators/utils.d.ts +18 -1
  6. package/dist/types/types.d.ts +2 -1
  7. package/package.json +1 -1
  8. package/templates/api/README.md +207 -0
  9. package/templates/api/env.example +12 -0
  10. package/templates/api/package.json +49 -0
  11. package/templates/api/prisma/schema.prisma +21 -0
  12. package/templates/api/src/context.ts +23 -0
  13. package/templates/api/src/controllers/UserController.ts +102 -0
  14. package/templates/api/src/index.ts +14 -0
  15. package/templates/api/src/lib/controller.ts +90 -0
  16. package/templates/api/src/lib/middleware.ts +170 -0
  17. package/templates/api/src/middleware/auth.ts +75 -0
  18. package/templates/api/src/middleware/common.ts +103 -0
  19. package/templates/api/src/router/index.ts +130 -0
  20. package/templates/api/src/server.ts +50 -0
  21. package/templates/api/src/trpc.ts +28 -0
  22. package/templates/api/tsconfig.json +44 -0
  23. package/templates/native/.yarnrc.yml +18 -18
  24. package/templates/native/App.tsx +23 -23
  25. package/templates/native/README.md +85 -85
  26. package/templates/native/app.json +4 -4
  27. package/templates/native/babel.config.js +9 -9
  28. package/templates/native/index.js +5 -5
  29. package/templates/native/metro.config.js +27 -27
  30. package/templates/native/package.json +9 -9
  31. package/templates/native/src/App-with-trpc.tsx +72 -0
  32. package/templates/native/src/utils/trpc.ts +127 -0
  33. package/templates/native/tsconfig.json +29 -29
  34. package/templates/shared/README.md +108 -108
  35. package/templates/shared/package.json +39 -39
  36. package/templates/shared/tsconfig.json +24 -24
  37. package/templates/web/README.md +89 -89
  38. package/templates/web/index.html +12 -12
  39. package/templates/web/package.json +55 -51
  40. package/templates/web/src/App-with-trpc.tsx +80 -0
  41. package/templates/web/src/App.tsx +14 -14
  42. package/templates/web/src/main.tsx +24 -24
  43. package/templates/web/src/utils/trpc.ts +93 -0
  44. package/templates/web/tsconfig.json +26 -26
  45. package/templates/web/vite.config.ts +68 -68
  46. package/templates/workspace/.yarnrc.yml +25 -25
  47. package/templates/workspace/README.md +79 -79
  48. package/templates/workspace/package.json +24 -24
package/README.md CHANGED
@@ -1,110 +1,110 @@
1
- # @idealyst/cli
2
-
3
- CLI tool for generating Idealyst Framework projects.
4
-
5
- ## Installation
6
-
7
- Install globally:
8
- ```bash
9
- npm install -g @idealyst/cli
10
- # or
11
- yarn global add @idealyst/cli
12
- ```
13
-
14
- ## Usage
15
-
16
- ### Create a new project
17
-
18
- ```bash
19
- idealyst create <project-name> [options]
20
- ```
21
-
22
- Options:
23
- - `-t, --type <type>` - Project type: `native`, `web`, or `shared` (default: `native`)
24
- - `-d, --directory <directory>` - Output directory (default: current directory)
25
- - `--skip-install` - Skip installing dependencies
26
-
27
- ### Initialize a new workspace
28
-
29
- ```bash
30
- idealyst init [options]
31
- ```
32
-
33
- Options:
34
- - `-d, --directory <directory>` - Output directory (default: current directory)
35
- - `--skip-install` - Skip installing dependencies
36
-
37
- ## Examples
38
-
39
- Create a React Native app:
40
- ```bash
41
- idealyst create my-app --type native
42
- ```
43
-
44
- Create a React web app:
45
- ```bash
46
- idealyst create my-web-app --type web
47
- ```
48
-
49
- Create a shared library:
50
- ```bash
51
- idealyst create my-lib --type shared
52
- ```
53
-
54
- Initialize a new workspace:
55
- ```bash
56
- idealyst init
57
- ```
58
-
59
- ## Project Types
60
-
61
- ### Native (React Native)
62
- - React Native 0.80.1
63
- - Idealyst Components
64
- - Idealyst Navigation
65
- - Idealyst Theme
66
- - TypeScript configuration
67
- - Metro bundler configuration
68
- - Babel configuration
69
-
70
- ### Web (React + Vite)
71
- - React 19.1
72
- - Vite build system
73
- - Idealyst Components (web-compatible)
74
- - Idealyst Navigation
75
- - Idealyst Theme
76
- - TypeScript configuration
77
- - React Native Web support
78
-
79
- ### Shared Library
80
- - Cross-platform components
81
- - TypeScript definitions
82
- - Rollup build system
83
- - Peer dependencies for React/React Native
84
- - Idealyst Theme integration
85
-
86
- ### Workspace
87
- - Yarn workspace configuration
88
- - Monorepo structure
89
- - Version management scripts
90
- - Build scripts for all packages
91
-
92
- ## Development
93
-
94
- Build the CLI:
95
- ```bash
96
- cd packages/cli
97
- yarn build
98
- ```
99
-
100
- Link for local development:
101
- ```bash
102
- yarn link
103
- ```
104
-
105
- ## Learn More
106
-
107
- - [Idealyst Framework Documentation](https://github.com/your-username/idealyst-framework)
108
- - [React Native Documentation](https://reactnative.dev/)
109
- - [React Documentation](https://react.dev/)
1
+ # @idealyst/cli
2
+
3
+ CLI tool for generating Idealyst Framework projects.
4
+
5
+ ## Installation
6
+
7
+ Install globally:
8
+ ```bash
9
+ npm install -g @idealyst/cli
10
+ # or
11
+ yarn global add @idealyst/cli
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ### Create a new project
17
+
18
+ ```bash
19
+ idealyst create <project-name> [options]
20
+ ```
21
+
22
+ Options:
23
+ - `-t, --type <type>` - Project type: `native`, `web`, or `shared` (default: `native`)
24
+ - `-d, --directory <directory>` - Output directory (default: current directory)
25
+ - `--skip-install` - Skip installing dependencies
26
+
27
+ ### Initialize a new workspace
28
+
29
+ ```bash
30
+ idealyst init [options]
31
+ ```
32
+
33
+ Options:
34
+ - `-d, --directory <directory>` - Output directory (default: current directory)
35
+ - `--skip-install` - Skip installing dependencies
36
+
37
+ ## Examples
38
+
39
+ Create a React Native app:
40
+ ```bash
41
+ idealyst create my-app --type native
42
+ ```
43
+
44
+ Create a React web app:
45
+ ```bash
46
+ idealyst create my-web-app --type web
47
+ ```
48
+
49
+ Create a shared library:
50
+ ```bash
51
+ idealyst create my-lib --type shared
52
+ ```
53
+
54
+ Initialize a new workspace:
55
+ ```bash
56
+ idealyst init
57
+ ```
58
+
59
+ ## Project Types
60
+
61
+ ### Native (React Native)
62
+ - React Native 0.80.1
63
+ - Idealyst Components
64
+ - Idealyst Navigation
65
+ - Idealyst Theme
66
+ - TypeScript configuration
67
+ - Metro bundler configuration
68
+ - Babel configuration
69
+
70
+ ### Web (React + Vite)
71
+ - React 19.1
72
+ - Vite build system
73
+ - Idealyst Components (web-compatible)
74
+ - Idealyst Navigation
75
+ - Idealyst Theme
76
+ - TypeScript configuration
77
+ - React Native Web support
78
+
79
+ ### Shared Library
80
+ - Cross-platform components
81
+ - TypeScript definitions
82
+ - Rollup build system
83
+ - Peer dependencies for React/React Native
84
+ - Idealyst Theme integration
85
+
86
+ ### Workspace
87
+ - Yarn workspace configuration
88
+ - Monorepo structure
89
+ - Version management scripts
90
+ - Build scripts for all packages
91
+
92
+ ## Development
93
+
94
+ Build the CLI:
95
+ ```bash
96
+ cd packages/cli
97
+ yarn build
98
+ ```
99
+
100
+ Link for local development:
101
+ ```bash
102
+ yarn link
103
+ ```
104
+
105
+ ## Learn More
106
+
107
+ - [Idealyst Framework Documentation](https://github.com/your-username/idealyst-framework)
108
+ - [React Native Documentation](https://reactnative.dev/)
109
+ - [React Documentation](https://react.dev/)
110
110
  - [Vite Documentation](https://vitejs.dev/)
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ function validateProjectName(name) {
16
16
  function createPackageName(name) {
17
17
  return name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
18
18
  }
19
- async function updateWorkspacePackageJson(projectName, directory) {
19
+ async function updateWorkspacePackageJson(workspacePath, directory) {
20
20
  // Look for package.json in the directory to see if we're in a workspace
21
21
  const packageJsonPath = path.join(directory, 'package.json');
22
22
  if (await fs.pathExists(packageJsonPath)) {
@@ -24,11 +24,18 @@ async function updateWorkspacePackageJson(projectName, directory) {
24
24
  const packageJson = await fs.readJSON(packageJsonPath);
25
25
  // Check if this is a workspace (has workspaces property)
26
26
  if (packageJson.workspaces && Array.isArray(packageJson.workspaces)) {
27
- // Add the new project to workspaces if not already present
28
- if (!packageJson.workspaces.includes(projectName)) {
29
- packageJson.workspaces.push(projectName);
27
+ // Check if workspace already covers this path with a wildcard
28
+ const workspaceDir = path.dirname(workspacePath);
29
+ const wildcardPattern = `${workspaceDir}/*`;
30
+ const isAlreadyCovered = packageJson.workspaces.some((ws) => ws === wildcardPattern || ws === workspacePath);
31
+ // Add the new project to workspaces if not already present or covered
32
+ if (!isAlreadyCovered) {
33
+ packageJson.workspaces.push(workspacePath);
30
34
  await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
31
- console.log(chalk.green(`āœ… Added ${projectName} to workspace configuration`));
35
+ console.log(chalk.green(`āœ… Added ${workspacePath} to workspace configuration`));
36
+ }
37
+ else {
38
+ console.log(chalk.blue(`šŸ“¦ Project ${workspacePath} already covered by existing workspace configuration`));
32
39
  }
33
40
  }
34
41
  }
@@ -78,6 +85,9 @@ async function processTemplateFile(filePath, data) {
78
85
  content = content.replace(/\{\{packageName\}\}/g, data.packageName);
79
86
  content = content.replace(/\{\{version\}\}/g, data.version);
80
87
  content = content.replace(/\{\{description\}\}/g, data.description);
88
+ // Handle appName (with fallback to projectName if not provided)
89
+ const appName = data.appName || data.projectName;
90
+ content = content.replace(/\{\{appName\}\}/g, appName);
81
91
  await fs.writeFile(filePath, content);
82
92
  }
83
93
  catch (error) {
@@ -133,6 +143,43 @@ function getTemplateData(projectName, description, appName) {
133
143
  appName
134
144
  };
135
145
  }
146
+ /**
147
+ * Detects if we're in a workspace root directory
148
+ */
149
+ async function isWorkspaceRoot(directory) {
150
+ const packageJsonPath = path.join(directory, 'package.json');
151
+ if (await fs.pathExists(packageJsonPath)) {
152
+ try {
153
+ const packageJson = await fs.readJSON(packageJsonPath);
154
+ return !!(packageJson.workspaces && Array.isArray(packageJson.workspaces));
155
+ }
156
+ catch (error) {
157
+ return false;
158
+ }
159
+ }
160
+ return false;
161
+ }
162
+ /**
163
+ * Resolves the correct project path for individual projects (native, web, shared).
164
+ * Individual projects can ONLY be created within an existing workspace.
165
+ * This enforces proper monorepo structure and prevents scattered individual projects.
166
+ */
167
+ async function resolveProjectPath(projectName, directory) {
168
+ // Check if we're in a workspace directory
169
+ const isWorkspace = await isWorkspaceRoot(directory);
170
+ if (!isWorkspace) {
171
+ throw new Error(`Individual projects can only be created within a workspace.\n` +
172
+ `Please first create a workspace with: idealyst init my-workspace\n` +
173
+ `Then navigate to the workspace directory and create your project.`);
174
+ }
175
+ // Create project in workspace's packages/ folder
176
+ const packagesDir = path.join(directory, 'packages');
177
+ await fs.ensureDir(packagesDir);
178
+ return {
179
+ projectPath: path.join(packagesDir, projectName),
180
+ workspacePath: `packages/${projectName}`
181
+ };
182
+ }
136
183
  async function initializeReactNativeProject(projectName, directory, displayName, skipInstall) {
137
184
  const spinner = ora('Initializing React Native project...').start();
138
185
  try {
@@ -206,6 +253,10 @@ async function mergePackageJsonDependencies(templatePath, projectPath) {
206
253
  '@react-navigation/drawer': '^7.5.3',
207
254
  '@react-navigation/native': '^7.1.14',
208
255
  '@react-navigation/native-stack': '^7.3.21',
256
+ '@tanstack/react-query': '^5.83.0',
257
+ '@trpc/client': '^11.4.3',
258
+ '@trpc/react-query': '^11.4.3',
259
+ '@trpc/server': '^11.4.3',
209
260
  'react-native-edge-to-edge': '^1.6.2',
210
261
  'react-native-gesture-handler': '^2.27.1',
211
262
  'react-native-nitro-modules': '^0.26.3',
@@ -259,7 +310,8 @@ async function promptForProjectType() {
259
310
  choices: [
260
311
  { name: 'React Native App', value: 'native' },
261
312
  { name: 'React Web App', value: 'web' },
262
- { name: 'Shared Library', value: 'shared' }
313
+ { name: 'Shared Library', value: 'shared' },
314
+ { name: 'API Server (tRPC + Prisma + Zod)', value: 'api' }
263
315
  ],
264
316
  default: 'native'
265
317
  }
@@ -284,6 +336,71 @@ async function promptForAppName(projectName) {
284
336
  ]);
285
337
  return appName;
286
338
  }
339
+ async function promptForTrpcIntegration() {
340
+ const { withTrpc } = await inquirer.prompt([
341
+ {
342
+ type: 'confirm',
343
+ name: 'withTrpc',
344
+ message: 'Would you like to include tRPC client setup and boilerplate?',
345
+ default: false
346
+ }
347
+ ]);
348
+ return withTrpc;
349
+ }
350
+ async function copyTrpcFiles(templatePath, projectPath, data) {
351
+ const spinner = ora('Adding tRPC client utilities...').start();
352
+ try {
353
+ const trpcUtilsSource = path.join(templatePath, 'src', 'utils', 'trpc.ts');
354
+ const trpcUtilsTarget = path.join(projectPath, 'src', 'utils', 'trpc.ts');
355
+ // Ensure utils directory exists
356
+ await fs.ensureDir(path.join(projectPath, 'src', 'utils'));
357
+ // Copy and process the tRPC utils file
358
+ await fs.copy(trpcUtilsSource, trpcUtilsTarget);
359
+ await processTemplateFile(trpcUtilsTarget, data);
360
+ spinner.succeed('tRPC client utilities added');
361
+ }
362
+ catch (error) {
363
+ spinner.fail('Failed to add tRPC client utilities');
364
+ console.warn(chalk.yellow('āš ļø tRPC utilities could not be copied, but the project was created successfully'));
365
+ }
366
+ }
367
+ async function copyTrpcAppComponent(templatePath, projectPath, data) {
368
+ const spinner = ora('Setting up tRPC App component...').start();
369
+ try {
370
+ const trpcAppSource = path.join(templatePath, 'src', 'App-with-trpc.tsx');
371
+ const appTarget = path.join(projectPath, 'src', 'App.tsx');
372
+ // Copy the tRPC-enabled App component over the default one
373
+ await fs.copy(trpcAppSource, appTarget, { overwrite: true });
374
+ await processTemplateFile(appTarget, data);
375
+ spinner.succeed('tRPC App component configured');
376
+ }
377
+ catch (error) {
378
+ spinner.fail('Failed to configure tRPC App component');
379
+ console.warn(chalk.yellow('āš ļø tRPC App component could not be configured, but the project was created successfully'));
380
+ }
381
+ }
382
+ async function removeTrpcDependencies(projectPath) {
383
+ try {
384
+ const packageJsonPath = path.join(projectPath, 'package.json');
385
+ const packageJson = await fs.readJSON(packageJsonPath);
386
+ // Remove tRPC-related dependencies
387
+ const trpcDeps = [
388
+ '@tanstack/react-query',
389
+ '@trpc/client',
390
+ '@trpc/react-query',
391
+ '@trpc/server'
392
+ ];
393
+ trpcDeps.forEach(dep => {
394
+ if (packageJson.dependencies && packageJson.dependencies[dep]) {
395
+ delete packageJson.dependencies[dep];
396
+ }
397
+ });
398
+ await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
399
+ }
400
+ catch (error) {
401
+ console.warn(chalk.yellow('āš ļø Could not remove tRPC dependencies from package.json'));
402
+ }
403
+ }
287
404
  async function configureAndroidVectorIcons(projectPath) {
288
405
  const buildGradlePath = path.join(projectPath, 'android', 'app', 'build.gradle');
289
406
  try {
@@ -323,10 +440,13 @@ var utils = /*#__PURE__*/Object.freeze({
323
440
  __proto__: null,
324
441
  configureAndroidVectorIcons: configureAndroidVectorIcons,
325
442
  copyTemplate: copyTemplate,
443
+ copyTrpcAppComponent: copyTrpcAppComponent,
444
+ copyTrpcFiles: copyTrpcFiles,
326
445
  createPackageName: createPackageName,
327
446
  getTemplateData: getTemplateData,
328
447
  initializeReactNativeProject: initializeReactNativeProject,
329
448
  installDependencies: installDependencies,
449
+ isWorkspaceRoot: isWorkspaceRoot,
330
450
  mergePackageJsonDependencies: mergePackageJsonDependencies,
331
451
  overlayIdealystFiles: overlayIdealystFiles,
332
452
  processTemplateFile: processTemplateFile,
@@ -334,34 +454,49 @@ var utils = /*#__PURE__*/Object.freeze({
334
454
  promptForAppName: promptForAppName,
335
455
  promptForProjectName: promptForProjectName,
336
456
  promptForProjectType: promptForProjectType,
457
+ promptForTrpcIntegration: promptForTrpcIntegration,
458
+ removeTrpcDependencies: removeTrpcDependencies,
459
+ resolveProjectPath: resolveProjectPath,
337
460
  runCommand: runCommand,
338
461
  updateWorkspacePackageJson: updateWorkspacePackageJson,
339
462
  validateProjectName: validateProjectName
340
463
  });
341
464
 
342
- const __filename$3 = fileURLToPath(import.meta.url);
343
- const __dirname$3 = path.dirname(__filename$3);
465
+ const __filename$4 = fileURLToPath(import.meta.url);
466
+ const __dirname$4 = path.dirname(__filename$4);
344
467
  async function generateNativeProject(options) {
345
- const { name, directory, skipInstall, appName } = options;
468
+ const { name, directory, skipInstall, appName, withTrpc } = options;
346
469
  if (!validateProjectName(name)) {
347
470
  throw new Error(`Invalid project name: ${name}`);
348
471
  }
349
472
  const displayName = appName || name.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
350
473
  console.log(chalk.blue(`šŸ“± Creating React Native project: ${name}`));
351
474
  console.log(chalk.gray(` App display name: ${displayName}`));
352
- const projectPath = path.join(directory, name);
353
- const templatePath = path.join(__dirname$3, '..', 'templates', 'native');
475
+ const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
476
+ const templatePath = path.join(__dirname$4, '..', 'templates', 'native');
354
477
  const templateData = getTemplateData(name, `React Native app built with Idealyst Framework`, displayName);
355
478
  try {
356
479
  // Step 1: Update workspace configuration FIRST (before React Native CLI)
357
- await updateWorkspacePackageJson(name, directory);
480
+ await updateWorkspacePackageJson(workspacePath, directory);
358
481
  // Step 2: Initialize React Native project using CLI with --skip-install
359
- await initializeReactNativeProject(name, directory, displayName, true);
482
+ // Note: For React Native CLI, we need to run it in the parent directory and specify the project name
483
+ const projectDir = path.dirname(projectPath);
484
+ const projectName = path.basename(projectPath);
485
+ await initializeReactNativeProject(projectName, projectDir, displayName, true);
360
486
  // Step 3: Overlay Idealyst-specific files
361
487
  await overlayIdealystFiles(templatePath, projectPath, templateData);
362
- // Step 4: Configure Android vector icons
488
+ // Step 4: Handle tRPC setup
489
+ if (withTrpc) {
490
+ await copyTrpcFiles(templatePath, projectPath, templateData);
491
+ await copyTrpcAppComponent(templatePath, projectPath, templateData);
492
+ }
493
+ // Step 5: Configure Android vector icons
363
494
  await configureAndroidVectorIcons(projectPath);
364
- // Step 5: Install dependencies (including Idealyst packages) after workspace config is updated
495
+ // Step 6: Remove tRPC dependencies if not requested (after merge but before install)
496
+ if (!withTrpc) {
497
+ await removeTrpcDependencies(projectPath);
498
+ }
499
+ // Step 7: Install dependencies (including Idealyst packages) after workspace config is updated
365
500
  await installDependencies(projectPath, skipInstall);
366
501
  console.log(chalk.green('āœ… React Native project created successfully!'));
367
502
  console.log(chalk.blue('šŸ“‹ Project includes:'));
@@ -374,6 +509,11 @@ async function generateNativeProject(options) {
374
509
  console.log(chalk.white(' • Metro configuration'));
375
510
  console.log(chalk.white(' • Babel configuration'));
376
511
  console.log(chalk.white(' • Native platform directories (android/, ios/)'));
512
+ if (withTrpc) {
513
+ console.log(chalk.white(' • tRPC client setup and utilities'));
514
+ console.log(chalk.white(' • React Query integration'));
515
+ console.log(chalk.white(' • Pre-configured tRPC provider'));
516
+ }
377
517
  }
378
518
  catch (error) {
379
519
  console.error(chalk.red('āŒ Error creating React Native project:'));
@@ -382,20 +522,29 @@ async function generateNativeProject(options) {
382
522
  }
383
523
  }
384
524
 
385
- const __filename$2 = fileURLToPath(import.meta.url);
386
- const __dirname$2 = path.dirname(__filename$2);
525
+ const __filename$3 = fileURLToPath(import.meta.url);
526
+ const __dirname$3 = path.dirname(__filename$3);
387
527
  async function generateWebProject(options) {
388
- const { name, directory, skipInstall } = options;
528
+ const { name, directory, skipInstall, withTrpc } = options;
389
529
  if (!validateProjectName(name)) {
390
530
  throw new Error(`Invalid project name: ${name}`);
391
531
  }
392
532
  console.log(chalk.blue(`🌐 Creating React Web project: ${name}`));
393
- const projectPath = path.join(directory, name);
394
- const templatePath = path.join(__dirname$2, '..', 'templates', 'web');
533
+ const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
534
+ const templatePath = path.join(__dirname$3, '..', 'templates', 'web');
395
535
  const templateData = getTemplateData(name, `React web app built with Idealyst Framework`);
396
536
  await copyTemplate(templatePath, projectPath, templateData);
537
+ // Handle tRPC setup
538
+ if (withTrpc) {
539
+ await copyTrpcFiles(templatePath, projectPath, templateData);
540
+ await copyTrpcAppComponent(templatePath, projectPath, templateData);
541
+ }
542
+ else {
543
+ // Remove tRPC dependencies if not requested
544
+ await removeTrpcDependencies(projectPath);
545
+ }
397
546
  await installDependencies(projectPath, skipInstall);
398
- await updateWorkspacePackageJson(name, directory);
547
+ await updateWorkspacePackageJson(workspacePath, directory);
399
548
  console.log(chalk.green('āœ… React Web project created successfully!'));
400
549
  console.log(chalk.blue('šŸ“‹ Project includes:'));
401
550
  console.log(chalk.white(' • React 19.1'));
@@ -405,22 +554,27 @@ async function generateWebProject(options) {
405
554
  console.log(chalk.white(' • Idealyst Theme'));
406
555
  console.log(chalk.white(' • TypeScript configuration'));
407
556
  console.log(chalk.white(' • React Router'));
557
+ if (withTrpc) {
558
+ console.log(chalk.white(' • tRPC client setup and utilities'));
559
+ console.log(chalk.white(' • React Query integration'));
560
+ console.log(chalk.white(' • Pre-configured tRPC provider'));
561
+ }
408
562
  }
409
563
 
410
- const __filename$1 = fileURLToPath(import.meta.url);
411
- const __dirname$1 = path.dirname(__filename$1);
564
+ const __filename$2 = fileURLToPath(import.meta.url);
565
+ const __dirname$2 = path.dirname(__filename$2);
412
566
  async function generateSharedLibrary(options) {
413
567
  const { name, directory, skipInstall } = options;
414
568
  if (!validateProjectName(name)) {
415
569
  throw new Error(`Invalid project name: ${name}`);
416
570
  }
417
571
  console.log(chalk.blue(`šŸ“¦ Creating shared library: ${name}`));
418
- const projectPath = path.join(directory, name);
419
- const templatePath = path.join(__dirname$1, '..', 'templates', 'shared');
572
+ const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
573
+ const templatePath = path.join(__dirname$2, '..', 'templates', 'shared');
420
574
  const templateData = getTemplateData(name, `Shared library built with Idealyst Framework`);
421
575
  await copyTemplate(templatePath, projectPath, templateData);
422
576
  await installDependencies(projectPath, skipInstall);
423
- await updateWorkspacePackageJson(name, directory);
577
+ await updateWorkspacePackageJson(workspacePath, directory);
424
578
  console.log(chalk.green('āœ… Shared library created successfully!'));
425
579
  console.log(chalk.blue('šŸ“‹ Project includes:'));
426
580
  console.log(chalk.white(' • Cross-platform components'));
@@ -430,8 +584,8 @@ async function generateSharedLibrary(options) {
430
584
  console.log(chalk.white(' • React & React Native support'));
431
585
  }
432
586
 
433
- const __filename = fileURLToPath(import.meta.url);
434
- const __dirname = path.dirname(__filename);
587
+ const __filename$1 = fileURLToPath(import.meta.url);
588
+ const __dirname$1 = path.dirname(__filename$1);
435
589
  async function generateWorkspace(options) {
436
590
  const { name, directory, skipInstall } = options;
437
591
  if (!validateProjectName(name)) {
@@ -439,7 +593,7 @@ async function generateWorkspace(options) {
439
593
  }
440
594
  console.log(chalk.blue(`šŸ—ļø Creating Idealyst workspace: ${name}`));
441
595
  const projectPath = path.join(directory, name);
442
- const templatePath = path.join(__dirname, '..', 'templates', 'workspace');
596
+ const templatePath = path.join(__dirname$1, '..', 'templates', 'workspace');
443
597
  const templateData = getTemplateData(name, `Idealyst Framework monorepo workspace`);
444
598
  await copyTemplate(templatePath, projectPath, templateData);
445
599
  await installDependencies(projectPath, skipInstall);
@@ -452,6 +606,32 @@ async function generateWorkspace(options) {
452
606
  console.log(chalk.white(' • Version management scripts'));
453
607
  }
454
608
 
609
+ const __filename = fileURLToPath(import.meta.url);
610
+ const __dirname = path.dirname(__filename);
611
+ async function generateApiProject(options) {
612
+ const { name, directory, skipInstall } = options;
613
+ if (!validateProjectName(name)) {
614
+ throw new Error(`Invalid project name: ${name}`);
615
+ }
616
+ console.log(chalk.blue(`šŸš€ Creating API project: ${name}`));
617
+ const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
618
+ const templatePath = path.join(__dirname, '..', 'templates', 'api');
619
+ const templateData = getTemplateData(name, `Clean API server template with tRPC, Prisma, and Zod`);
620
+ await copyTemplate(templatePath, projectPath, templateData);
621
+ await installDependencies(projectPath, skipInstall);
622
+ await updateWorkspacePackageJson(workspacePath, directory);
623
+ console.log(chalk.green('āœ… API project created successfully!'));
624
+ console.log(chalk.blue('šŸ“‹ Project includes:'));
625
+ console.log(chalk.white(' • tRPC for type-safe APIs'));
626
+ console.log(chalk.white(' • Prisma for database management'));
627
+ console.log(chalk.white(' • Zod for schema validation'));
628
+ console.log(chalk.white(' • Express.js server'));
629
+ console.log(chalk.white(' • TypeScript configuration'));
630
+ console.log(chalk.white(' • CORS and middleware setup'));
631
+ console.log(chalk.white(' • Database migration scripts'));
632
+ console.log(chalk.white(' • Clean template ready for your models'));
633
+ }
634
+
455
635
  async function generateProject(options) {
456
636
  const { type } = options;
457
637
  switch (type) {
@@ -467,6 +647,9 @@ async function generateProject(options) {
467
647
  case 'workspace':
468
648
  await generateWorkspace(options);
469
649
  break;
650
+ case 'api':
651
+ await generateApiProject(options);
652
+ break;
470
653
  default:
471
654
  throw new Error(`Unknown project type: ${type}`);
472
655
  }
@@ -480,9 +663,10 @@ program
480
663
  program
481
664
  .command('create [project-name]')
482
665
  .description('Create a new Idealyst project')
483
- .option('-t, --type <type>', 'Project type: native, web, or shared')
666
+ .option('-t, --type <type>', 'Project type: native, web, shared, or api')
484
667
  .option('-d, --directory <directory>', 'Output directory', '.')
485
668
  .option('-a, --app-name <app-name>', 'Display name for native apps (e.g., "My Awesome App")')
669
+ .option('--with-trpc', 'Include tRPC boilerplate and setup (for web/native projects)')
486
670
  .option('--skip-install', 'Skip installing dependencies')
487
671
  .action(async (projectName, options) => {
488
672
  try {
@@ -505,7 +689,7 @@ program
505
689
  if (!projectType) {
506
690
  projectType = await promptForProjectType();
507
691
  }
508
- const validTypes = ['native', 'web', 'shared'];
692
+ const validTypes = ['native', 'web', 'shared', 'api'];
509
693
  if (!validTypes.includes(projectType)) {
510
694
  console.error(chalk.red(`Invalid project type: ${projectType}`));
511
695
  console.error(chalk.yellow(`Valid types are: ${validTypes.join(', ')}`));
@@ -516,28 +700,41 @@ program
516
700
  if (projectType === 'native' && !appName) {
517
701
  appName = await promptForAppName(projectName);
518
702
  }
703
+ // Prompt for tRPC integration if it's a web/native project and flag not provided
704
+ let withTrpc = options.withTrpc;
705
+ if ((projectType === 'web' || projectType === 'native') && withTrpc === undefined) {
706
+ withTrpc = await promptForTrpcIntegration();
707
+ }
519
708
  await generateProject({
520
709
  name: projectName,
521
710
  type: projectType,
522
711
  directory: options.directory,
523
712
  skipInstall: options.skipInstall || false,
524
- appName
713
+ appName,
714
+ withTrpc: withTrpc || false
525
715
  });
526
716
  console.log(chalk.green(`✨ Successfully created ${projectName}!`));
527
- console.log(chalk.blue(`šŸ“ Project created in: ${options.directory}/${projectName}`));
717
+ console.log(chalk.blue(`šŸ“ Project created in: ${options.directory}/packages/${projectName}`));
528
718
  if (projectType === 'native') {
529
719
  console.log(chalk.yellow('\nšŸ“± Next steps for React Native:'));
530
- console.log(chalk.white(' cd ' + projectName));
720
+ console.log(chalk.white(' cd packages/' + projectName));
531
721
  console.log(chalk.white(' yarn android # or yarn ios'));
532
722
  }
533
723
  else if (projectType === 'web') {
534
724
  console.log(chalk.yellow('\n🌐 Next steps for React Web:'));
535
- console.log(chalk.white(' cd ' + projectName));
725
+ console.log(chalk.white(' cd packages/' + projectName));
536
726
  console.log(chalk.white(' yarn dev'));
537
727
  }
728
+ else if (projectType === 'api') {
729
+ console.log(chalk.yellow('\nšŸš€ Next steps for API Server:'));
730
+ console.log(chalk.white(' cd packages/' + projectName));
731
+ console.log(chalk.white(' yarn dev # Start development server'));
732
+ console.log(chalk.white(' yarn db:push # Push database schema'));
733
+ console.log(chalk.white(' yarn db:studio # Open Prisma Studio'));
734
+ }
538
735
  else {
539
736
  console.log(chalk.yellow('\nšŸ“¦ Next steps for Shared Library:'));
540
- console.log(chalk.white(' cd ' + projectName));
737
+ console.log(chalk.white(' cd packages/' + projectName));
541
738
  console.log(chalk.white(' yarn build'));
542
739
  }
543
740
  }