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.
- package/dist/create-stb.d.ts +15 -0
- package/dist/create-stb.js +122 -0
- package/package.json +62 -0
- package/serverless/.env.example +14 -0
- package/serverless/.prettierignore +20 -0
- package/serverless/.prettierrc +6 -0
- package/serverless/README.md +36 -0
- package/serverless/docker-compose.yml +36 -0
- package/serverless/package-lock.json +4839 -0
- package/serverless/package.json +39 -0
- package/serverless/serverless.yml +52 -0
- package/serverless/src/config/variables.ts +11 -0
- package/serverless/src/env.ts +6 -0
- package/serverless/src/functions/example.ts +24 -0
- package/serverless/src/handlers/example/get.ts +17 -0
- package/serverless/src/lib/dynamodb.ts +203 -0
- package/serverless/src/lib/http.ts +261 -0
- package/serverless/src/lib/seed.ts +57 -0
- package/serverless/src/scripts/create-tables.ts +67 -0
- package/serverless/src/scripts/seed-tables.ts +25 -0
- package/serverless/src/types/index.ts +7 -0
- package/serverless/src/utils/helpers.ts +4 -0
- package/serverless/tsconfig.json +19 -0
|
@@ -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,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:
|