create-lafkn 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.
Files changed (3) hide show
  1. package/README.md +85 -0
  2. package/dist/index.js +176 -0
  3. package/package.json +31 -0
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # 🌊 Lafkn
2
+
3
+ A modern serverless framework scaffolding tool for AWS CDK projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm create lafkn@latest
9
+ ```
10
+
11
+ Or use directly with npx:
12
+
13
+ ```bash
14
+ npx create-lafkn
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Simply run the command and follow the interactive prompts:
20
+
21
+ ```bash
22
+ npm create lafkn
23
+ ```
24
+
25
+ The CLI will guide you through:
26
+
27
+ 1. **Project name**: Choose a name for your project
28
+ 2. **Directory selection**: If your current directory matches the project name, you'll be asked if you want to use it
29
+ 3. **Service selection**: Choose which AWS services to include in your project
30
+ 4. **Dependency installation**: Optionally install dependencies with your preferred package manager
31
+
32
+ ## Available Services
33
+
34
+ Lafkn supports the following AWS services out of the box:
35
+
36
+ - **API Gateway** - RESTful API endpoints
37
+ - **Authentication** - User authentication and authorization
38
+ - **S3 Bucket** - Object storage
39
+ - **DynamoDB** - NoSQL database
40
+ - **EventBridge** - Event bus for event-driven architecture
41
+ - **SQS Queue** - Message queuing service
42
+ - **EventBridge Schedule** - Scheduled task execution
43
+ - **Step Functions** - State machine workflows
44
+
45
+ ## Project Structure
46
+
47
+ After scaffolding, your project will have the following structure:
48
+
49
+ ```
50
+ my-lafkn-app/
51
+ β”œβ”€β”€ src/
52
+ β”‚ └── index.ts
53
+ β”œβ”€β”€ package.json
54
+ β”œβ”€β”€ tsconfig.json
55
+ └── cdktf.json
56
+ ```
57
+
58
+ The `package.json` will include only the services you selected during setup.
59
+
60
+ ## Development
61
+
62
+ Once your project is created:
63
+
64
+ ```bash
65
+ cd my-lafkn-app
66
+ npm install # if you didn't install during setup
67
+ npm run build
68
+ npm run cdktf:synth
69
+ ```
70
+
71
+ ## Available Scripts
72
+
73
+ - `npm run build` - Compile TypeScript to JavaScript
74
+ - `npm run cdktf:deploy` - Build and deploy your infrastructure
75
+ - `npm run cdktf:destroy` - Destroy your infrastructure
76
+ - `npm run cdktf:synth` - Synthesize CloudFormation templates
77
+ - `npm run clean` - Clean build artifacts
78
+
79
+ ## Support
80
+
81
+ For issues and questions, please open an issue on GitHub.
82
+
83
+ ---
84
+
85
+ Built with ❀️ using [Eta](https://eta.js.org/) templates and [Inquirer](https://github.com/SBoudrias/Inquirer.js)
package/dist/index.js ADDED
@@ -0,0 +1,176 @@
1
+ #! /usr/bin/env node
2
+ import path from "node:path";
3
+ import fs from "node:fs/promises";
4
+ import { exec } from "node:child_process";
5
+ import { promisify } from "node:util";
6
+ import crypto from "node:crypto";
7
+ import { fileURLToPath } from "node:url";
8
+ import { input, checkbox, confirm, select } from "@inquirer/prompts";
9
+ import { Eta } from "eta";
10
+ const execPromise = promisify(exec);
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ const TEMPLATE_DIR = path.join(__dirname, "../template");
14
+ const processDirectory = async (src, dest, context) => {
15
+ await fs.mkdir(dest, { recursive: true });
16
+ const entries = await fs.readdir(src, { withFileTypes: true });
17
+ for (const entry of entries) {
18
+ const srcPath = path.join(src, entry.name);
19
+ const destPath = path.join(dest, entry.name);
20
+ if (entry.isDirectory()) {
21
+ await processDirectory(srcPath, destPath, context);
22
+ }
23
+ else {
24
+ if (entry.name.endsWith(".eta")) {
25
+ const content = await fs.readFile(srcPath, "utf-8");
26
+ const realDestPath = destPath.replace(/\.eta$/, "");
27
+ const eta = new Eta();
28
+ console.log(context);
29
+ const rendered = eta.renderString(content, context);
30
+ await fs.writeFile(realDestPath, rendered);
31
+ }
32
+ else {
33
+ await fs.copyFile(srcPath, destPath);
34
+ }
35
+ }
36
+ }
37
+ };
38
+ const checkDirectoryEmpty = async (dir) => {
39
+ try {
40
+ const files = await fs.readdir(dir);
41
+ return files.length === 0;
42
+ }
43
+ catch {
44
+ return true;
45
+ }
46
+ };
47
+ const main = async () => {
48
+ try {
49
+ console.log("🌊 Welcome to Lafkn 🌊");
50
+ const appName = await input({
51
+ message: "Project name:",
52
+ default: "my-lafkn-app",
53
+ validate: (value) => {
54
+ if (!value || value.trim().length === 0) {
55
+ return "Project name cannot be empty";
56
+ }
57
+ if (!/^[a-z0-9-_]+$/i.test(value)) {
58
+ return "Project name can only contain letters, numbers, hyphens and underscores";
59
+ }
60
+ return true;
61
+ },
62
+ });
63
+ const currentDirName = path.basename(process.cwd());
64
+ let useCurrentDir = false;
65
+ if (currentDirName === appName) {
66
+ useCurrentDir = await confirm({
67
+ message: `Current directory is already named "${appName}". Create project here?`,
68
+ default: true,
69
+ });
70
+ }
71
+ const targetDir = useCurrentDir
72
+ ? process.cwd()
73
+ : path.join(process.cwd(), appName);
74
+ let dirExists = false;
75
+ try {
76
+ await fs.access(targetDir);
77
+ dirExists = true;
78
+ }
79
+ catch {
80
+ dirExists = false;
81
+ }
82
+ if (!dirExists) {
83
+ console.log(`\nπŸ“ Creating directory: ${targetDir}`);
84
+ await fs.mkdir(targetDir, { recursive: true });
85
+ }
86
+ else {
87
+ const isEmpty = await checkDirectoryEmpty(targetDir);
88
+ if (!isEmpty) {
89
+ const overwrite = await confirm({
90
+ message: "⚠️ Directory is not empty. Continue anyway?",
91
+ default: false,
92
+ });
93
+ if (!overwrite) {
94
+ console.log("\n❌ Project creation cancelled");
95
+ process.exit(0);
96
+ }
97
+ }
98
+ }
99
+ const services = await checkbox({
100
+ message: "Select services to include:",
101
+ choices: [
102
+ { name: "API Gateway", value: "api" },
103
+ { name: "Cognito Authentication", value: "auth" },
104
+ { name: "S3 Bucket", value: "bucket" },
105
+ { name: "DynamoDB", value: "dynamo" },
106
+ { name: "EventBridge Events", value: "event" },
107
+ { name: "SQS Queue", value: "queue" },
108
+ { name: "EventBridge Schedule", value: "schedule" },
109
+ { name: "Step Functions", value: "state-machine" },
110
+ ],
111
+ });
112
+ const shouldInstall = await confirm({
113
+ message: "Install dependencies?",
114
+ default: true,
115
+ });
116
+ let packageManager = "npm";
117
+ if (shouldInstall) {
118
+ packageManager = await select({
119
+ message: "Select package manager:",
120
+ choices: [
121
+ { name: "npm", value: "npm" },
122
+ { name: "yarn", value: "yarn" },
123
+ { name: "pnpm", value: "pnpm" },
124
+ ],
125
+ default: "npm",
126
+ });
127
+ }
128
+ console.log(`\nπŸš€ Creating project in ${targetDir}...`);
129
+ try {
130
+ await fs.access(TEMPLATE_DIR);
131
+ }
132
+ catch {
133
+ console.error(`❌ Template directory not found at ${TEMPLATE_DIR}`);
134
+ process.exit(1);
135
+ }
136
+ const uuid = crypto.randomUUID();
137
+ await processDirectory(TEMPLATE_DIR, targetDir, {
138
+ appName,
139
+ services,
140
+ uuid,
141
+ });
142
+ console.log("βœ… Project created successfully!");
143
+ if (shouldInstall) {
144
+ console.log(`\nπŸ“¦ Installing dependencies with ${packageManager}...`);
145
+ const installCommand = packageManager === "yarn"
146
+ ? "yarn install"
147
+ : `${packageManager} install`;
148
+ try {
149
+ await execPromise(installCommand, { cwd: targetDir });
150
+ console.log("βœ… Dependencies installed successfully!");
151
+ }
152
+ catch (error) {
153
+ console.error("❌ Failed to install dependencies:", error);
154
+ }
155
+ }
156
+ console.log("\nπŸŽ‰ All done! Happy coding with Lafkn!\n");
157
+ console.log("Next steps:");
158
+ if (!useCurrentDir) {
159
+ console.log(` cd ${appName}`);
160
+ }
161
+ if (!shouldInstall) {
162
+ console.log(` ${packageManager} install`);
163
+ }
164
+ console.log(` ${packageManager === "npm" ? "npm run" : packageManager} dev\n`);
165
+ }
166
+ catch (error) {
167
+ if (error instanceof Error && error.name === "ExitPromptError") {
168
+ console.log("\nπŸ‘‹ Project creation cancelled");
169
+ process.exit(0);
170
+ }
171
+ console.error("❌ An error occurred:", error);
172
+ process.exit(1);
173
+ }
174
+ };
175
+ main();
176
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "create-lafkn",
3
+ "version": "1.0.0",
4
+ "description": "Create a simple lafkn project",
5
+ "keywords": [
6
+ "aws",
7
+ "lafkn",
8
+ "serverless",
9
+ "cdk"
10
+ ],
11
+ "license": "ISC",
12
+ "author": "AnΓ­bal Jorquera<ajorquera.cornejo@gmail.com>",
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "bin": "./dist/index.js",
16
+ "files": [
17
+ "lib"
18
+ ],
19
+ "dependencies": {
20
+ "@inquirer/prompts": "8.1.0",
21
+ "eta": "4.5.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "25.0.3",
25
+ "typescript": "5.9.3"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "release": "pnpm run build && pnpm -r publish --access public --no-git-checks"
30
+ }
31
+ }