| title | Templates |
|---|---|
| sidebar_label | Templates |
| sidebar_position | 4 |
The package ships a default app template and a shared “project” baseline.
- templates/project — shared boilerplate (tsconfig/eslint/prettier/vitest/typedoc)
- templates/default — a small app:
- app/config/app.config.ts
- app/functions/rest/hello/get/{lambda,handler,openapi}.ts
- app/functions/rest/openapi/get/{lambda,handler,openapi}.ts
- serverless.ts
- app/config/openapi.ts
SMOZ keeps side‑effect registers in app/generated/:
- register.functions.ts — imports all
lambda.ts - register.openapi.ts — imports all
openapi.ts - register.serverless.ts — imports all per‑function
serverless.ts(non‑HTTP)
Generate/update:
npx smoz registerTemplates do not commit generated files under app/generated/ (including register.*.ts). Instead, each template ships an ambient declarations file that declares the three register modules so TypeScript can typecheck without artifacts:
@/app/generated/register.functions@/app/generated/register.openapi@/app/generated/register.serverless
For the default template this file is: templates/default/types/registers.d.ts.
When a template needs to ensure register side effects are evaluated at runtime (e.g., in serverless.ts or the OpenAPI builder), import the register module as a namespace and reference it via void. This satisfies TypeScript’s noUncheckedSideEffectImports while still executing module side effects:
import * as __register_functions from '@/app/generated/register.functions';
void __register_functions;In real apps, smoz init seeds empty placeholders in app/generated/ and smoz register keeps them up to date. Teams often commit the generated register.*.ts files so CI typecheck remains stable.
The template includes a script to build app/generated/openapi.json:
npm run openapiIt imports register.openapi.ts, collects paths, and writes the document.
Always normalize file system separators when deriving paths from import.meta.url or from Node helpers. Example:
import { fileURLToPath } from 'node:url';
import { toPosixPath } from '@karmaniverous/smoz';
export const APP_ROOT_ABS = toPosixPath(
fileURLToPath(new URL('..', import.meta.url)),
);- Lint (ESLint drives Prettier):
A single ESLint flat config discovers all templates (no per‑template wiring).
npm run templates:lint
- Typecheck:
A small script finds
npm run templates:typecheck
templates/*/tsconfig.jsonand runstsc -p --noEmitper template. Adding a new template directory requires no script changes.
- Keep endpoint modules small and focused:
- lambda.ts — define/register function
- handler.ts — business handler
- openapi.ts — call
fn.openapi - serverless.ts (non‑HTTP only) — call
fn.serverless(extras)
- Do not duplicate HEAD routes; the HTTP stack short‑circuits HEAD to 200 {}.
- Prefer clear routes; when you must alias, use small wrappers or redirects.
Create a new folder under templates/* with a tsconfig.json. Lint/typecheck will pick it up automatically via the unified config and the typecheck script.
Yes—this can still be a good practice for downstream apps.
- If your CI/local scripts always run
smoz registerbefore typecheck/build/package, you don’t need to commitapp/generated/register.*.ts. - If you want typecheck/IDE and CI stability without relying on a prior CLI step, many teams commit
app/generated/register.*.ts.