create-astra 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # create-astra
2
+
3
+ A CLI tool that scaffolds production-ready backend projects with everything wired up automatically. No more manually editing config files, no more copy-pasting boilerplate.
4
+
5
+ ```bash
6
+ npx create-astra
7
+ ```
8
+
9
+ ---
10
+
11
+ ## The problem
12
+
13
+ Every time you start a backend project you repeat the same steps. Install dependencies, write a tsconfig, connect Prisma to a database adapter, write a docker-compose, set up a CI pipeline. It works but it's tedious and easy to get wrong.
14
+
15
+ create-astra does all of that in one command.
16
+
17
+ ---
18
+
19
+ ## What it sets up
20
+
21
+ Depending on your selections, create-astra generates a fully wired project with:
22
+
23
+ - Express app with a working entry point
24
+ - TypeScript configured correctly for Node.js
25
+ - Prisma with schema, config, adapter, and generated client
26
+ - Docker Compose with a postgres service wired to your env vars
27
+ - GitHub Actions CI pipeline that matches your stack
28
+ - `.env` and `.env.example` with all required variables
29
+ - `.gitignore` with sensible defaults
30
+ - `package.json` with all scripts ready to use
31
+
32
+ ---
33
+
34
+ ## Usage
35
+
36
+ ```bash
37
+ npx create-astra
38
+ ```
39
+
40
+ Follow the interactive prompts:
41
+
42
+ ```
43
+ What is your project name? my-app
44
+ Select a language: Node.js
45
+ Select a framework: Express (TypeScript)
46
+ Select extra features: Prisma, Docker, CI/CD
47
+ ```
48
+
49
+ Then:
50
+
51
+ ```bash
52
+ cd my-app
53
+ npm run dev
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Generated scripts
59
+
60
+ | Script | What it does |
61
+ |---|---|
62
+ | `npm run dev` | starts the dev server |
63
+ | `npm run build` | compiles TypeScript |
64
+ | `npm run start` | runs the compiled app |
65
+ | `npm run db:generate` | generates the Prisma client |
66
+ | `npm run db:migrate` | runs database migrations |
67
+ | `npm run db:studio` | opens Prisma Studio |
68
+
69
+ ---
70
+
71
+ ## After setup
72
+
73
+ If you selected Prisma, you need to:
74
+
75
+ 1. Set up a postgres database
76
+ 2. Update `DATABASE_URL` in your `.env` with real credentials
77
+ 3. Run `npm run db:migrate` to create your tables
78
+
79
+ The Prisma client is already generated during setup so TypeScript types resolve immediately.
80
+
81
+ ---
82
+
83
+ ## Supported stacks
84
+
85
+ | Language | Framework | Status |
86
+ |---|---|---|
87
+ | Node.js | Express (JavaScript) | available |
88
+ | Node.js | Express (TypeScript) | available |
89
+
90
+
91
+ Want to add support for a new language or framework? See [CONTRIBUTING.md](./CONTRIBUTING.md).
92
+
93
+ ---
94
+
95
+ ## Supported plugins
96
+
97
+ | Plugin | What it adds |
98
+ |---|---|
99
+ | Prisma | schema, config, adapter, client, db scripts |
100
+ | Docker | Dockerfile, docker-compose, .dockerignore |
101
+ | CI/CD | GitHub Actions pipeline |
102
+
103
+ Want to add a new plugin? See [CONTRIBUTING.md](./CONTRIBUTING.md).
104
+
105
+ ---
106
+
107
+ ## Local development
108
+
109
+ ```bash
110
+ git clone https://github.com/your-username/create-astra
111
+ cd create-astra
112
+ npm install
113
+ npm run dev
114
+ ```
115
+
116
+ ---
117
+
118
+ ## License
119
+
120
+ MIT
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.generateProject = generateProject;
40
+ const clack = __importStar(require("@clack/prompts"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const execa_1 = require("execa");
43
+ const promises_1 = __importDefault(require("fs/promises"));
44
+ const base_1 = require("./plugins/base");
45
+ const prisma_1 = require("./plugins/prisma");
46
+ const docker_1 = require("./plugins/docker");
47
+ const ci_1 = require("./plugins/ci");
48
+ const files_1 = require("./utils/files");
49
+ const packages_1 = require("./utils/packages");
50
+ const env_1 = require("./utils/env");
51
+ async function generateProject(options) {
52
+ if (options.language === 'node') {
53
+ await generateNodeProject(options);
54
+ }
55
+ else {
56
+ clack.outro('This language is coming soon. Want to contribute? github.com/you/create-astra');
57
+ process.exit(0);
58
+ }
59
+ }
60
+ async function generateNodeProject(options) {
61
+ const { projectName, extras } = options;
62
+ const projectPath = path_1.default.join(process.cwd(), projectName);
63
+ const spinner = clack.spinner();
64
+ const plugins = [
65
+ ...(options.language === 'node' ? [(0, base_1.createBasePlugin)(options)] : []),
66
+ ...(extras.includes('prisma') ? [(0, prisma_1.createPrismaPlugin)(options)] : []),
67
+ ...(extras.includes('docker') ? [(0, docker_1.createDockerPlugin)(options)] : []),
68
+ ...(extras.includes('ci') ? [(0, ci_1.createCiPlugin)(options)] : []),
69
+ ];
70
+ const dependencies = plugins.flatMap(p => p.dependencies);
71
+ const devDependencies = plugins.flatMap(p => p.devDependencies);
72
+ const envVars = plugins.reduce((acc, p) => ({ ...acc, ...p.envVars }), {});
73
+ const packageScripts = plugins.reduce((acc, p) => ({ ...acc, ...p.packageScripts }), {});
74
+ const files = plugins.flatMap(p => p.files);
75
+ spinner.start('Initialising project...');
76
+ try {
77
+ await (0, files_1.createFolder)(projectPath);
78
+ await (0, execa_1.execa)('npm', ['init', '-y'], { cwd: projectPath });
79
+ spinner.stop('Project initialised!');
80
+ }
81
+ catch (err) {
82
+ spinner.stop('Failed.');
83
+ clack.log.error('Could not initialise project.');
84
+ console.error(err);
85
+ process.exit(1);
86
+ }
87
+ spinner.start('Creating files...');
88
+ try {
89
+ for (const file of files) {
90
+ await (0, files_1.createFile)(file.path, file.content);
91
+ }
92
+ await writeGitignore(projectPath);
93
+ spinner.stop('Files created!');
94
+ }
95
+ catch (err) {
96
+ spinner.stop('Failed.');
97
+ clack.log.error('Could not create files.');
98
+ console.error(err);
99
+ process.exit(1);
100
+ }
101
+ spinner.start('Writing environment variables...');
102
+ try {
103
+ await (0, env_1.writeEnvFile)(projectPath, envVars);
104
+ spinner.stop('Environment variables written!');
105
+ }
106
+ catch (err) {
107
+ spinner.stop('Failed.');
108
+ clack.log.error('Could not write env files.');
109
+ console.error(err);
110
+ process.exit(1);
111
+ }
112
+ spinner.start('Installing dependencies...');
113
+ try {
114
+ await (0, packages_1.installPackages)(dependencies, projectPath);
115
+ await (0, packages_1.installPackages)(devDependencies, projectPath, true);
116
+ spinner.stop('Dependencies installed!');
117
+ }
118
+ catch (err) {
119
+ spinner.stop('Failed.');
120
+ clack.log.error('Could not install dependencies.');
121
+ process.exit(1);
122
+ }
123
+ spinner.start('Configuring package.json...');
124
+ try {
125
+ await patchPackageJson(projectPath, packageScripts);
126
+ spinner.stop('package.json configured!');
127
+ }
128
+ catch (err) {
129
+ spinner.stop('Failed.');
130
+ clack.log.error('Could not configure package.json.');
131
+ process.exit(1);
132
+ }
133
+ clack.outro(`Your project is ready! cd ${projectName} and npm run dev to start.`);
134
+ }
135
+ async function writeGitignore(projectPath) {
136
+ await (0, files_1.createFile)(path_1.default.join(projectPath, '.gitignore'), `node_modules\ndist\n.env\ngenerated\n`);
137
+ }
138
+ async function patchPackageJson(projectPath, scripts) {
139
+ const packageJsonPath = path_1.default.join(projectPath, 'package.json');
140
+ const raw = await promises_1.default.readFile(packageJsonPath, 'utf-8');
141
+ const packageJson = JSON.parse(raw);
142
+ packageJson.scripts = { ...packageJson.scripts, ...scripts };
143
+ await promises_1.default.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
144
+ }
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const prompts_1 = require("./prompts");
5
+ const generator_1 = require("./generator");
6
+ async function main() {
7
+ const options = await (0, prompts_1.getProjectOptions)();
8
+ await (0, generator_1.generateProject)(options);
9
+ }
10
+ main().catch(err => {
11
+ console.error(err);
12
+ process.exit(1);
13
+ });
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBasePlugin = void 0;
4
+ const createBasePlugin = (options) => {
5
+ const { projectName, useTypescript } = options;
6
+ const ext = useTypescript ? 'ts' : 'js';
7
+ const srcEntry = useTypescript ?
8
+ `import express from 'express'
9
+
10
+ const app = express()
11
+ const PORT = process.env.PORT || 3000
12
+
13
+ app.use(express.json())
14
+
15
+ app.get('/', (req,res) => {
16
+ res.json({message: 'Hello from ${projectName}'})
17
+ })
18
+
19
+ app.listen(PORT, () => {
20
+ console.log(\`Server running on port \${PORT}\`)
21
+ })
22
+ `
23
+ :
24
+ `const express = require('express')
25
+ const app = express()
26
+ const PORT = process.env.PORT || 3000
27
+
28
+ app.use(express.json())
29
+
30
+ app.get('/', (req, res) => {
31
+ res.json({ message: 'Hello from ${projectName}!' })
32
+ })
33
+
34
+ app.listen(PORT, () => {
35
+ console.log(\`Server running on port \${PORT}\`)
36
+ })
37
+ `;
38
+ return {
39
+ name: 'base',
40
+ dependencies: ['express'],
41
+ devDependencies: useTypescript
42
+ ? ['typescript', 'ts-node', '@types/node', '@types/express']
43
+ : [],
44
+ files: [
45
+ {
46
+ path: `${projectName}/src/index.${ext}`,
47
+ content: srcEntry
48
+ },
49
+ ...(useTypescript ? [{
50
+ path: `${projectName}/tsconfig.json`,
51
+ content: JSON.stringify({
52
+ compilerOptions: {
53
+ target: 'es2020',
54
+ module: 'commonjs',
55
+ rootDir: 'src',
56
+ outDir: 'dist',
57
+ strict: true,
58
+ esModuleInterop: true,
59
+ types: ['node']
60
+ },
61
+ include: ['src/**/*']
62
+ }, null, 2)
63
+ }] : []),
64
+ ],
65
+ envVars: {
66
+ PORT: '3000',
67
+ NODE_ENV: 'development',
68
+ },
69
+ packageScripts: useTypescript ? {
70
+ dev: 'ts-node src/index.ts',
71
+ build: 'tsc',
72
+ start: 'node dist/index.js',
73
+ } : {
74
+ dev: 'node src/index.js',
75
+ start: 'node src/index.js',
76
+ }
77
+ };
78
+ };
79
+ exports.createBasePlugin = createBasePlugin;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCiPlugin = createCiPlugin;
4
+ function createCiPlugin(options) {
5
+ const { projectName, useTypescript, extras } = options;
6
+ const hasPrisma = extras.includes('prisma');
7
+ const ciContent = `name: CI
8
+
9
+ on:
10
+ push:
11
+ branches: [main]
12
+ pull_request:
13
+ branches: [main]
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-latest
18
+
19
+ ${hasPrisma ? `services:
20
+ postgres:
21
+ image: postgres:15
22
+ env:
23
+ POSTGRES_USER: user
24
+ POSTGRES_PASSWORD: password
25
+ POSTGRES_DB: mydb
26
+ ports:
27
+ - 5432:5432
28
+ options: >-
29
+ --health-cmd pg_isready
30
+ --health-interval 10s
31
+ --health-timeout 5s
32
+ --health-retries 5` : ''}
33
+
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+
37
+ - name: Setup Node.js
38
+ uses: actions/setup-node@v4
39
+ with:
40
+ node-version: 20
41
+ cache: 'npm'
42
+
43
+ - name: Install dependencies
44
+ run: npm install
45
+
46
+ ${hasPrisma ? `- name: Generate Prisma client
47
+ run: npm run db:generate
48
+ env:
49
+ DATABASE_URL: postgresql://user:password@localhost:5432/mydb` : ''}
50
+
51
+ ${useTypescript ? `- name: Build
52
+ run: npm run build` : ''}
53
+ `;
54
+ return {
55
+ name: 'ci',
56
+ dependencies: [],
57
+ devDependencies: [],
58
+ files: [
59
+ {
60
+ path: `${projectName}/.github/workflows/ci.yml`,
61
+ content: ciContent,
62
+ },
63
+ ],
64
+ envVars: {},
65
+ packageScripts: {},
66
+ };
67
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDockerPlugin = createDockerPlugin;
4
+ function createDockerPlugin(options) {
5
+ const { projectName, extras } = options;
6
+ const hasPrisma = extras.includes('prisma');
7
+ const dockerComposeContent = `services:
8
+ app:
9
+ build: .
10
+ ports:
11
+ - "\${PORT}:3000"
12
+ env_file:
13
+ - .env
14
+ depends_on:
15
+ ${hasPrisma ? '- postgres' : ''}
16
+
17
+ ${hasPrisma ? ` postgres:
18
+ image: postgres:15
19
+ restart: always
20
+ environment:
21
+ POSTGRES_USER: user
22
+ POSTGRES_PASSWORD: password
23
+ POSTGRES_DB: mydb
24
+ ports:
25
+ - "5432:5432"
26
+ volumes:
27
+ - postgres_data:/var/lib/postgresql/data` : ''}
28
+
29
+ ${hasPrisma ? `volumes:
30
+ postgres_data:` : ''}
31
+ `;
32
+ const dockerfileContent = `FROM node:20-alpine
33
+
34
+ WORKDIR /app
35
+
36
+ COPY package*.json ./
37
+ RUN npm install
38
+
39
+ COPY . .
40
+
41
+ ${options.useTypescript ? 'RUN npm run build\nCMD ["node", "dist/index.js"]' : 'CMD ["node", "src/index.js"]'}
42
+ `;
43
+ const dockerignoreContent = `node_modules
44
+ dist
45
+ .env
46
+ generated
47
+ `;
48
+ return {
49
+ name: 'docker',
50
+ dependencies: [],
51
+ devDependencies: [],
52
+ files: [
53
+ {
54
+ path: `${projectName}/docker-compose.yml`,
55
+ content: dockerComposeContent,
56
+ },
57
+ {
58
+ path: `${projectName}/Dockerfile`,
59
+ content: dockerfileContent,
60
+ },
61
+ {
62
+ path: `${projectName}/.dockerignore`,
63
+ content: dockerignoreContent,
64
+ },
65
+ ],
66
+ envVars: {},
67
+ packageScripts: {},
68
+ };
69
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPrismaPlugin = void 0;
4
+ const createPrismaPlugin = (options) => {
5
+ const { projectName, useTypescript } = options;
6
+ const prismaConfig = `prisma.config.ts`;
7
+ const schemaContent = `generator client {
8
+ provider = "prisma-client"
9
+ output = "../generated/prisma"
10
+ }
11
+
12
+ datasource db {
13
+ provider = "postgresql"
14
+ }`;
15
+ const prismaConfigContent = `import path from 'path'
16
+ import { defineConfig } from 'prisma/config'
17
+
18
+ export default defineConfig({
19
+ earlyAccess: true,
20
+ schema: path.join('prisma', 'schema.prisma'),
21
+ migrate: {
22
+ async adapter() {
23
+ const { PrismaPg } = await import('@prisma/adapter-pg')
24
+ return new PrismaPg({ connectionString: process.env.DATABASE_URL })
25
+ }
26
+ }
27
+ })`;
28
+ const prismaClientContent = useTypescript
29
+ ? `import { PrismaClient } from '../../generated/prisma'
30
+ import { PrismaPg } from '@prisma/adapter-pg'
31
+
32
+ const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! })
33
+ const prisma = new PrismaClient({ adapter })
34
+
35
+ export default prisma`
36
+ : `const { PrismaClient } = require('../../generated/prisma')
37
+ const { PrismaPg } = require('@prisma/adapter-pg')
38
+
39
+ const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL })
40
+ const prisma = new PrismaClient({ adapter })
41
+
42
+ module.exports = prisma`;
43
+ return {
44
+ name: 'prisma',
45
+ dependencies: ['@prisma/client', '@prisma/adapter-pg', 'pg'],
46
+ devDependencies: ['prisma'],
47
+ files: [
48
+ {
49
+ path: `${projectName}/prisma/schema.prisma`,
50
+ content: schemaContent
51
+ },
52
+ {
53
+ path: `${projectName}/${prismaConfig}`,
54
+ content: prismaConfigContent
55
+ },
56
+ {
57
+ path: `${projectName}/src/lib/prisma.${useTypescript ? 'ts' : 'js'}`,
58
+ content: prismaClientContent
59
+ }
60
+ ],
61
+ envVars: {
62
+ DATABASE_URL: 'postgresql://user:password@localhost:5432/mydb'
63
+ },
64
+ packageScripts: {
65
+ 'db:generate': 'prisma generate',
66
+ 'db:migrate': 'prisma migrate dev',
67
+ 'db:studio': 'prisma studio'
68
+ }
69
+ };
70
+ };
71
+ exports.createPrismaPlugin = createPrismaPlugin;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getProjectOptions = void 0;
37
+ const clack = __importStar(require("@clack/prompts"));
38
+ const getProjectOptions = async () => {
39
+ clack.intro('Welcome to create-astra!');
40
+ const projectName = await clack.text({
41
+ message: 'What is your project name?',
42
+ placeholder: 'my-app',
43
+ validate(value) {
44
+ if (!value || value.trim() === '') {
45
+ return 'Project name cannot be empty.';
46
+ }
47
+ }
48
+ });
49
+ if (clack.isCancel(projectName)) {
50
+ clack.cancel('Operation cancelled.');
51
+ process.exit(0);
52
+ }
53
+ const language = await clack.select({
54
+ message: 'Select a language:',
55
+ options: [
56
+ { value: 'node', label: 'Js(node)' }
57
+ ]
58
+ });
59
+ if (clack.isCancel(language)) {
60
+ clack.cancel('Operation cancelled.');
61
+ process.exit(0);
62
+ }
63
+ const frameworkOptions = {
64
+ node: [
65
+ { value: 'express', label: 'Express (JavaScript)' },
66
+ { value: 'express-ts', label: 'Express (TypeScript)' },
67
+ ],
68
+ python: [
69
+ { value: 'fastapi', label: 'FastAPI' },
70
+ { value: 'flask', label: 'Flask' },
71
+ ],
72
+ go: [
73
+ { value: 'gin', label: 'Gin' },
74
+ { value: 'fiber', label: 'Fiber' },
75
+ ],
76
+ };
77
+ const framework = await clack.select({
78
+ message: 'Select a framework:',
79
+ options: frameworkOptions[language]
80
+ });
81
+ if (clack.isCancel(framework)) {
82
+ clack.cancel('Operation cancelled.');
83
+ process.exit(0);
84
+ }
85
+ const extras = await clack.multiselect({
86
+ message: 'Select extra features:',
87
+ options: [
88
+ { value: 'prisma', label: 'Prisma' },
89
+ { value: 'docker', label: 'Docker' },
90
+ { value: 'ci', label: 'CI/CD' },
91
+ ]
92
+ });
93
+ if (clack.isCancel(extras)) {
94
+ clack.cancel('Operation cancelled.');
95
+ process.exit(0);
96
+ }
97
+ return {
98
+ projectName: projectName,
99
+ language: language,
100
+ framework: framework,
101
+ extras: extras,
102
+ useTypescript: framework === 'express-ts'
103
+ };
104
+ };
105
+ exports.getProjectOptions = getProjectOptions;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.writeEnvFile = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const files_1 = require("./files");
9
+ const writeEnvFile = async (projectPath, vars) => {
10
+ const lines = Object.entries(vars)
11
+ .map(([key, value]) => `${key}=${value}`)
12
+ .join('\n');
13
+ await (0, files_1.createFile)(path_1.default.join(projectPath, '.env'), lines);
14
+ await (0, files_1.createFile)(path_1.default.join(projectPath, '.env.example'), Object.entries(vars)
15
+ .map(([key]) => `${key}=`)
16
+ .join('\n'));
17
+ };
18
+ exports.writeEnvFile = writeEnvFile;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createFolder = createFolder;
7
+ exports.createFile = createFile;
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const path_1 = __importDefault(require("path"));
10
+ async function createFolder(folderPath) {
11
+ await promises_1.default.mkdir(folderPath, { recursive: true });
12
+ }
13
+ async function createFile(filePath, content) {
14
+ const dir = path_1.default.dirname(filePath);
15
+ await promises_1.default.mkdir(dir, { recursive: true });
16
+ await promises_1.default.writeFile(filePath, content, 'utf-8');
17
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installPackages = void 0;
4
+ const execa_1 = require("execa");
5
+ const installPackages = async (packages, projectPath, dev = false) => {
6
+ if (packages.length === 0)
7
+ return;
8
+ const flag = dev ? ['--save-dev'] : [];
9
+ await (0, execa_1.execa)('npm', ['install', ...flag, ...packages], { cwd: projectPath });
10
+ };
11
+ exports.installPackages = installPackages;
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-astra",
3
+ "version": "0.1.1",
4
+ "description": "A CLI that scaffolds production-ready backend projects",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "create-astra": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "dev": "ts-node src/index.ts",
11
+ "build": "tsc",
12
+ "prepare": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "scaffold",
17
+ "express",
18
+ "prisma",
19
+ "typescript",
20
+ "backend"
21
+ ],
22
+ "author": "Njong Remy",
23
+ "license": "MIT",
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "type": "commonjs",
28
+ "dependencies": {
29
+ "@clack/prompts": "^1.6.0",
30
+ "execa": "^9.6.1"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^26.0.1",
34
+ "ts-node": "^10.9.2",
35
+ "typescript": "^6.0.3"
36
+ }
37
+ }