create-stb 1.0.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.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ export declare function checkNodeVersion(minMajor?: number): void;
3
+ export declare function createProjectDirectory(projectPath: string): void;
4
+ export declare function copyDir(src: string, dest: string): void;
5
+ export declare function updatePackageJson(projectPath: string, projectName: string): void;
6
+ export declare function updateServerlessYml(projectPath: string, projectName: string): void;
7
+ export declare function main(): Promise<void>;
8
+ declare const _default: {
9
+ checkNodeVersion: typeof checkNodeVersion;
10
+ createProjectDirectory: typeof createProjectDirectory;
11
+ copyDir: typeof copyDir;
12
+ updatePackageJson: typeof updatePackageJson;
13
+ main: typeof main;
14
+ };
15
+ export default _default;
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.checkNodeVersion = checkNodeVersion;
8
+ exports.createProjectDirectory = createProjectDirectory;
9
+ exports.copyDir = copyDir;
10
+ exports.updatePackageJson = updatePackageJson;
11
+ exports.updateServerlessYml = updateServerlessYml;
12
+ exports.main = main;
13
+ const path_1 = __importDefault(require("path"));
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const child_process_1 = require("child_process");
16
+ // Progress display helpers
17
+ function writeLine(msg) {
18
+ const width = process.stdout.columns || 80;
19
+ process.stdout.write(`\r${" ".repeat(width)}\r${msg}`);
20
+ }
21
+ function clearLine() {
22
+ const width = process.stdout.columns || 80;
23
+ process.stdout.write(`\r${" ".repeat(width)}\r`);
24
+ }
25
+ function step(label) {
26
+ writeLine(label + "...");
27
+ }
28
+ function doneStep() {
29
+ clearLine();
30
+ }
31
+ // Ensure required Node version
32
+ function checkNodeVersion(minMajor = 20) {
33
+ const [major] = process.version.replace("v", "").split(".");
34
+ if (Number(major) < minMajor)
35
+ throw new Error(`Node.js v${minMajor}+ required`);
36
+ }
37
+ // Create an empty directory (or error if not empty)
38
+ function createProjectDirectory(projectPath) {
39
+ if (fs_1.default.existsSync(projectPath)) {
40
+ if (fs_1.default.readdirSync(projectPath).length === 0)
41
+ return;
42
+ throw new Error(`Directory "${projectPath}" exists and is not empty.`);
43
+ }
44
+ fs_1.default.mkdirSync(projectPath, { recursive: true });
45
+ }
46
+ // Recursively copy everything, including dotfiles and subfolders
47
+ function copyDir(src, dest) {
48
+ if (!fs_1.default.existsSync(dest))
49
+ fs_1.default.mkdirSync(dest, { recursive: true });
50
+ for (const entry of fs_1.default.readdirSync(src, { withFileTypes: true })) {
51
+ const srcPath = path_1.default.join(src, entry.name);
52
+ const destPath = path_1.default.join(dest, entry.name);
53
+ if (entry.isDirectory()) {
54
+ copyDir(srcPath, destPath);
55
+ }
56
+ else {
57
+ fs_1.default.copyFileSync(srcPath, destPath);
58
+ }
59
+ }
60
+ }
61
+ // Only update basic project info in package.json
62
+ function updatePackageJson(projectPath, projectName) {
63
+ const file = path_1.default.join(projectPath, "package.json");
64
+ if (!fs_1.default.existsSync(file))
65
+ return;
66
+ const pkg = JSON.parse(fs_1.default.readFileSync(file, "utf8"));
67
+ pkg.name = projectName;
68
+ pkg.description = `${projectName} app description`;
69
+ fs_1.default.writeFileSync(file, JSON.stringify(pkg, null, 2));
70
+ }
71
+ function updateServerlessYml(projectPath, projectName) {
72
+ const serverlessPath = path_1.default.join(projectPath, "serverless.yml");
73
+ if (!fs_1.default.existsSync(serverlessPath))
74
+ return;
75
+ let content = fs_1.default.readFileSync(serverlessPath, "utf8");
76
+ content = content.replace(/^service:.*$/m, `service: ${projectName}`);
77
+ fs_1.default.writeFileSync(serverlessPath, content);
78
+ }
79
+ // Main CLI flow
80
+ async function main() {
81
+ const name = process.argv[2];
82
+ if (!name) {
83
+ console.error("Please provide a project name.");
84
+ process.exit(1);
85
+ }
86
+ const projectPath = path_1.default.resolve(process.cwd(), name);
87
+ const boilerplateSrc = path_1.default.resolve(__dirname, "..", "serverless");
88
+ step("Checking Node version");
89
+ checkNodeVersion();
90
+ doneStep();
91
+ step("Creating project directory");
92
+ createProjectDirectory(projectPath);
93
+ doneStep();
94
+ step("Copying boilerplate files");
95
+ copyDir(boilerplateSrc, projectPath);
96
+ doneStep();
97
+ step("Updating package.json");
98
+ updatePackageJson(projectPath, name);
99
+ doneStep();
100
+ step("Updating serverless.yml");
101
+ updateServerlessYml(projectPath, name);
102
+ doneStep();
103
+ step("Installing packages");
104
+ (0, child_process_1.execSync)("npm install --silent", { cwd: projectPath, stdio: "inherit" });
105
+ doneStep();
106
+ clearLine();
107
+ console.log(`\nInstallation complete\n\nNext steps:\n\n cd ${name}\n npm run offline\n`);
108
+ }
109
+ exports.default = {
110
+ checkNodeVersion,
111
+ createProjectDirectory,
112
+ copyDir,
113
+ updatePackageJson,
114
+ main,
115
+ };
116
+ if (require.main === module) {
117
+ main().catch((err) => {
118
+ clearLine();
119
+ console.error("Error:", err.message);
120
+ process.exit(1);
121
+ });
122
+ }
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "create-stb",
3
+ "version": "1.0.1",
4
+ "description": "A CLI to quickly scaffold a Serverless TypeScript Boilerplate project.",
5
+ "license": "ISC",
6
+ "readme": "README.md",
7
+ "engines": {
8
+ "node": ">=20.0.0",
9
+ "npm": ">=10.0.0"
10
+ },
11
+ "bin": {
12
+ "create-stb": "./dist/create-stb.js"
13
+ },
14
+ "files": [
15
+ "dist/create-stb.js",
16
+ "dist/create-stb.d.ts",
17
+ "README.md",
18
+ "LICENSE",
19
+ "package.json",
20
+ "serverless"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.json",
24
+ "format": "prettier --write .",
25
+ "test": "jest --roots ./bin"
26
+ },
27
+ "devDependencies": {
28
+ "@types/jest": "30.0.0",
29
+ "@types/node": "20.19.25",
30
+ "jest": "^30.2.0",
31
+ "prettier": "3.6.2",
32
+ "ts-jest": "29.4.5",
33
+ "typescript": "5.9.3"
34
+ },
35
+ "homepage": "https://github.com/SamNewhouse/create-stb",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/SamNewhouse/create-stb.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/SamNewhouse/create-stb/issues"
42
+ },
43
+ "author": {
44
+ "name": "Sam Newhouse",
45
+ "url": "https://github.com/SamNewhouse"
46
+ },
47
+ "funding": {
48
+ "type": "github",
49
+ "url": "https://github.com/sponsors/SamNewhouse"
50
+ },
51
+ "keywords": [
52
+ "create-stb",
53
+ "serverless",
54
+ "typescript",
55
+ "boilerplate",
56
+ "starter",
57
+ "scaffold",
58
+ "cli",
59
+ "template",
60
+ "starter-kit"
61
+ ]
62
+ }
@@ -0,0 +1,14 @@
1
+ # AWS credentials (dummy for local, ignored by DynamoDB Local)
2
+ AWS_ACCESS_KEY_ID=
3
+ AWS_SECRET_ACCESS_KEY=
4
+ AWS_REGION=eu-west-2
5
+ AWS_REGION_FALLBACK=eu-west-1
6
+
7
+ # DynamoDB Setup
8
+ DYNAMODB_ENDPOINT=http://localhost:8000
9
+
10
+ # If you use other secrets (JWT, third party APIs etc.), add those here too:
11
+ JWT_SECRET=
12
+
13
+ # Current environment/stage
14
+ STAGE=dev
@@ -0,0 +1,20 @@
1
+ # Ignore build output
2
+ .build
3
+ dist
4
+ coverage
5
+
6
+ # Node
7
+ node_modules
8
+
9
+ # Dependency lockfiles (if you don't want Prettier to format them)
10
+ package-lock.json
11
+ yarn.lock
12
+
13
+ # Serverless, system, IDE, or OS files
14
+ .serverless
15
+ .DS_Store
16
+ .env
17
+ *.log
18
+
19
+ # Lambdas' bundles (if any)
20
+ bundle-*.js
@@ -0,0 +1,6 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "printWidth": 100,
5
+ "trailingComma": "all"
6
+ }
@@ -0,0 +1,36 @@
1
+ # Serverless Typescript Boilerplate
2
+
3
+ Minimalist project template to jump start a Serverless application in TypeScript.
4
+
5
+ ## Keys features
6
+
7
+ The current Serverless Starter Kit adds a light layer on top of the Serverless framework with modern JavaScript tools:
8
+
9
+ - **TypeScript** Support.
10
+ - **Offline** mode
11
+ - Formatting with Prettier to enforce a consistent code style.
12
+
13
+ ## Services
14
+
15
+ Currently, the boilerplate is built and tested on AWS using the following services.
16
+
17
+ - AWS Lambda
18
+
19
+ ## Quick start
20
+
21
+ ```
22
+ npm install
23
+ npm run offline
24
+ ```
25
+
26
+ ### Deployment
27
+
28
+ Make sure you have AWS Cli configured
29
+
30
+ ```bash
31
+ npm run deploy
32
+ ```
33
+
34
+ ## Serverless plugins
35
+
36
+ - [serverless-offline](https://github.com/dherault/serverless-offline): run your services offline for e.g. testing
@@ -0,0 +1,36 @@
1
+ version: "3.8"
2
+ services:
3
+ dynamodb-local:
4
+ image: amazon/dynamodb-local
5
+ container_name: dynamodb-local
6
+ restart: unless-stopped
7
+ ports:
8
+ - "8000:8000"
9
+ command: "-jar DynamoDBLocal.jar -inMemory -sharedDb"
10
+ working_dir: /home/dynamodblocal
11
+ volumes:
12
+ - dynamodb_data:/home/dynamodblocal/data
13
+ environment:
14
+ - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-dummy}
15
+ - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-dummy}
16
+ - AWS_REGION=${AWS_REGION:-eu-west-2}
17
+ healthcheck:
18
+ test: ["CMD", "curl", "-f", "http://localhost:8000/"]
19
+ interval: 10s
20
+ timeout: 5s
21
+ retries: 5
22
+
23
+ dynamodb-admin:
24
+ image: aaronshaf/dynamodb-admin
25
+ ports:
26
+ - "8001:8001"
27
+ environment:
28
+ - DYNAMO_ENDPOINT=${DYNAMO_ENDPOINT:-http://dynamodb-local:8000}
29
+ - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-dummy}
30
+ - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-dummy}
31
+ - AWS_REGION=${AWS_REGION:-eu-west-2}
32
+ links:
33
+ - dynamodb-local
34
+
35
+ volumes:
36
+ dynamodb_data: