@karmaniverous/smoz 0.1.6 → 0.1.8
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 +2 -11
- package/dist/cli/index.cjs +28 -2
- package/package.json +1 -1
- package/templates/.manifests/package.full.json +9 -8
- package/templates/.manifests/package.minimal.json +10 -7
- package/templates/.manifests/package.project.json +9 -8
- package/templates/project/.vscode/extensions.json +8 -0
- package/templates/project/.vscode/settings.json +23 -0
- package/templates/project/README.md +4 -13
- package/templates/project/gitignore +42 -0
- package/templates/project/test/smoke.test.ts +7 -0
- package/templates/project/tsdoc.json +46 -0
package/README.md
CHANGED
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
SMOZ is a small, pragmatic toolkit for authoring AWS Lambda handlers with
|
|
16
|
-
[Middy] and [Zod], then aggregating Serverless functions and hand‑crafted
|
|
17
|
-
OpenAPI 3.1 paths from a single, schema‑first application definition.
|
|
15
|
+
SMOZ is a small, pragmatic toolkit for authoring AWS Lambda handlers with [Middy] and [Zod], then aggregating Serverless functions and hand‑crafted OpenAPI 3.1 paths from a single, schema‑first application definition.
|
|
18
16
|
|
|
19
17
|
- Keep prod code testable and framework‑agnostic
|
|
20
18
|
- HTTP middleware with validation, shaping, errors, CORS, negotiation, and HEAD
|
|
@@ -41,14 +39,7 @@ OpenAPI 3.1 paths from a single, schema‑first application definition.
|
|
|
41
39
|
## Install
|
|
42
40
|
|
|
43
41
|
```bash
|
|
44
|
-
npm i @karmaniverous/smoz zod zod-openapi
|
|
45
|
-
@middy/http-header-normalizer \
|
|
46
|
-
@middy/http-event-normalizer \
|
|
47
|
-
@middy/http-json-body-parser \
|
|
48
|
-
@middy/http-content-negotiation \
|
|
49
|
-
@middy/http-error-handler \
|
|
50
|
-
@middy/http-cors \
|
|
51
|
-
@middy/http-response-serializer
|
|
42
|
+
npm i @karmaniverous/smoz zod zod-openapi
|
|
52
43
|
```
|
|
53
44
|
|
|
54
45
|
## Dev tooling (recommended):
|
package/dist/cli/index.cjs
CHANGED
|
@@ -796,8 +796,7 @@ const launchInline = async (root, opts) => {
|
|
|
796
796
|
* Scaffolds a new project from packaged templates.
|
|
797
797
|
* - Copies ./templates/project/ into the target root (shared boilerplate)
|
|
798
798
|
* - Copies ./templates/<template>/ into the target root (default: minimal)
|
|
799
|
-
* - Seeds app/generated/register.*.ts (empty modules) if missing
|
|
800
|
-
* - Idempotent: copy-if-absent; if a file exists, writes <name>.example alongside
|
|
799
|
+
* - Seeds app/generated/register.*.ts (empty modules) if missing * - Idempotent: copy-if-absent; if a file exists, writes <name>.example alongside
|
|
801
800
|
* - Additive merge of template manifest (deps/devDeps/scripts) into package.json
|
|
802
801
|
* - Optional dependency installation via --install[=<pm>]
|
|
803
802
|
*/
|
|
@@ -971,6 +970,33 @@ const runInit = async (root, template = 'minimal', opts) => {
|
|
|
971
970
|
}
|
|
972
971
|
// 2) Copy selected template
|
|
973
972
|
await copyDirIdempotent(srcBase, root, created, skipped, examples);
|
|
973
|
+
// 2.5) Convert template 'gitignore' into real '.gitignore'
|
|
974
|
+
// NPM often excludes '.gitignore' from published packages; shipping 'gitignore'
|
|
975
|
+
// and converting here ensures downstream projects get a proper .gitignore.
|
|
976
|
+
try {
|
|
977
|
+
const giSrc = path.join(root, 'gitignore');
|
|
978
|
+
const giDot = path.join(root, '.gitignore');
|
|
979
|
+
if (fs.existsSync(giSrc)) {
|
|
980
|
+
if (!fs.existsSync(giDot)) {
|
|
981
|
+
await fs.promises.rename(giSrc, giDot);
|
|
982
|
+
created.push(path.posix.normalize(giDot));
|
|
983
|
+
}
|
|
984
|
+
else {
|
|
985
|
+
// Both exist: preserve the template as an example (if not already present),
|
|
986
|
+
// then remove the extra 'gitignore' to avoid clutter.
|
|
987
|
+
const example = path.join(root, 'gitignore.example');
|
|
988
|
+
if (!fs.existsSync(example)) {
|
|
989
|
+
const data = await fs.promises.readFile(giSrc, 'utf8');
|
|
990
|
+
await fs.promises.writeFile(example, data, 'utf8');
|
|
991
|
+
examples.push(path.posix.normalize(example));
|
|
992
|
+
}
|
|
993
|
+
await fs.promises.rm(giSrc, { force: true });
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
catch {
|
|
998
|
+
// best-effort; ignore conversion errors
|
|
999
|
+
}
|
|
974
1000
|
// Seed app/generated/register.*.ts (empty modules) if missing
|
|
975
1001
|
const genDir = path.resolve(root, 'app', 'generated');
|
|
976
1002
|
const seeds = [
|
package/package.json
CHANGED
|
@@ -185,5 +185,5 @@
|
|
|
185
185
|
"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"
|
|
186
186
|
},
|
|
187
187
|
"type": "module",
|
|
188
|
-
"version": "0.1.
|
|
188
|
+
"version": "0.1.8"
|
|
189
189
|
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"@middy/core": "^6.4.4",
|
|
4
|
+
"zod": "^4.1.5"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"typescript": "^5.9.2",
|
|
8
|
-
"typescript-eslint": "^8.41.0",
|
|
9
7
|
"eslint": "^9.34.0",
|
|
10
8
|
"eslint-config-prettier": "^10.1.8",
|
|
11
9
|
"eslint-plugin-prettier": "^5.5.4",
|
|
12
10
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
13
|
-
"
|
|
14
|
-
"typedoc": "^0.28.11"
|
|
11
|
+
"jiti": "^2.5.1",
|
|
12
|
+
"typedoc": "^0.28.11",
|
|
13
|
+
"typescript": "^5.9.2",
|
|
14
|
+
"typescript-eslint": "^8.41.0",
|
|
15
|
+
"vitest": "^3.2.4"
|
|
15
16
|
},
|
|
16
17
|
"scripts": {
|
|
17
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
18
|
"lint": "eslint .",
|
|
19
|
-
"lint:fix": "eslint --fix ."
|
|
19
|
+
"lint:fix": "eslint --fix .",
|
|
20
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"@middy/core": "^6.4.4",
|
|
4
|
+
"zod": "^4.1.5"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"typescript": "^5.9.2",
|
|
8
|
-
"typescript-eslint": "^8.41.0",
|
|
9
7
|
"eslint": "^9.34.0",
|
|
10
8
|
"eslint-config-prettier": "^10.1.8",
|
|
11
9
|
"eslint-plugin-prettier": "^5.5.4",
|
|
12
|
-
"eslint-plugin-simple-import-sort": "^12.1.1"
|
|
10
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
11
|
+
"jiti": "^2.5.1",
|
|
12
|
+
"typescript": "^5.9.2",
|
|
13
|
+
"typescript-eslint": "^8.41.0",
|
|
14
|
+
"vitest": "^3.2.4"
|
|
13
15
|
},
|
|
14
16
|
"scripts": {
|
|
15
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
17
|
"lint": "eslint .",
|
|
17
|
-
"lint:fix": "eslint --fix ."
|
|
18
|
+
"lint:fix": "eslint --fix .",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
18
21
|
}
|
|
19
22
|
}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"@middy/core": "^6.4.4",
|
|
4
|
+
"zod": "^4.1.5"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"typescript": "^5.9.2",
|
|
8
|
-
"typescript-eslint": "^8.41.0",
|
|
9
7
|
"eslint": "^9.34.0",
|
|
10
8
|
"eslint-config-prettier": "^10.1.8",
|
|
11
9
|
"eslint-plugin-prettier": "^5.5.4",
|
|
12
10
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
13
|
-
"
|
|
14
|
-
"typedoc": "^0.28.11"
|
|
11
|
+
"jiti": "^2.5.1",
|
|
12
|
+
"typedoc": "^0.28.11",
|
|
13
|
+
"typescript": "^5.9.2",
|
|
14
|
+
"typescript-eslint": "^8.41.0",
|
|
15
|
+
"vitest": "^3.2.4"
|
|
15
16
|
},
|
|
16
17
|
"scripts": {
|
|
17
|
-
"
|
|
18
|
+
"docs": "typedoc",
|
|
18
19
|
"lint": "eslint .",
|
|
19
20
|
"lint:fix": "eslint --fix .",
|
|
20
21
|
"test": "vitest run",
|
|
21
|
-
"
|
|
22
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
22
23
|
}
|
|
23
24
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[markdown]": {
|
|
3
|
+
"editor.wordWrap": "bounded"
|
|
4
|
+
},
|
|
5
|
+
"diffEditor.ignoreTrimWhitespace": false,
|
|
6
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
7
|
+
"editor.formatOnPaste": true,
|
|
8
|
+
"editor.formatOnSave": true,
|
|
9
|
+
"eslint.useFlatConfig": true,
|
|
10
|
+
"eslint.validate": [
|
|
11
|
+
"javascript",
|
|
12
|
+
"javascriptreact",
|
|
13
|
+
"typescript",
|
|
14
|
+
"typescriptreact"
|
|
15
|
+
],
|
|
16
|
+
"git.autofetch": true,
|
|
17
|
+
"git.enableSmartCommit": true,
|
|
18
|
+
"javascript.preferences.importModuleSpecifierEnding": "minimal",
|
|
19
|
+
"javascript.updateImportsOnFileMove.enabled": "always",
|
|
20
|
+
"prettier.prettierPath": "./node_modules/prettier",
|
|
21
|
+
"prettier.singleQuote": true,
|
|
22
|
+
"yaml.format.singleQuote": true
|
|
23
|
+
}
|
|
@@ -23,34 +23,27 @@ This template provides a minimal, convention‑friendly baseline for new SMOZ ap
|
|
|
23
23
|
|
|
24
24
|
1. Install dependencies
|
|
25
25
|
- Run: `npm install`
|
|
26
|
-
|
|
27
26
|
2. Type checking
|
|
28
27
|
- Run: `npm run typecheck`
|
|
29
|
-
|
|
30
28
|
3. Linting
|
|
31
29
|
- Run: `npm run lint` (or `npm run lint:fix` to auto‑fix)
|
|
32
|
-
|
|
33
30
|
4. Tests (baseline suite OK)
|
|
34
31
|
- Run: `npm run test`
|
|
35
|
-
|
|
36
32
|
5. Docs (TypeDoc baseline loads)
|
|
37
33
|
- Run: `npm run docs`
|
|
38
|
-
|
|
39
34
|
6. Generate OpenAPI (if your app config and endpoints are present)
|
|
40
35
|
- Run: `npm run openapi`
|
|
41
36
|
|
|
42
37
|
## SMOZ CLI — register
|
|
43
38
|
|
|
44
|
-
The CLI scans `app/functions/**` for `lambda.ts`, `openapi.ts`, and optional `serverless.ts`
|
|
45
|
-
and generates side‑effect registration files under `app/generated/`.
|
|
39
|
+
The CLI scans `app/functions/**` for `lambda.ts`, `openapi.ts`, and optional `serverless.ts` and generates side‑effect registration files under `app/generated/`.
|
|
46
40
|
|
|
47
41
|
- Build CLI (if packaged locally): `npm run cli:build`
|
|
48
42
|
- Register: `npx smoz register`
|
|
49
43
|
- Idempotent: rewrites files only when content changes
|
|
50
44
|
- Formats output with Prettier when available
|
|
51
45
|
|
|
52
|
-
Tip: Commit `app/generated/register.*.ts` so typecheck is stable without running the CLI.
|
|
53
|
-
Teams often keep `app/generated/openapi.json` untracked in VCS (optional).
|
|
46
|
+
Tip: Commit `app/generated/register.*.ts` so typecheck is stable without running the CLI. Teams often keep `app/generated/openapi.json` untracked in VCS (optional).
|
|
54
47
|
|
|
55
48
|
## Notes
|
|
56
49
|
|
|
@@ -70,9 +63,7 @@ Teams often keep `app/generated/openapi.json` untracked in VCS (optional).
|
|
|
70
63
|
|
|
71
64
|
## Path hygiene (cross‑platform)
|
|
72
65
|
|
|
73
|
-
Windows uses backslashes in paths, which can leak into string comparisons and
|
|
74
|
-
generated artifacts. Normalize separators consistently using the helper exported
|
|
75
|
-
by the toolkit:
|
|
66
|
+
Windows uses backslashes in paths, which can leak into string comparisons and generated artifacts. Normalize separators consistently using the helper exported by the toolkit:
|
|
76
67
|
|
|
77
68
|
```ts
|
|
78
69
|
import { toPosixPath } from '@karmaniverous/smoz';
|
|
@@ -82,4 +73,4 @@ import { fileURLToPath } from 'node:url';
|
|
|
82
73
|
export const APP_ROOT_ABS = toPosixPath(
|
|
83
74
|
fileURLToPath(new URL('..', import.meta.url)),
|
|
84
75
|
);
|
|
85
|
-
```
|
|
76
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build outputs and caches
|
|
5
|
+
dist/
|
|
6
|
+
.tsbuild/
|
|
7
|
+
**/.tsbuild/
|
|
8
|
+
*.tsbuildinfo
|
|
9
|
+
**/.rollup.cache/
|
|
10
|
+
|
|
11
|
+
# Serverless packaging
|
|
12
|
+
.serverless/
|
|
13
|
+
|
|
14
|
+
# Test coverage
|
|
15
|
+
coverage/
|
|
16
|
+
|
|
17
|
+
# Generated artifacts
|
|
18
|
+
# Teams often keep registers tracked for typecheck stability,
|
|
19
|
+
# but the OpenAPI JSON is usually untracked.
|
|
20
|
+
app/generated/openapi.json
|
|
21
|
+
|
|
22
|
+
# Environment files (local only; do not commit secrets)
|
|
23
|
+
.env
|
|
24
|
+
.env.local
|
|
25
|
+
.env.*.local
|
|
26
|
+
|
|
27
|
+
# Logs
|
|
28
|
+
*.log
|
|
29
|
+
npm-debug.log*
|
|
30
|
+
yarn-debug.log*
|
|
31
|
+
yarn-error.log*
|
|
32
|
+
pnpm-debug.log*
|
|
33
|
+
|
|
34
|
+
# OS / editor files
|
|
35
|
+
.DS_Store
|
|
36
|
+
Thumbs.db
|
|
37
|
+
.idea/
|
|
38
|
+
.vscode/
|
|
39
|
+
|
|
40
|
+
# Misc
|
|
41
|
+
*.swp
|
|
42
|
+
*.swo
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
|
3
|
+
"noStandardTags": false,
|
|
4
|
+
"tagDefinitions": [
|
|
5
|
+
{ "tagName": "@author", "syntaxKind": "block" },
|
|
6
|
+
{ "tagName": "@module", "syntaxKind": "block" },
|
|
7
|
+
{ "tagName": "@type", "syntaxKind": "block" },
|
|
8
|
+
{ "tagName": "@typedef", "syntaxKind": "block" },
|
|
9
|
+
{ "tagName": "@callback", "syntaxKind": "block" },
|
|
10
|
+
{ "tagName": "@prop", "syntaxKind": "block", "allowMultiple": true },
|
|
11
|
+
{ "tagName": "@property", "syntaxKind": "block", "allowMultiple": true },
|
|
12
|
+
{ "tagName": "@group", "syntaxKind": "block", "allowMultiple": true },
|
|
13
|
+
{ "tagName": "@groupDescription", "syntaxKind": "block", "allowMultiple": true },
|
|
14
|
+
{ "tagName": "@category", "syntaxKind": "block", "allowMultiple": true },
|
|
15
|
+
{ "tagName": "@categoryDescription", "syntaxKind": "block", "allowMultiple": true },
|
|
16
|
+
{ "tagName": "@hidden", "syntaxKind": "modifier" },
|
|
17
|
+
{ "tagName": "@ignore", "syntaxKind": "modifier" },
|
|
18
|
+
{ "tagName": "@class", "syntaxKind": "modifier" },
|
|
19
|
+
{ "tagName": "@document", "syntaxKind": "block" },
|
|
20
|
+
{ "tagName": "@default", "syntaxKind": "block" },
|
|
21
|
+
{ "tagName": "@extends", "syntaxKind": "block" },
|
|
22
|
+
{ "tagName": "@augments", "syntaxKind": "block" },
|
|
23
|
+
{ "tagName": "@return", "syntaxKind": "block" },
|
|
24
|
+
{ "tagName": "@yields", "syntaxKind": "block" },
|
|
25
|
+
{ "tagName": "@enum", "syntaxKind": "modifier" },
|
|
26
|
+
{ "tagName": "@event", "syntaxKind": "modifier" },
|
|
27
|
+
{ "tagName": "@template", "syntaxKind": "block", "allowMultiple": true },
|
|
28
|
+
{ "tagName": "@linkcode", "syntaxKind": "inline", "allowMultiple": true },
|
|
29
|
+
{ "tagName": "@linkplain", "syntaxKind": "inline", "allowMultiple": true },
|
|
30
|
+
{ "tagName": "@private", "syntaxKind": "modifier" },
|
|
31
|
+
{ "tagName": "@protected", "syntaxKind": "modifier" },
|
|
32
|
+
{ "tagName": "@satisfies", "syntaxKind": "block" },
|
|
33
|
+
{ "tagName": "@since", "syntaxKind": "block" },
|
|
34
|
+
{ "tagName": "@license", "syntaxKind": "block" },
|
|
35
|
+
{ "tagName": "@import", "syntaxKind": "block" },
|
|
36
|
+
{ "tagName": "@overload", "syntaxKind": "modifier" },
|
|
37
|
+
{ "tagName": "@namespace", "syntaxKind": "modifier" },
|
|
38
|
+
{ "tagName": "@interface", "syntaxKind": "modifier" },
|
|
39
|
+
{ "tagName": "@showCategories", "syntaxKind": "modifier" },
|
|
40
|
+
{ "tagName": "@hideCategories", "syntaxKind": "modifier" },
|
|
41
|
+
{ "tagName": "@showGroups", "syntaxKind": "modifier" },
|
|
42
|
+
{ "tagName": "@hideGroups", "syntaxKind": "modifier" },
|
|
43
|
+
{ "tagName": "@hideconstructor", "syntaxKind": "modifier" },
|
|
44
|
+
{ "tagName": "@jsx", "syntaxKind": "block" }
|
|
45
|
+
]
|
|
46
|
+
}
|