zero-config-cli 1.0.0

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/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function createCLI(): Command;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8QpC,wBAAgB,SAAS,IAAI,OAAO,CA8BnC"}
package/dist/cli.js ADDED
@@ -0,0 +1,245 @@
1
+ // ---------------------------------------------------------------------------
2
+ // CLI interface — Commander setup + interactive prompts via @clack/prompts
3
+ // ---------------------------------------------------------------------------
4
+ import { Command } from 'commander';
5
+ import { intro, outro, select, text, spinner, note, cancel, isCancel } from '@clack/prompts';
6
+ import pc from 'picocolors';
7
+ import { templateData, FRONTEND_KEYS, BACKEND_KEYS, databaseOptions } from './registry.js';
8
+ import { generateProject } from './generator.js';
9
+ import { installDependencies } from './installer.js';
10
+ const PKG = { version: '1.0.0', name: 'zero-config-cli' };
11
+ /** Prompt user to select a frontend framework. */
12
+ async function promptFrontend() {
13
+ const choices = FRONTEND_KEYS.map((key) => {
14
+ const t = templateData[key];
15
+ return {
16
+ value: key,
17
+ label: `${t.icon} ${t.name} ${t.version}`,
18
+ hint: `Port ${t.port} · ${t.description}`,
19
+ };
20
+ });
21
+ const result = await select({
22
+ message: 'Select a frontend framework:',
23
+ options: choices,
24
+ });
25
+ if (isCancel(result)) {
26
+ cancel('Operation cancelled.');
27
+ process.exit(0);
28
+ }
29
+ return result;
30
+ }
31
+ /** Ask user for a custom folder name, with a default fallback. */
32
+ async function promptFolderName(defaultName, label) {
33
+ const result = await text({
34
+ message: `Enter folder name for ${label}:`,
35
+ placeholder: defaultName,
36
+ defaultValue: defaultName,
37
+ validate: (value) => {
38
+ if (!value || value.trim().length === 0)
39
+ return 'Folder name cannot be empty';
40
+ if (!/^[a-zA-Z0-9\-_]+$/.test(value.trim())) {
41
+ return 'Folder name must only contain letters, numbers, hyphens, and underscores';
42
+ }
43
+ },
44
+ });
45
+ if (isCancel(result)) {
46
+ cancel('Operation cancelled.');
47
+ process.exit(0);
48
+ }
49
+ return result.trim() || defaultName;
50
+ }
51
+ /** Prompt user to select a backend framework. */
52
+ async function promptBackend() {
53
+ const choices = BACKEND_KEYS.map((key) => {
54
+ const t = templateData[key];
55
+ return {
56
+ value: key,
57
+ label: `${t.icon} ${t.name} ${t.version}`,
58
+ hint: `Port ${t.port} · ${t.description}`,
59
+ };
60
+ });
61
+ const result = await select({
62
+ message: 'Select a backend framework:',
63
+ options: choices,
64
+ });
65
+ if (isCancel(result)) {
66
+ cancel('Operation cancelled.');
67
+ process.exit(0);
68
+ }
69
+ return result;
70
+ }
71
+ /** Prompt user to select a database. */
72
+ async function promptDatabase() {
73
+ const choices = databaseOptions.map((db) => ({
74
+ value: db.id,
75
+ label: `${db.icon} ${db.name}`,
76
+ hint: db.description,
77
+ }));
78
+ const result = await select({
79
+ message: 'Select a database:',
80
+ options: choices,
81
+ });
82
+ if (isCancel(result)) {
83
+ cancel('Operation cancelled.');
84
+ process.exit(0);
85
+ }
86
+ return result;
87
+ }
88
+ /** Prompt user for npm install scope. */
89
+ async function promptInstallScope() {
90
+ const result = await select({
91
+ message: 'Install dependencies?',
92
+ options: [
93
+ { value: 'both', label: 'Yes (both frontend & backend)', hint: 'Recommended' },
94
+ { value: 'backend', label: 'Backend only' },
95
+ { value: 'frontend', label: 'Frontend only' },
96
+ { value: 'skip', label: 'Skip' },
97
+ ],
98
+ initialValue: 'both',
99
+ });
100
+ if (isCancel(result)) {
101
+ cancel('Operation cancelled.');
102
+ process.exit(0);
103
+ }
104
+ return result;
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Main interactive flow
108
+ // ---------------------------------------------------------------------------
109
+ async function runInteractive(outputDir, options) {
110
+ intro(pc.bold(pc.cyan('Zero-Config Starter Generator')));
111
+ // Step 1: Frontend
112
+ const frontend = options.frontend || (await promptFrontend());
113
+ const frontendFolder = options.frontendFolder || (await promptFolderName(frontend, 'frontend'));
114
+ // Step 2: Backend
115
+ const backend = options.backend || (await promptBackend());
116
+ const backendFolder = options.backendFolder || (await promptFolderName(backend, 'backend'));
117
+ // Step 3: Database
118
+ const database = options.database || (await promptDatabase());
119
+ // Generate
120
+ const genSpinner = spinner();
121
+ genSpinner.start('Generating your project...');
122
+ try {
123
+ const result = await generateProject({
124
+ frontend,
125
+ backend,
126
+ database,
127
+ outputDir,
128
+ frontendFolderName: frontendFolder,
129
+ backendFolderName: backendFolder,
130
+ templatesPath: options.templatesPath,
131
+ });
132
+ genSpinner.stop('Project generated successfully!');
133
+ note(`📁 ${pc.bold(outputDir)}/\n` +
134
+ ` ${result.frontendFolder}/\n` +
135
+ ` ${result.backendFolder}/\n` +
136
+ `🗄️ Database: ${databaseOptions.find((d) => d.id === database)?.name || database}`, 'Generated Structure');
137
+ // Step 4: npm install (skip with --no-install flag)
138
+ const installScope = options.install === false ? 'skip' : await promptInstallScope();
139
+ if (installScope !== 'skip') {
140
+ const installSpinner = spinner();
141
+ installSpinner.start('Installing dependencies...');
142
+ const { installed, failed } = await installDependencies(installScope, result.frontendPath, result.backendPath);
143
+ if (failed.length > 0) {
144
+ installSpinner.stop(`${pc.green(`Installed in: ${installed.join(', ') || 'none'}`)} ${pc.red(`Failed: ${failed.join(', ') || 'none'}`)}`);
145
+ }
146
+ else if (installed.length > 0) {
147
+ installSpinner.stop(`${pc.green(`Dependencies installed in ${installed.join(' & ')}`)}`);
148
+ }
149
+ }
150
+ // Final message
151
+ const fe = templateData[frontend];
152
+ const be = templateData[backend];
153
+ const db = databaseOptions.find((d) => d.id === database);
154
+ outro(`${pc.green('✨')} Your stack is ready!\n\n` +
155
+ ` ${fe.icon} Frontend: ${pc.cyan(`cd ${outputDir}/${result.frontendFolder} && npm run dev`)} → ${pc.underline(`http://localhost:${fe.port}`)}\n` +
156
+ ` ${be.icon} Backend: ${pc.cyan(`cd ${outputDir}/${result.backendFolder} && npm run dev`)} → ${pc.underline(`http://localhost:${be.port}`)}\n` +
157
+ ` ${db.icon} Database: ${db.name}\n\n` +
158
+ ` ${pc.dim('Happy coding! 🚀')}`);
159
+ }
160
+ catch (err) {
161
+ genSpinner.stop('Generation failed');
162
+ const message = err instanceof Error ? err.message : 'Unknown error';
163
+ cancel(`${pc.red('Error:')} ${message}`);
164
+ process.exit(1);
165
+ }
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Non-interactive / flag-based mode
169
+ // ---------------------------------------------------------------------------
170
+ async function runNonInteractive(outputDir, options) {
171
+ if (!options.frontend || !options.backend || !options.database) {
172
+ console.error(pc.red('Error:') +
173
+ ' In non-interactive mode you must provide --frontend, --backend, and --database flags.\n' +
174
+ ` Example: npx zero-config my-project -f react -b express -d postgresql`);
175
+ process.exit(1);
176
+ }
177
+ const frontendFolder = options.frontendFolder || options.frontend;
178
+ const backendFolder = options.backendFolder || options.backend;
179
+ try {
180
+ const result = await generateProject({
181
+ frontend: options.frontend,
182
+ backend: options.backend,
183
+ database: options.database,
184
+ outputDir,
185
+ frontendFolderName: frontendFolder,
186
+ backendFolderName: backendFolder,
187
+ templatesPath: options.templatesPath,
188
+ });
189
+ console.log(pc.green('✅ Project generated successfully!'));
190
+ console.log(` ${outputDir}/${result.frontendFolder}/`);
191
+ console.log(` ${outputDir}/${result.backendFolder}/`);
192
+ if (options.install !== false) {
193
+ console.log(pc.cyan('\nInstalling dependencies...'));
194
+ const { installed, failed } = await installDependencies('both', result.frontendPath, result.backendPath);
195
+ if (failed.length > 0) {
196
+ console.log(pc.yellow(`Installed: ${installed.join(', ') || 'none'} Failed: ${failed.join(', ') || 'none'}`));
197
+ }
198
+ else {
199
+ console.log(pc.green(`Dependencies installed in ${installed.join(' & ')}`));
200
+ }
201
+ }
202
+ const fe = templateData[options.frontend];
203
+ const be = templateData[options.backend];
204
+ console.log(`\n${pc.bold('Next steps:')}`);
205
+ console.log(` ${fe.icon} Frontend: cd ${outputDir}/${result.frontendFolder} && npm run dev`);
206
+ console.log(` ${be.icon} Backend: cd ${outputDir}/${result.backendFolder} && npm run dev`);
207
+ }
208
+ catch (err) {
209
+ const message = err instanceof Error ? err.message : 'Unknown error';
210
+ console.error(pc.red('Error:'), message);
211
+ process.exit(1);
212
+ }
213
+ }
214
+ // ---------------------------------------------------------------------------
215
+ // Commander setup
216
+ // ---------------------------------------------------------------------------
217
+ export function createCLI() {
218
+ const program = new Command();
219
+ program
220
+ .name('zero-config')
221
+ .description('Generate production-ready full-stack starter projects with zero config')
222
+ .version(PKG.version);
223
+ program
224
+ .command('init', { isDefault: true })
225
+ .description('Generate a new full-stack starter project')
226
+ .argument('[outputDir]', 'Output directory name', 'my-project')
227
+ .option('-f, --frontend <name>', 'Frontend template (react, angular, vuejs, nextjs)')
228
+ .option('-b, --backend <name>', 'Backend template (express, nestjs, fastify)')
229
+ .option('-d, --database <name>', 'Database (postgresql, mysql, mariadb, sqlserver, sqlite, cockroachdb, mongodb)')
230
+ .option('--frontend-folder <name>', 'Custom folder name for frontend')
231
+ .option('--backend-folder <name>', 'Custom folder name for backend')
232
+ .option('--no-install', 'Skip npm install step')
233
+ .option('-t, --templates-path <path>', 'Path to templates folder or GitHub zip URL')
234
+ .action(async (outputDir, options) => {
235
+ const isInteractive = !options.frontend && !options.backend && !options.database;
236
+ if (isInteractive) {
237
+ await runInteractive(outputDir, options);
238
+ }
239
+ else {
240
+ await runNonInteractive(outputDir, options);
241
+ }
242
+ });
243
+ return program;
244
+ }
245
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { TemplateFile } from './types.js';
2
+ /**
3
+ * Recursively read a template directory and return all files with their paths.
4
+ * Mirror of the backend's `readLocalTemplateFolder()`.
5
+ */
6
+ export declare function readLocalTemplateFolder(templateName: string, basePath: string): TemplateFile[];
7
+ /**
8
+ * Write template files to a target output directory.
9
+ * Creates directories as needed.
10
+ */
11
+ export declare function writeTemplateFiles(files: TemplateFile[], outputDir: string): void;
12
+ //# sourceMappingURL=copier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copier.d.ts","sourceRoot":"","sources":["../src/copier.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,uBAAuB,CACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACjB,YAAY,EAAE,CAahB;AAiBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,YAAY,EAAE,EACrB,SAAS,EAAE,MAAM,GAClB,IAAI,CAMN"}
package/dist/copier.js ADDED
@@ -0,0 +1,45 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Local template copier — walks a directory and returns all files as buffers
3
+ // Ported from zero-config/Backend/src/app.service.ts — readLocalTemplateFolder()
4
+ // ---------------------------------------------------------------------------
5
+ import * as fs from 'node:fs';
6
+ import * as path from 'node:path';
7
+ /**
8
+ * Recursively read a template directory and return all files with their paths.
9
+ * Mirror of the backend's `readLocalTemplateFolder()`.
10
+ */
11
+ export function readLocalTemplateFolder(templateName, basePath) {
12
+ const templateDir = path.join(basePath, templateName);
13
+ const files = [];
14
+ if (!fs.existsSync(templateDir)) {
15
+ throw new Error(`Template "${templateName}" not found at: ${templateDir}. ` +
16
+ 'Make sure the templates path is correct.');
17
+ }
18
+ walkDir(templateDir, '', files);
19
+ return files;
20
+ }
21
+ function walkDir(dir, relativePrefix, files) {
22
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
23
+ for (const entry of entries) {
24
+ const fullPath = path.join(dir, entry.name);
25
+ const relPath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name;
26
+ if (entry.isDirectory()) {
27
+ walkDir(fullPath, relPath, files);
28
+ }
29
+ else if (entry.isFile()) {
30
+ files.push({ path: relPath, content: fs.readFileSync(fullPath) });
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Write template files to a target output directory.
36
+ * Creates directories as needed.
37
+ */
38
+ export function writeTemplateFiles(files, outputDir) {
39
+ for (const file of files) {
40
+ const absolutePath = path.resolve(outputDir, file.path);
41
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
42
+ fs.writeFileSync(absolutePath, file.content);
43
+ }
44
+ }
45
+ //# sourceMappingURL=copier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copier.js","sourceRoot":"","sources":["../src/copier.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,iFAAiF;AACjF,8EAA8E;AAE9E,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACnC,YAAoB,EACpB,QAAgB;IAEhB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACtD,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACX,aAAa,YAAY,mBAAmB,WAAW,IAAI;YAC3D,0CAA0C,CAC7C,CAAC;IACN,CAAC;IAED,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,OAAO,CAAC,GAAW,EAAE,cAAsB,EAAE,KAAqB;IACvE,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAEhF,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACtB,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAC9B,KAAqB,EACrB,SAAiB;IAEjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { TemplateFile } from './types.js';
2
+ /**
3
+ * Fetch a zip archive from a URL with a timeout.
4
+ */
5
+ export declare function fetchZip(url: string): Promise<Buffer>;
6
+ /**
7
+ * Extract a single template folder from a zip buffer.
8
+ * Ported from the backend's `extractTemplateFolder()`.
9
+ */
10
+ export declare function extractTemplateFolder(zipBuffer: Buffer, templateName: string): Promise<TemplateFile[]>;
11
+ /**
12
+ * Download templates from URL, then extract a specific template folder.
13
+ */
14
+ export declare function downloadAndExtract(url: string, templateName: string): Promise<TemplateFile[]>;
15
+ //# sourceMappingURL=downloader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../src/downloader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C;;GAEG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB3D;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACvC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyCzB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACpC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC,CAGzB"}
@@ -0,0 +1,69 @@
1
+ // ---------------------------------------------------------------------------
2
+ // GitHub zip downloader + extractor
3
+ // Ported from zero-config/Backend/src/app.service.ts — extractTemplateFolder()
4
+ // ---------------------------------------------------------------------------
5
+ import unzipper from 'unzipper';
6
+ const FETCH_TIMEOUT = 30_000; // 30 seconds
7
+ const MAX_ZIP_SIZE = 50 * 1024 * 1024; // 50 MB
8
+ const MAX_EXTRACTED_SIZE = 100 * 1024 * 1024; // 100 MB
9
+ /**
10
+ * Fetch a zip archive from a URL with a timeout.
11
+ */
12
+ export async function fetchZip(url) {
13
+ const controller = new AbortController();
14
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
15
+ try {
16
+ const response = await fetch(url, { signal: controller.signal });
17
+ if (!response.ok) {
18
+ throw new Error(`Failed to fetch templates from ${url} (HTTP ${response.status})`);
19
+ }
20
+ const buffer = Buffer.from(await response.arrayBuffer());
21
+ if (buffer.length > MAX_ZIP_SIZE) {
22
+ throw new Error('Template archive exceeds maximum size (50MB)');
23
+ }
24
+ return buffer;
25
+ }
26
+ finally {
27
+ clearTimeout(timer);
28
+ }
29
+ }
30
+ /**
31
+ * Extract a single template folder from a zip buffer.
32
+ * Ported from the backend's `extractTemplateFolder()`.
33
+ */
34
+ export async function extractTemplateFolder(zipBuffer, templateName) {
35
+ let totalExtractedSize = 0;
36
+ const directory = await unzipper.Open.buffer(zipBuffer);
37
+ const repoPrefix = directory.files[0]?.path.split('/')[0] || '';
38
+ const templatePath = `${repoPrefix}/${templateName}/`;
39
+ const templateFiles = directory.files.filter((file) => file.path.startsWith(templatePath));
40
+ if (templateFiles.length === 0) {
41
+ throw new Error(`Template "${templateName}" not found in the archive. ` +
42
+ 'Make sure the template name is correct and the archive contains the expected folder.');
43
+ }
44
+ const files = [];
45
+ for (const file of templateFiles) {
46
+ if (file.type !== 'File')
47
+ continue;
48
+ const content = await file.buffer();
49
+ totalExtractedSize += content.length;
50
+ if (totalExtractedSize > MAX_EXTRACTED_SIZE) {
51
+ throw new Error('Total extracted size exceeds maximum (100MB)');
52
+ }
53
+ const relativePath = file.path.replace(templatePath, '');
54
+ // Prevent path traversal
55
+ if (relativePath.includes('..') || relativePath.startsWith('/')) {
56
+ continue;
57
+ }
58
+ files.push({ path: relativePath, content });
59
+ }
60
+ return files;
61
+ }
62
+ /**
63
+ * Download templates from URL, then extract a specific template folder.
64
+ */
65
+ export async function downloadAndExtract(url, templateName) {
66
+ const zipBuffer = await fetchZip(url);
67
+ return extractTemplateFolder(zipBuffer, templateName);
68
+ }
69
+ //# sourceMappingURL=downloader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloader.js","sourceRoot":"","sources":["../src/downloader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface GenerateOptions {
2
+ /** Frontend template key (e.g. "react") */
3
+ frontend: string;
4
+ /** Backend template key (e.g. "express") */
5
+ backend: string;
6
+ /** Database ID (e.g. "postgresql") */
7
+ database: string;
8
+ /** Output directory — the parent where frontend/backend folders go */
9
+ outputDir: string;
10
+ /** Custom folder name for the frontend template (defaults to template key) */
11
+ frontendFolderName?: string;
12
+ /** Custom folder name for the backend template (defaults to template key) */
13
+ backendFolderName?: string;
14
+ /** Explicit templates path (local folder or GitHub zip URL) */
15
+ templatesPath?: string;
16
+ }
17
+ export interface GenerateResult {
18
+ frontendPath: string;
19
+ backendPath: string;
20
+ frontendFolder: string;
21
+ backendFolder: string;
22
+ }
23
+ /**
24
+ * Generate a full-stack project:
25
+ * 1. Resolve template source
26
+ * 2. Copy/extract frontend + backend templates
27
+ * 3. Swap Prisma provider in backend
28
+ * 4. Write to output directory
29
+ */
30
+ export declare function generateProject(opts: GenerateOptions): Promise<GenerateResult>;
31
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,eAAe;IAC5B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACzB;AA4BD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAgEpF"}
@@ -0,0 +1,91 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Generator — orchestrates template resolution, file copying, and Prisma swap
3
+ // Ported from zero-config/Backend/src/app.service.ts — generateCombinedTemplates()
4
+ // ---------------------------------------------------------------------------
5
+ import * as path from 'node:path';
6
+ import * as fs from 'node:fs';
7
+ import { ALLOWED_TEMPLATES, FRONTEND_KEYS, BACKEND_KEYS } from './registry.js';
8
+ import { resolveTemplateSource } from './resolver.js';
9
+ import { readLocalTemplateFolder, writeTemplateFiles } from './copier.js';
10
+ import { fetchZip, extractTemplateFolder } from './downloader.js';
11
+ import { replacePrismaProvider, replacePrismaTestProvider } from './prisma-swap.js';
12
+ /**
13
+ * Validate that the selected templates are allowed and correctly paired.
14
+ */
15
+ function validateOptions(opts) {
16
+ if (!ALLOWED_TEMPLATES.has(opts.frontend)) {
17
+ throw new Error(`Invalid frontend: "${opts.frontend}". Allowed: ${FRONTEND_KEYS.join(', ')}`);
18
+ }
19
+ if (!ALLOWED_TEMPLATES.has(opts.backend)) {
20
+ throw new Error(`Invalid backend: "${opts.backend}". Allowed: ${BACKEND_KEYS.join(', ')}`);
21
+ }
22
+ if (!FRONTEND_KEYS.includes(opts.frontend)) {
23
+ throw new Error(`"${opts.frontend}" is not a frontend template. Expected one of: ${FRONTEND_KEYS.join(', ')}`);
24
+ }
25
+ if (!BACKEND_KEYS.includes(opts.backend)) {
26
+ throw new Error(`"${opts.backend}" is not a backend template. Expected one of: ${BACKEND_KEYS.join(', ')}`);
27
+ }
28
+ }
29
+ /**
30
+ * Generate a full-stack project:
31
+ * 1. Resolve template source
32
+ * 2. Copy/extract frontend + backend templates
33
+ * 3. Swap Prisma provider in backend
34
+ * 4. Write to output directory
35
+ */
36
+ export async function generateProject(opts) {
37
+ validateOptions(opts);
38
+ const source = resolveTemplateSource(opts.templatesPath);
39
+ const frontendFolder = opts.frontendFolderName || opts.frontend;
40
+ const backendFolder = opts.backendFolderName || opts.backend;
41
+ // Create output directory
42
+ const outputDir = path.resolve(process.cwd(), opts.outputDir);
43
+ fs.mkdirSync(outputDir, { recursive: true });
44
+ // --- Resolve templates ---
45
+ let frontendFiles;
46
+ let backendFiles;
47
+ if (source.type === 'local') {
48
+ frontendFiles = readLocalTemplateFolder(opts.frontend, source.path);
49
+ backendFiles = readLocalTemplateFolder(opts.backend, source.path);
50
+ }
51
+ else {
52
+ // Download once, extract both templates from the same zip
53
+ let zipBuffer;
54
+ try {
55
+ zipBuffer = await fetchZip(source.path);
56
+ }
57
+ catch (err) {
58
+ throw new Error(`Could not download templates from ${source.path}. ` +
59
+ 'Check your internet connection or set ZERO_CONFIG_TEMPLATES_PATH to a local folder.');
60
+ }
61
+ try {
62
+ [frontendFiles, backendFiles] = await Promise.all([
63
+ extractTemplateFolder(zipBuffer, opts.frontend),
64
+ extractTemplateFolder(zipBuffer, opts.backend),
65
+ ]);
66
+ }
67
+ catch (err) {
68
+ throw new Error(`Failed to extract templates from the archive: ${err instanceof Error ? err.message : 'Unknown error'}`);
69
+ }
70
+ }
71
+ // --- Swap Prisma provider in backend ---
72
+ replacePrismaProvider(backendFiles, opts.database);
73
+ replacePrismaTestProvider(backendFiles, opts.database);
74
+ // --- Prefix paths with folder names ---
75
+ for (const file of frontendFiles) {
76
+ file.path = `${frontendFolder}/${file.path}`;
77
+ }
78
+ for (const file of backendFiles) {
79
+ file.path = `${backendFolder}/${file.path}`;
80
+ }
81
+ // --- Write to disk ---
82
+ const allFiles = [...frontendFiles, ...backendFiles];
83
+ writeTemplateFiles(allFiles, outputDir);
84
+ return {
85
+ frontendPath: path.resolve(outputDir, frontendFolder),
86
+ backendPath: path.resolve(outputDir, backendFolder),
87
+ frontendFolder,
88
+ backendFolder,
89
+ };
90
+ }
91
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ // ---------------------------------------------------------------------------
3
+ // Entry point for the zero-config CLI.
4
+ // Bootstraps Commander and parses command-line arguments.
5
+ // ---------------------------------------------------------------------------
6
+ import { createCLI } from './cli.js';
7
+ const program = createCLI();
8
+ program.parse(process.argv);
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,8EAA8E;AAC9E,uCAAuC;AACvC,0DAA0D;AAC1D,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;AAE5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type InstallScope = 'both' | 'backend' | 'frontend' | 'skip';
2
+ /**
3
+ * Run npm install in one or both generated project directories.
4
+ * Returns a summary of what was installed.
5
+ */
6
+ export declare function installDependencies(scope: InstallScope, frontendPath: string, backendPath: string): Promise<{
7
+ installed: string[];
8
+ failed: string[];
9
+ }>;
10
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAEpE;;;GAGG;AACH,wBAAsB,mBAAmB,CACrC,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAyBpD"}
@@ -0,0 +1,33 @@
1
+ // ---------------------------------------------------------------------------
2
+ // npm install runner — installs dependencies in generated project folders
3
+ // ---------------------------------------------------------------------------
4
+ import { execSync } from 'node:child_process';
5
+ /**
6
+ * Run npm install in one or both generated project directories.
7
+ * Returns a summary of what was installed.
8
+ */
9
+ export async function installDependencies(scope, frontendPath, backendPath) {
10
+ const installed = [];
11
+ const failed = [];
12
+ const tasks = [
13
+ { label: 'Frontend', path: frontendPath, shouldRun: scope === 'both' || scope === 'frontend' },
14
+ { label: 'Backend', path: backendPath, shouldRun: scope === 'both' || scope === 'backend' },
15
+ ];
16
+ for (const task of tasks) {
17
+ if (!task.shouldRun)
18
+ continue;
19
+ try {
20
+ execSync('npm install', {
21
+ cwd: task.path,
22
+ stdio: 'pipe',
23
+ timeout: 120_000, // 2 minutes per folder
24
+ });
25
+ installed.push(task.label);
26
+ }
27
+ catch {
28
+ failed.push(task.label);
29
+ }
30
+ }
31
+ return { installed, failed };
32
+ }
33
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACrC,KAAmB,EACnB,YAAoB,EACpB,WAAmB;IAEnB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,KAAK,GAA0D;QACjE,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,UAAU,EAAE;QAC9F,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS,EAAE;KAC9F,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,SAAS;QAE9B,IAAI,CAAC;YACD,QAAQ,CAAC,aAAa,EAAE;gBACpB,GAAG,EAAE,IAAI,CAAC,IAAI;gBACd,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,OAAO,EAAE,uBAAuB;aAC5C,CAAC,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACL,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACL,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { TemplateFile } from './types.js';
2
+ /**
3
+ * Replace the Prisma datasource provider in all schema.prisma files.
4
+ *
5
+ * Targets only the `datasource db { ... }` block's provider line,
6
+ * not the `generator client { ... }` block.
7
+ *
8
+ * Ported from the backend's `replacePrismaProvider()`.
9
+ */
10
+ export declare function replacePrismaProvider(files: TemplateFile[], database: string | undefined): void;
11
+ /**
12
+ * Replace the test Prisma schema provider (schema.test.prisma) as well.
13
+ * Some templates have a separate test database schema.
14
+ */
15
+ export declare function replacePrismaTestProvider(files: TemplateFile[], database: string | undefined): void;
16
+ //# sourceMappingURL=prisma-swap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-swap.d.ts","sourceRoot":"","sources":["../src/prisma-swap.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,KAAK,EAAE,YAAY,EAAE,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC7B,IAAI,CAwBN;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,YAAY,EAAE,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC7B,IAAI,CAmBN"}
@@ -0,0 +1,53 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Prisma provider replacer
3
+ // Ported from zero-config/Backend/src/app.service.ts — replacePrismaProvider()
4
+ // ---------------------------------------------------------------------------
5
+ import { PROVIDER_MAP } from './registry.js';
6
+ /**
7
+ * Replace the Prisma datasource provider in all schema.prisma files.
8
+ *
9
+ * Targets only the `datasource db { ... }` block's provider line,
10
+ * not the `generator client { ... }` block.
11
+ *
12
+ * Ported from the backend's `replacePrismaProvider()`.
13
+ */
14
+ export function replacePrismaProvider(files, database) {
15
+ if (!database)
16
+ return;
17
+ const provider = PROVIDER_MAP[database];
18
+ if (!provider) {
19
+ console.warn(`[warn] Unknown database "${database}", skipping Prisma provider replacement`);
20
+ return;
21
+ }
22
+ for (const file of files) {
23
+ if (!file.path.endsWith('prisma/schema.prisma'))
24
+ continue;
25
+ const content = file.content.toString('utf-8');
26
+ // Match: datasource db { ... provider = "current_provider" ... }
27
+ const updated = content.replace(/(datasource db\s*\{[\s\S]*?provider\s*=\s*")[a-z0-9\-_]+(")/, `$1${provider}$2`);
28
+ if (updated !== content) {
29
+ file.content = Buffer.from(updated, 'utf-8');
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * Replace the test Prisma schema provider (schema.test.prisma) as well.
35
+ * Some templates have a separate test database schema.
36
+ */
37
+ export function replacePrismaTestProvider(files, database) {
38
+ if (!database)
39
+ return;
40
+ const provider = PROVIDER_MAP[database];
41
+ if (!provider)
42
+ return;
43
+ for (const file of files) {
44
+ if (!file.path.endsWith('prisma/schema.test.prisma'))
45
+ continue;
46
+ const content = file.content.toString('utf-8');
47
+ const updated = content.replace(/(datasource db\s*\{[\s\S]*?provider\s*=\s*")[a-z0-9\-_]+(")/, `$1${provider}$2`);
48
+ if (updated !== content) {
49
+ file.content = Buffer.from(updated, 'utf-8');
50
+ }
51
+ }
52
+ }
53
+ //# sourceMappingURL=prisma-swap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-swap.js","sourceRoot":"","sources":["../src/prisma-swap.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2BAA2B;AAC3B,+EAA+E;AAC/E,8EAA8E;AAG9E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACjC,KAAqB,EACrB,QAA4B;IAE5B,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,4BAA4B,QAAQ,yCAAyC,CAAC,CAAC;QAC5F,OAAO;IACX,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YAAE,SAAS;QAE1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE/C,iEAAiE;QACjE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAC3B,6DAA6D,EAC7D,KAAK,QAAQ,IAAI,CACpB,CAAC;QAEF,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACrC,KAAqB,EACrB,QAA4B;IAE5B,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAAE,SAAS;QAE/D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAC3B,6DAA6D,EAC7D,KAAK,QAAQ,IAAI,CACpB,CAAC;QAEF,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;IACL,CAAC;AACL,CAAC"}
@@ -0,0 +1,40 @@
1
+ export type TemplateType = 'frontend' | 'backend';
2
+ export interface FrontendTemplate {
3
+ name: string;
4
+ fullName: string;
5
+ icon: string;
6
+ type: 'frontend';
7
+ version: string;
8
+ port: number;
9
+ description: string;
10
+ technologies: string;
11
+ }
12
+ export interface BackendTemplate {
13
+ name: string;
14
+ fullName: string;
15
+ icon: string;
16
+ type: 'backend';
17
+ version: string;
18
+ port: number;
19
+ description: string;
20
+ technologies: string;
21
+ database: string;
22
+ databaseIcon: string;
23
+ orm: string;
24
+ }
25
+ export type Template = FrontendTemplate | BackendTemplate;
26
+ export interface DatabaseOption {
27
+ id: string;
28
+ name: string;
29
+ icon: string;
30
+ description: string;
31
+ defaultOrm: string;
32
+ }
33
+ export declare const templateData: Record<string, Template>;
34
+ export declare const ALL_TEMPLATE_KEYS: string[];
35
+ export declare const FRONTEND_KEYS: string[];
36
+ export declare const BACKEND_KEYS: string[];
37
+ export declare const databaseOptions: DatabaseOption[];
38
+ export declare const PROVIDER_MAP: Record<string, string>;
39
+ export declare const ALLOWED_TEMPLATES: ReadonlySet<string>;
40
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACtB;AAID,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAgFjD,CAAC;AAIF,eAAO,MAAM,iBAAiB,UAA4B,CAAC;AAE3D,eAAO,MAAM,aAAa,UAEF,CAAC;AAEzB,eAAO,MAAM,YAAY,UAED,CAAC;AAIzB,eAAO,MAAM,eAAe,EAAE,cAAc,EAQ3C,CAAC;AAMF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQ/C,CAAC;AAKF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAA8B,CAAC"}
@@ -0,0 +1,121 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Registry — single source of truth for all templates, databases, and mappings
3
+ // Ported from zero-config/frontend/app/data/templates.ts and
4
+ // zero-config/frontend/app/types/templates.ts
5
+ // ---------------------------------------------------------------------------
6
+ // --- Template Data --------------------------------------------------------
7
+ export const templateData = {
8
+ react: {
9
+ name: 'React',
10
+ fullName: 'React + Vite',
11
+ icon: '⚛️',
12
+ type: 'frontend',
13
+ version: 'v19',
14
+ port: 5173,
15
+ description: 'Auth context, Protected routes, Token refresh',
16
+ technologies: 'React 19, Vite 7.2, React Router v6, TypeScript 5.9, Tailwind CSS',
17
+ },
18
+ angular: {
19
+ name: 'Angular',
20
+ fullName: 'Angular + SSR',
21
+ icon: '🅰️',
22
+ type: 'frontend',
23
+ version: 'v21',
24
+ port: 4200,
25
+ description: 'Auth guards, Signals, Tailwind CSS 4',
26
+ technologies: 'Angular 21, SSR, Signals, Tailwind CSS 4.x, Vitest, RxJS',
27
+ },
28
+ vuejs: {
29
+ name: 'Vue.js',
30
+ fullName: 'Vue.js + Vite',
31
+ icon: '💚',
32
+ type: 'frontend',
33
+ version: 'v3',
34
+ port: 5173,
35
+ description: 'Pinia store, Composition API, Oxlint',
36
+ technologies: 'Vue 3.5, Pinia 3.0, Vue Router 4.6, Vite 7.3, Oxlint, Tailwind CSS',
37
+ },
38
+ nextjs: {
39
+ name: 'Next.js',
40
+ fullName: 'Next.js App Router',
41
+ icon: '▲',
42
+ type: 'frontend',
43
+ version: 'v16',
44
+ port: 3000,
45
+ description: 'SQLite auth, Server Actions, Full CRUD',
46
+ technologies: 'Next.js 16, SQLite, Server Actions, Tailwind CSS 4',
47
+ },
48
+ express: {
49
+ name: 'Express',
50
+ fullName: 'Express.js',
51
+ icon: '🚀',
52
+ type: 'backend',
53
+ version: 'v4.18',
54
+ port: 5000,
55
+ description: 'Minimalist, unopinionated, Auto-migration',
56
+ technologies: 'Express 4.18, Prisma 6, JWT, bcrypt, express-validator',
57
+ database: 'PostgreSQL',
58
+ databaseIcon: '🐘',
59
+ orm: 'Prisma',
60
+ },
61
+ nestjs: {
62
+ name: 'NestJS',
63
+ fullName: 'NestJS',
64
+ icon: '🐱',
65
+ type: 'backend',
66
+ version: 'v11',
67
+ port: 5000,
68
+ description: 'Modular architecture, Passport.js',
69
+ technologies: 'NestJS 11, Prisma 6.2, Passport.js, JWT, class-validator',
70
+ database: 'PostgreSQL',
71
+ databaseIcon: '🐘',
72
+ orm: 'Prisma',
73
+ },
74
+ fastify: {
75
+ name: 'Fastify',
76
+ fullName: 'Fastify',
77
+ icon: '⚡',
78
+ type: 'backend',
79
+ version: 'v5',
80
+ port: 5000,
81
+ description: 'High-performance, low overhead',
82
+ technologies: 'Fastify 5, Prisma, JWT, Swagger, TypeScript',
83
+ database: 'PostgreSQL',
84
+ databaseIcon: '🐘',
85
+ orm: 'Prisma',
86
+ },
87
+ };
88
+ // --- Lists ----------------------------------------------------------------
89
+ export const ALL_TEMPLATE_KEYS = Object.keys(templateData);
90
+ export const FRONTEND_KEYS = Object.entries(templateData)
91
+ .filter(([, t]) => t.type === 'frontend')
92
+ .map(([key]) => key);
93
+ export const BACKEND_KEYS = Object.entries(templateData)
94
+ .filter(([, t]) => t.type === 'backend')
95
+ .map(([key]) => key);
96
+ // --- Database Options -----------------------------------------------------
97
+ export const databaseOptions = [
98
+ { id: 'postgresql', name: 'PostgreSQL', icon: '🐘', description: 'Relational SQL database', defaultOrm: 'Prisma' },
99
+ { id: 'mysql', name: 'MySQL', icon: '🐬', description: 'Popular open-source RDBMS', defaultOrm: 'Prisma' },
100
+ { id: 'mariadb', name: 'MariaDB', icon: '🪶', description: 'MySQL-compatible fork', defaultOrm: 'Prisma' },
101
+ { id: 'sqlserver', name: 'SQL Server', icon: '🟦', description: 'Microsoft enterprise database', defaultOrm: 'Prisma' },
102
+ { id: 'sqlite', name: 'SQLite', icon: '📁', description: 'Embedded file-based database', defaultOrm: 'Prisma' },
103
+ { id: 'cockroachdb', name: 'CockroachDB', icon: '🪳', description: 'Cloud-native distributed SQL', defaultOrm: 'Prisma' },
104
+ { id: 'mongodb', name: 'MongoDB', icon: '🍃', description: 'NoSQL document database', defaultOrm: 'Prisma' },
105
+ ];
106
+ // --- Provider Map ---------------------------------------------------------
107
+ // Maps user-facing database IDs to Prisma provider strings.
108
+ // Ported from zero-config/Backend/src/app.service.ts
109
+ export const PROVIDER_MAP = {
110
+ postgresql: 'postgresql',
111
+ mysql: 'mysql',
112
+ mariadb: 'mysql',
113
+ sqlserver: 'sqlserver',
114
+ sqlite: 'sqlite',
115
+ cockroachdb: 'cockroachdb',
116
+ mongodb: 'mongodb',
117
+ };
118
+ // --- Allowed Template Whitelist -------------------------------------------
119
+ // Ported from zero-config/Backend/src/app.service.ts
120
+ export const ALLOWED_TEMPLATES = new Set(ALL_TEMPLATE_KEYS);
121
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type SourceType = 'local' | 'url';
2
+ export interface ResolvedSource {
3
+ type: SourceType;
4
+ path: string;
5
+ }
6
+ /**
7
+ * Resolve where templates live:
8
+ * 1. If `TEMPLATES_PATH` env var is set, use it (local path or URL)
9
+ * 2. Auto-detect sibling `zero-config-templates/` folder relative to CWD
10
+ * 3. Fall back to the GitHub zip URL
11
+ *
12
+ * Ported from the backend's `resolveTemplateSource()`.
13
+ */
14
+ export declare function resolveTemplateSource(templatesPath?: string): ResolvedSource;
15
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,cAAc,CA4B5E"}
@@ -0,0 +1,40 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Template source resolver
3
+ // Ported from zero-config/Backend/src/app.service.ts — resolveTemplateSource()
4
+ // ---------------------------------------------------------------------------
5
+ import * as fs from 'node:fs';
6
+ import * as path from 'node:path';
7
+ /**
8
+ * Resolve where templates live:
9
+ * 1. If `TEMPLATES_PATH` env var is set, use it (local path or URL)
10
+ * 2. Auto-detect sibling `zero-config-templates/` folder relative to CWD
11
+ * 3. Fall back to the GitHub zip URL
12
+ *
13
+ * Ported from the backend's `resolveTemplateSource()`.
14
+ */
15
+ export function resolveTemplateSource(templatesPath) {
16
+ const envPath = templatesPath || process.env.ZERO_CONFIG_TEMPLATES_PATH || '';
17
+ if (envPath) {
18
+ return {
19
+ type: envPath.startsWith('http://') || envPath.startsWith('https://') ? 'url' : 'local',
20
+ path: envPath,
21
+ };
22
+ }
23
+ // Auto-detect: check CWD, then parent, then grandparent
24
+ const candidates = [
25
+ path.resolve(process.cwd(), 'zero-config-templates'),
26
+ path.resolve(process.cwd(), '..', 'zero-config-templates'),
27
+ path.resolve(process.cwd(), '..', '..', 'zero-config-templates'),
28
+ ];
29
+ for (const candidate of candidates) {
30
+ if (fs.existsSync(candidate)) {
31
+ return { type: 'local', path: candidate };
32
+ }
33
+ }
34
+ // Fallback — GitHub default branch zip
35
+ return {
36
+ type: 'url',
37
+ path: 'https://github.com/dhuruvandb/zero-config-templates/archive/refs/heads/main.zip',
38
+ };
39
+ }
40
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2BAA2B;AAC3B,+EAA+E;AAC/E,8EAA8E;AAE9E,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AASlC;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,aAAsB;IACxD,MAAM,OAAO,GAAG,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC;IAE9E,IAAI,OAAO,EAAE,CAAC;QACV,OAAO;YACH,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;YACvF,IAAI,EAAE,OAAO;SAChB,CAAC;IACN,CAAC;IAED,wDAAwD;IACxD,MAAM,UAAU,GAAG;QACf,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAuB,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,uBAAuB,CAAC;QAC1D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,CAAC;KACnE,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACjC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC9C,CAAC;IACL,CAAC;IAED,uCAAuC;IACvC,OAAO;QACH,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,iFAAiF;KAC1F,CAAC;AACN,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** A single file extracted or read from a template. */
2
+ export interface TemplateFile {
3
+ /** Relative path within the template (e.g. "package.json") */
4
+ path: string;
5
+ /** Raw file content */
6
+ content: Buffer;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,uDAAuD;AACvD,MAAM,WAAW,YAAY;IACzB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shared types for template file handling
3
+ // Ported from zero-config/Backend/src/app.service.ts (TemplateFile interface)
4
+ // ---------------------------------------------------------------------------
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0CAA0C;AAC1C,8EAA8E;AAC9E,8EAA8E"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "zero-config-cli",
3
+ "version": "1.0.0",
4
+ "description": "Generate production-ready full-stack projects from the terminal — zero config required.",
5
+ "type": "module",
6
+ "bin": "dist/index.js",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "engines": {
11
+ "node": ">=18"
12
+ },
13
+ "scripts": {
14
+ "dev": "tsx src/index.ts",
15
+ "build": "tsc",
16
+ "start": "node dist/index.js",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "keywords": [
27
+ "zero-config",
28
+ "starter",
29
+ "generator",
30
+ "full-stack",
31
+ "react",
32
+ "angular",
33
+ "vue",
34
+ "nextjs",
35
+ "express",
36
+ "nestjs",
37
+ "fastify"
38
+ ],
39
+ "license": "MIT",
40
+ "dependencies": {
41
+ "@clack/prompts": "^0.10.1",
42
+ "commander": "^13.1.0",
43
+ "picocolors": "^1.1.1",
44
+ "unzipper": "^0.12.3"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.10.7",
48
+ "@types/unzipper": "^0.10.10",
49
+ "tsx": "^4.19.2",
50
+ "typescript": "^5.7.3",
51
+ "vitest": "^3.0.0"
52
+ }
53
+ }