@karmaniverous/smoz 0.1.2
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/LICENSE +28 -0
- package/README.md +66 -0
- package/dist/cjs/index.js +706 -0
- package/dist/cjs/serverless-plugin.js +43 -0
- package/dist/index.d.ts +422 -0
- package/dist/mjs/index.js +690 -0
- package/dist/mjs/serverless-plugin.js +41 -0
- package/dist/serverless-plugin.d.ts +6 -0
- package/package.json +190 -0
- package/templates/.check/eslint.minimal.config.ts +41 -0
- package/templates/.check/eslint.templates.config.ts +60 -0
- package/templates/.check/tsconfig.eslintconfig.json +6 -0
- package/templates/.check/tsconfig.minimal.json +14 -0
- package/templates/.manifests/package.minimal.json +19 -0
- package/templates/.manifests/package.project.json +23 -0
- package/templates/minimal/app/config/app.config.ts +50 -0
- package/templates/minimal/app/config/openapi.ts +45 -0
- package/templates/minimal/app/functions/rest/hello/get/handler.ts +18 -0
- package/templates/minimal/app/functions/rest/hello/get/lambda.ts +28 -0
- package/templates/minimal/app/functions/rest/hello/get/openapi.ts +23 -0
- package/templates/minimal/serverless.ts +34 -0
- package/templates/minimal/tsconfig.json +25 -0
- package/templates/minimal/types/registers.d.ts +11 -0
- package/templates/project/.prettierrc.json +3 -0
- package/templates/project/README.md +85 -0
- package/templates/project/eslint.config.ts +47 -0
- package/templates/project/tsconfig.base.json +21 -0
- package/templates/project/tsconfig.json +16 -0
- package/templates/project/typedoc.json +14 -0
- package/templates/project/vitest.config.ts +8 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/* REQUIREMENTS ADDRESSED
|
|
5
|
+
* - Provide a lightweight Serverless Framework plugin that ensures registers are fresh
|
|
6
|
+
* by running `smoz register` before package/deploy.
|
|
7
|
+
* - Keep it simple: spawn Node to run the packaged CJS CLI, inherit stdio, and fail fast.
|
|
8
|
+
*
|
|
9
|
+
* Notes:
|
|
10
|
+
* - This file is bundled to dist/cjs/serverless-plugin.js and exported via the "./serverless-plugin" subpath.
|
|
11
|
+
* - Serverless v4 loads CJS plugins via `require`; exporting a default class allows
|
|
12
|
+
* rollup to wrap it for CJS while preserving the ESM entry for completeness.
|
|
13
|
+
*/
|
|
14
|
+
const runRegister = () => {
|
|
15
|
+
// Resolve the packaged CLI entry relative to the compiled CJS plugin:
|
|
16
|
+
// dist/cjs/serverless-plugin.js -> ../cli/index.cjs
|
|
17
|
+
const cliPath = path.resolve(__dirname, '../cli/index.cjs');
|
|
18
|
+
const res = spawnSync(process.execPath, [cliPath, 'register'], {
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
shell: false,
|
|
21
|
+
});
|
|
22
|
+
const code = typeof res.status === 'number' ? String(res.status) : 'unknown';
|
|
23
|
+
if (res.status !== 0)
|
|
24
|
+
throw new Error(`smoz register failed (exit code ${code})`);
|
|
25
|
+
};
|
|
26
|
+
// Minimal Serverless v4 plugin: register hooks that run before package/deploy.
|
|
27
|
+
class SmozRegisterPlugin {
|
|
28
|
+
hooks;
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
constructor(_serverless, _options) {
|
|
31
|
+
this.hooks = {
|
|
32
|
+
// Package lifecycle
|
|
33
|
+
'before:package:initialize': runRegister,
|
|
34
|
+
// Deploy lifecycles where functions/artifacts can be (re)built
|
|
35
|
+
'before:deploy:function:initialize': runRegister,
|
|
36
|
+
'before:deploy:deploy': runRegister,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { SmozRegisterPlugin as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Jason Williscroft",
|
|
3
|
+
"auto-changelog": {
|
|
4
|
+
"output": "CHANGELOG.md",
|
|
5
|
+
"unreleased": true,
|
|
6
|
+
"commitLimit": false,
|
|
7
|
+
"hideCredit": true
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"smoz": "dist/cli/index.cjs"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/karmaniverous/smoz/issues"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@karmaniverous/cached-axios": "^0.2.0",
|
|
17
|
+
"@middy/core": "^6.4.5",
|
|
18
|
+
"@middy/http-content-negotiation": "^6.4.5",
|
|
19
|
+
"@middy/http-cors": "^6.4.5",
|
|
20
|
+
"@middy/http-error-handler": "^6.4.5",
|
|
21
|
+
"@middy/http-event-normalizer": "^6.4.5",
|
|
22
|
+
"@middy/http-header-normalizer": "^6.4.5",
|
|
23
|
+
"@middy/http-json-body-parser": "^6.4.5",
|
|
24
|
+
"@middy/http-response-serializer": "^6.4.5",
|
|
25
|
+
"aws-lambda": "^1.0.7",
|
|
26
|
+
"chokidar": "^4.0.3",
|
|
27
|
+
"commander": "^14.0.0",
|
|
28
|
+
"http-errors": "^2.0.0",
|
|
29
|
+
"package-directory": "^8.1.0",
|
|
30
|
+
"radash": "^12.1.1",
|
|
31
|
+
"zod": "^4.1.6"
|
|
32
|
+
},
|
|
33
|
+
"description": "John Galt Services back end.",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@dotenvx/dotenvx": "^1.49.0",
|
|
36
|
+
"@eslint/js": "^9.35.0",
|
|
37
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
38
|
+
"@serverless/typescript": "^4.18.2",
|
|
39
|
+
"@types/aws-lambda": "^8.10.152",
|
|
40
|
+
"@types/fs-extra": "^11.0.4",
|
|
41
|
+
"@types/http-errors": "^2.0.5",
|
|
42
|
+
"@types/serverless": "^3.12.27",
|
|
43
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
44
|
+
"auto-changelog": "^2.5.0",
|
|
45
|
+
"eslint": "^9.35.0",
|
|
46
|
+
"eslint-config-prettier": "^10.1.8",
|
|
47
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
48
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
49
|
+
"fs-extra": "^11.3.1",
|
|
50
|
+
"knip": "^5.63.1",
|
|
51
|
+
"lefthook": "^1.12.4",
|
|
52
|
+
"orval": "^7.11.2",
|
|
53
|
+
"pkg-dir": "^9.0.0",
|
|
54
|
+
"prettier": "^3.6.2",
|
|
55
|
+
"release-it": "^19.0.4",
|
|
56
|
+
"rimraf": "^6.0.1",
|
|
57
|
+
"rollup": "^4.50.1",
|
|
58
|
+
"rollup-plugin-dts": "^6.2.3",
|
|
59
|
+
"serverless": "^4.18.2",
|
|
60
|
+
"serverless-apigateway-log-retention": "^1.1.0",
|
|
61
|
+
"serverless-deployment-bucket": "^1.6.0",
|
|
62
|
+
"serverless-domain-manager": "^8.0.0",
|
|
63
|
+
"serverless-offline": "^14.4.0",
|
|
64
|
+
"serverless-plugin-common-excludes": "^4.0.0",
|
|
65
|
+
"tsx": "^4.20.5",
|
|
66
|
+
"typedoc": "^0.28.12",
|
|
67
|
+
"typedoc-plugin-mdn-links": "^5.0.9",
|
|
68
|
+
"typedoc-plugin-replace-text": "^4.2.0",
|
|
69
|
+
"typedoc-plugin-zod": "^1.4.2",
|
|
70
|
+
"typescript": "^5.9.2",
|
|
71
|
+
"typescript-eslint": "^8.43.0",
|
|
72
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
73
|
+
"vitest": "^3.2.4",
|
|
74
|
+
"zod-openapi": "^5.4.1"
|
|
75
|
+
},
|
|
76
|
+
"exports": {
|
|
77
|
+
".": {
|
|
78
|
+
"import": {
|
|
79
|
+
"types": "./dist/index.d.ts",
|
|
80
|
+
"default": "./dist/mjs/index.js"
|
|
81
|
+
},
|
|
82
|
+
"require": {
|
|
83
|
+
"types": "./dist/index.d.ts",
|
|
84
|
+
"default": "./dist/cjs/index.js"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"./serverless-plugin": {
|
|
88
|
+
"import": "./dist/mjs/serverless-plugin.js",
|
|
89
|
+
"require": "./dist/cjs/serverless-plugin.js"
|
|
90
|
+
},
|
|
91
|
+
"./package.json": "./package.json"
|
|
92
|
+
},
|
|
93
|
+
"files": [
|
|
94
|
+
"dist",
|
|
95
|
+
"templates"
|
|
96
|
+
],
|
|
97
|
+
"homepage": "https://github.com/karmaniverous/smoz#readme",
|
|
98
|
+
"keywords": [
|
|
99
|
+
"smoz",
|
|
100
|
+
"serverless",
|
|
101
|
+
"serverless-framework",
|
|
102
|
+
"aws-lambda",
|
|
103
|
+
"middy",
|
|
104
|
+
"openapi",
|
|
105
|
+
"openapi-3-1",
|
|
106
|
+
"zod",
|
|
107
|
+
"typescript",
|
|
108
|
+
"api-gateway",
|
|
109
|
+
"http-middleware",
|
|
110
|
+
"validation",
|
|
111
|
+
"schema-first",
|
|
112
|
+
"lambda-handlers",
|
|
113
|
+
"openapi-generator",
|
|
114
|
+
"api-docs",
|
|
115
|
+
"content-negotiation",
|
|
116
|
+
"cors",
|
|
117
|
+
"error-handling",
|
|
118
|
+
"toolkit"
|
|
119
|
+
],
|
|
120
|
+
"license": "BSD-3-Clause",
|
|
121
|
+
"main": "dist/cjs/index.js",
|
|
122
|
+
"module": "dist/mjs/index.js",
|
|
123
|
+
"name": "@karmaniverous/smoz",
|
|
124
|
+
"publishConfig": {
|
|
125
|
+
"access": "public"
|
|
126
|
+
},
|
|
127
|
+
"release-it": {
|
|
128
|
+
"git": {
|
|
129
|
+
"changelog": "npx auto-changelog --stdout --template https://raw.githubusercontent.com/release-it/release-it/main/templates/changelog-compact.hbs",
|
|
130
|
+
"commitMessage": "chore: release v${version}",
|
|
131
|
+
"requireBranch": "main"
|
|
132
|
+
},
|
|
133
|
+
"github": {
|
|
134
|
+
"release": true
|
|
135
|
+
},
|
|
136
|
+
"hooks": {
|
|
137
|
+
"after:init": [
|
|
138
|
+
"npm run lint",
|
|
139
|
+
"npm run test",
|
|
140
|
+
"npm run knip",
|
|
141
|
+
"npm run build"
|
|
142
|
+
],
|
|
143
|
+
"before:npm:release": [
|
|
144
|
+
"npx auto-changelog -p",
|
|
145
|
+
"npm run docs",
|
|
146
|
+
"git add -A"
|
|
147
|
+
],
|
|
148
|
+
"after:release": [
|
|
149
|
+
"git switch -c release/${version}",
|
|
150
|
+
"git push -u origin release/${version}",
|
|
151
|
+
"git switch ${branchName}"
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
"npm": {
|
|
155
|
+
"publish": true
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"repository": {
|
|
159
|
+
"type": "git",
|
|
160
|
+
"url": "git+https://github.com/karmaniverous/smoz.git"
|
|
161
|
+
},
|
|
162
|
+
"scripts": {
|
|
163
|
+
"build": "rimraf dist && rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
|
|
164
|
+
"build:cli": "rollup --config cli.rollup.config.ts --configPlugin @rollup/plugin-typescript",
|
|
165
|
+
"changelog": "auto-changelog",
|
|
166
|
+
"deploy": "tsx src/cli/index.ts register && serverless deploy",
|
|
167
|
+
"diagrams": "cd diagrams/src && plantuml -tpng -o ../out -r .",
|
|
168
|
+
"docs": "typedoc",
|
|
169
|
+
"domain:create": "serverless create_domain",
|
|
170
|
+
"domain:delete": "serverless delete_domain",
|
|
171
|
+
"generate": "cd services/activecampaign && orval",
|
|
172
|
+
"knip": "knip",
|
|
173
|
+
"lint": "eslint .",
|
|
174
|
+
"lint:fix": "eslint --fix .",
|
|
175
|
+
"openapi": "tsx src/cli/index.ts register && tsx app/config/openapi && prettier -w app/generated/openapi.json",
|
|
176
|
+
"package": "tsx src/cli/index.ts register && serverless package",
|
|
177
|
+
"release": "dotenvx run -f .env.local -- release-it",
|
|
178
|
+
"release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease",
|
|
179
|
+
"remove": "serverless remove",
|
|
180
|
+
"smoz": "tsx src/cli/index.ts",
|
|
181
|
+
"stan:build": "rimraf stan.dist && rollup --config stan.rollup.config.ts --configPlugin @rollup/plugin-typescript && rimraf stan.dist",
|
|
182
|
+
"stan:docs": "typedoc --emit none",
|
|
183
|
+
"test": "vitest run",
|
|
184
|
+
"typecheck": "tsx src/cli/index.ts register && tsc -p tsconfig.json --noEmit",
|
|
185
|
+
"templates:typecheck": "tsx scripts/templates-typecheck.ts",
|
|
186
|
+
"templates:lint": "eslint --fix -c templates/.check/eslint.templates.config.ts \"templates/**/*.{ts,tsx,js,jsx}\" && eslint --fix --no-ignore templates/.check/eslint.templates.config.ts"
|
|
187
|
+
},
|
|
188
|
+
"type": "module",
|
|
189
|
+
"version": "0.1.2"
|
|
190
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import prettierConfig from 'eslint-config-prettier';
|
|
3
|
+
import prettierPlugin from 'eslint-plugin-prettier';
|
|
4
|
+
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
import { dirname } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
export default tseslint.config(
|
|
12
|
+
{ ignores: [
|
|
13
|
+
'**/node_modules/**',
|
|
14
|
+
'**/dist/**',
|
|
15
|
+
'**/.tsbuild/**',
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
eslint.configs.recommended,
|
|
19
|
+
tseslint.configs.strictTypeChecked,
|
|
20
|
+
prettierConfig,
|
|
21
|
+
{
|
|
22
|
+
languageOptions: {
|
|
23
|
+
parser: tseslint.parser,
|
|
24
|
+
parserOptions: {
|
|
25
|
+
project: ['./tsconfig.minimal.json'],
|
|
26
|
+
tsconfigRootDir,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
plugins: { prettier: prettierPlugin,
|
|
30
|
+
'simple-import-sort': simpleImportSortPlugin,
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
'@typescript-eslint/consistent-type-imports': 'error',
|
|
34
|
+
'@typescript-eslint/no-unused-expressions': 'off',
|
|
35
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
36
|
+
'no-unused-vars': 'off',
|
|
37
|
+
'simple-import-sort/imports': 'error',
|
|
38
|
+
'simple-import-sort/exports': 'error',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import prettierConfig from 'eslint-config-prettier';
|
|
3
|
+
import prettierPlugin from 'eslint-plugin-prettier';
|
|
4
|
+
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
|
|
5
|
+
import { dirname } from 'path';
|
|
6
|
+
import tseslint from 'typescript-eslint';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
// Unified ESLint config for all templates under templates/*
|
|
10
|
+
// - Uses projectService so type info is picked up from each template's tsconfig.json
|
|
11
|
+
// - ESLint drives Prettier via 'prettier/prettier': 'error'
|
|
12
|
+
const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
export default [
|
|
15
|
+
{
|
|
16
|
+
ignores: [
|
|
17
|
+
'**/node_modules/**',
|
|
18
|
+
'**/dist/**',
|
|
19
|
+
'**/.tsbuild/**',
|
|
20
|
+
'**/generated/**',
|
|
21
|
+
'**/.check/**',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
eslint.configs.recommended,
|
|
25
|
+
...tseslint.configs.strictTypeChecked,
|
|
26
|
+
prettierConfig,
|
|
27
|
+
{
|
|
28
|
+
languageOptions: {
|
|
29
|
+
parser: tseslint.parser,
|
|
30
|
+
parserOptions: {
|
|
31
|
+
// Let the project service discover the nearest tsconfig.json per file
|
|
32
|
+
// (typed where possible; falls back to default project when unmatched).
|
|
33
|
+
project: true,
|
|
34
|
+
projectService: true,
|
|
35
|
+
allowDefaultProject: true,
|
|
36
|
+
tsconfigRootDir,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
plugins: {
|
|
40
|
+
prettier: prettierPlugin,
|
|
41
|
+
'simple-import-sort': simpleImportSortPlugin,
|
|
42
|
+
},
|
|
43
|
+
rules: {
|
|
44
|
+
// Formatting via Prettier
|
|
45
|
+
'prettier/prettier': 'error',
|
|
46
|
+
// Code-quality and sorting
|
|
47
|
+
'@typescript-eslint/consistent-type-imports': 'error',
|
|
48
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
49
|
+
'@typescript-eslint/no-unused-expressions': 'off',
|
|
50
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
51
|
+
'no-unused-vars': 'off',
|
|
52
|
+
'simple-import-sort/imports': 'error',
|
|
53
|
+
'simple-import-sort/exports': 'error',
|
|
54
|
+
// Keep strictness reasonable for templates
|
|
55
|
+
'@typescript-eslint/no-unsafe-assignment': 'error',
|
|
56
|
+
'@typescript-eslint/no-unsafe-member-access': 'error',
|
|
57
|
+
'@typescript-eslint/no-unsafe-return': 'error',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../project/tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "../../templates/minimal",
|
|
5
|
+
"baseUrl": "../../templates/minimal",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@/*": ["*"],
|
|
8
|
+
"@karmaniverous/smoz": ["../../.stan/dist/index.d.ts"]
|
|
9
|
+
},
|
|
10
|
+
"types": ["node"]
|
|
11
|
+
}, "include": [
|
|
12
|
+
"../../templates/minimal/**/*.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"zod": "^4.1.5",
|
|
4
|
+
"@middy/core": "^6.4.4"
|
|
5
|
+
},
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"typescript": "^5.9.2",
|
|
8
|
+
"typescript-eslint": "^8.41.0",
|
|
9
|
+
"eslint": "^9.34.0",
|
|
10
|
+
"eslint-config-prettier": "^10.1.8",
|
|
11
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
12
|
+
"eslint-plugin-simple-import-sort": "^12.1.1"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"lint:fix": "eslint --fix ."
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"zod": "^4.1.5",
|
|
4
|
+
"@middy/core": "^6.4.4"
|
|
5
|
+
},
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"typescript": "^5.9.2",
|
|
8
|
+
"typescript-eslint": "^8.41.0",
|
|
9
|
+
"eslint": "^9.34.0",
|
|
10
|
+
"eslint-config-prettier": "^10.1.8",
|
|
11
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
12
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
13
|
+
"vitest": "^3.2.4",
|
|
14
|
+
"typedoc": "^0.28.11"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"lint:fix": "eslint --fix .",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"docs": "typedoc"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { App, baseEventTypeMapSchema, toPosixPath } from '@karmaniverous/smoz';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
// Derive the app root as the parent directory of app/config/
|
|
8
|
+
export const APP_ROOT_ABS = toPosixPath(
|
|
9
|
+
fileURLToPath(new URL('..', import.meta.url)),
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export const app = App.create({
|
|
13
|
+
appRootAbs: APP_ROOT_ABS,
|
|
14
|
+
globalParamsSchema: z.object({
|
|
15
|
+
PROFILE: z.string(),
|
|
16
|
+
REGION: z.string(),
|
|
17
|
+
SERVICE_NAME: z.string(),
|
|
18
|
+
}),
|
|
19
|
+
stageParamsSchema: z.object({
|
|
20
|
+
STAGE: z.string(),
|
|
21
|
+
}),
|
|
22
|
+
eventTypeMapSchema: baseEventTypeMapSchema,
|
|
23
|
+
serverless: {
|
|
24
|
+
httpContextEventMap: {
|
|
25
|
+
my: {}, // place a Cognito authorizer here if needed
|
|
26
|
+
private: { private: true },
|
|
27
|
+
public: {},
|
|
28
|
+
},
|
|
29
|
+
defaultHandlerFileName: 'handler',
|
|
30
|
+
defaultHandlerFileExport: 'handler',
|
|
31
|
+
},
|
|
32
|
+
global: {
|
|
33
|
+
params: {
|
|
34
|
+
PROFILE: 'dev',
|
|
35
|
+
REGION: 'us-east-1',
|
|
36
|
+
SERVICE_NAME: 'my-smoz-app',
|
|
37
|
+
},
|
|
38
|
+
envKeys: ['PROFILE', 'REGION', 'SERVICE_NAME'] as const,
|
|
39
|
+
},
|
|
40
|
+
stage: {
|
|
41
|
+
params: {
|
|
42
|
+
dev: { STAGE: 'dev' },
|
|
43
|
+
},
|
|
44
|
+
envKeys: ['STAGE'] as const,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const ENDPOINTS_ROOT_REST = toPosixPath(
|
|
49
|
+
join(APP_ROOT_ABS, 'functions', 'rest'),
|
|
50
|
+
);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import { packageDirectorySync } from 'pkg-dir';
|
|
5
|
+
import { createDocument } from 'zod-openapi';
|
|
6
|
+
|
|
7
|
+
import { app } from '@/app/config/app.config';
|
|
8
|
+
/**
|
|
9
|
+
* Template note:
|
|
10
|
+
* - Templates do NOT commit generated register files under app/generated; they
|
|
11
|
+
* are declared via ambient types (templates/minimal/types/registers.d.ts) so
|
|
12
|
+
* TypeScript can typecheck without artifacts.
|
|
13
|
+
* - To ensure side effects still run (endpoint registration) and to satisfy
|
|
14
|
+
* noUncheckedSideEffectImports, import the register module as a namespace and
|
|
15
|
+
* reference it via `void`.
|
|
16
|
+
* - In real apps, `smoz init` seeds placeholders and `smoz register` rewrites
|
|
17
|
+
* app/generated/register.*.ts at author time.
|
|
18
|
+
*/
|
|
19
|
+
import * as __register_openapi from '@/app/generated/register.openapi';
|
|
20
|
+
void __register_openapi;
|
|
21
|
+
console.log('Generating OpenAPI document...');
|
|
22
|
+
|
|
23
|
+
const paths = app.buildAllOpenApiPaths();
|
|
24
|
+
export const doc = createDocument({
|
|
25
|
+
openapi: '3.1.0',
|
|
26
|
+
servers: [{ description: 'Dev', url: 'http://localhost' }],
|
|
27
|
+
info: {
|
|
28
|
+
title: process.env.npm_package_name ?? 'smoz-app',
|
|
29
|
+
version: process.env.npm_package_version ?? '0.0.0',
|
|
30
|
+
},
|
|
31
|
+
paths,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const pkgDir = packageDirectorySync();
|
|
35
|
+
if (!pkgDir) {
|
|
36
|
+
throw new Error('Could not resolve package root directory');
|
|
37
|
+
}
|
|
38
|
+
const outDir = path.join(pkgDir, 'app', 'generated');
|
|
39
|
+
fs.ensureDirSync(outDir);
|
|
40
|
+
fs.writeFileSync(
|
|
41
|
+
path.join(outDir, 'openapi.json'),
|
|
42
|
+
JSON.stringify(doc, null, 2),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
console.log('Done!');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import type { responseSchema } from './lambda';
|
|
4
|
+
import { fn } from './lambda';
|
|
5
|
+
|
|
6
|
+
type Response = z.infer<typeof responseSchema>;
|
|
7
|
+
|
|
8
|
+
type FnHandlerApi<T> = {
|
|
9
|
+
handler: (impl: () => Promise<T> | T) => (...args: unknown[]) => Promise<T>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const reg = fn as unknown as FnHandlerApi<Response>;
|
|
13
|
+
|
|
14
|
+
export const handler = reg.handler(async () => {
|
|
15
|
+
const res: Response = { ok: true };
|
|
16
|
+
await Promise.resolve(); // satisfy require-await without adding complexity
|
|
17
|
+
return res;
|
|
18
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { toPosixPath } from '@karmaniverous/smoz';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
import { app, APP_ROOT_ABS } from '@/app/config/app.config';
|
|
7
|
+
|
|
8
|
+
export const eventSchema = z.object({}).optional();
|
|
9
|
+
export const responseSchema = z.object({ ok: z.boolean() });
|
|
10
|
+
type FnApi = {
|
|
11
|
+
handler: <T>(
|
|
12
|
+
impl: () => Promise<T> | T,
|
|
13
|
+
) => (...args: unknown[]) => Promise<T>;
|
|
14
|
+
openapi: (op: unknown) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const fn = app.defineFunction({
|
|
18
|
+
functionName: 'hello_get',
|
|
19
|
+
eventType: 'rest',
|
|
20
|
+
httpContexts: ['public'],
|
|
21
|
+
method: 'get',
|
|
22
|
+
basePath: 'hello',
|
|
23
|
+
contentType: 'application/json',
|
|
24
|
+
eventSchema,
|
|
25
|
+
responseSchema,
|
|
26
|
+
callerModuleUrl: import.meta.url,
|
|
27
|
+
endpointsRootAbs: toPosixPath(join(APP_ROOT_ABS, 'functions', 'rest')),
|
|
28
|
+
}) as unknown as FnApi;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { fn, responseSchema } from './lambda';
|
|
2
|
+
|
|
3
|
+
type FnOpenApiApi = {
|
|
4
|
+
openapi: (op: unknown) => void;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const reg = fn as unknown as FnOpenApiApi;
|
|
8
|
+
|
|
9
|
+
reg.openapi({
|
|
10
|
+
summary: 'Hello',
|
|
11
|
+
description: 'Return a simple OK payload.',
|
|
12
|
+
responses: {
|
|
13
|
+
200: {
|
|
14
|
+
description: 'Ok',
|
|
15
|
+
content: {
|
|
16
|
+
'application/json': { schema: responseSchema },
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
tags: ['public'],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AWS } from '@serverless/typescript';
|
|
2
|
+
|
|
3
|
+
import { app } from '@/app/config/app.config';
|
|
4
|
+
/**
|
|
5
|
+
* Template note:
|
|
6
|
+
* - Templates do NOT commit generated register files under app/generated; they
|
|
7
|
+
* are declared via ambient types (templates/minimal/types/registers.d.ts) so
|
|
8
|
+
* TypeScript can typecheck without artifacts.
|
|
9
|
+
* - To ensure side effects still run (endpoint/serverless registration) and to
|
|
10
|
+
* satisfy noUncheckedSideEffectImports, import register modules as namespaces
|
|
11
|
+
* and reference them via `void`.
|
|
12
|
+
* - In real apps, `smoz init` seeds placeholders and `smoz register` rewrites
|
|
13
|
+
* app/generated/register.*.ts at author time.
|
|
14
|
+
*/
|
|
15
|
+
import * as __register_functions from '@/app/generated/register.functions';
|
|
16
|
+
import * as __register_serverless from '@/app/generated/register.serverless';
|
|
17
|
+
void __register_functions;
|
|
18
|
+
void __register_serverless;
|
|
19
|
+
|
|
20
|
+
const config: AWS = {
|
|
21
|
+
service: '${param:SERVICE_NAME}',
|
|
22
|
+
frameworkVersion: '4',
|
|
23
|
+
stages: app.stages as NonNullable<AWS['stages']>,
|
|
24
|
+
provider: {
|
|
25
|
+
name: 'aws',
|
|
26
|
+
region: '${param:REGION}' as NonNullable<AWS['provider']['region']>,
|
|
27
|
+
runtime: 'nodejs22.x',
|
|
28
|
+
environment: app.environment as NonNullable<AWS['provider']['environment']>,
|
|
29
|
+
stage: '${opt:stage, "dev"}',
|
|
30
|
+
},
|
|
31
|
+
functions: app.buildAllServerlessFunctions() as NonNullable<AWS['functions']>,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default config;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"rootDir": ".",
|
|
5
|
+
"outDir": ".tsbuild",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@/*": ["*"],
|
|
8
|
+
"@karmaniverous/smoz": ["../../.stan/dist/index.d.ts"]
|
|
9
|
+
},
|
|
10
|
+
"typeRoots": ["../../node_modules/@types", "./node_modules/@types"],
|
|
11
|
+
"tsBuildInfoFile": ".tsbuild/tsconfig.tsbuildinfo"
|
|
12
|
+
},
|
|
13
|
+
"exclude": [
|
|
14
|
+
".serverless/**",
|
|
15
|
+
"node_modules/**",
|
|
16
|
+
"app/generated/**",
|
|
17
|
+
"dist/**"
|
|
18
|
+
],
|
|
19
|
+
"extends": "../project/tsconfig.base.json",
|
|
20
|
+
"include": [
|
|
21
|
+
"**/*.ts",
|
|
22
|
+
"**/*.tsx",
|
|
23
|
+
"**/*.d.ts"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Ambient declarations to satisfy template typechecking without requiring
|
|
2
|
+
// generated register files to exist on disk.
|
|
3
|
+
declare module '@/app/generated/register.functions' {
|
|
4
|
+
export {};
|
|
5
|
+
}
|
|
6
|
+
declare module '@/app/generated/register.openapi' {
|
|
7
|
+
export {};
|
|
8
|
+
}
|
|
9
|
+
declare module '@/app/generated/register.serverless' {
|
|
10
|
+
export {};
|
|
11
|
+
}
|