tempest-express-sdk 0.9.0 → 0.11.0

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 CHANGED
@@ -38,7 +38,7 @@ npm install tempest-express-sdk tempest-db-js express zod
38
38
  | **flags / storage** | `FeatureFlags` (+ guard), `UploadStorage`/`LocalUploadStorage` |
39
39
  | **webpush / email** | `WebPushDispatcher` (VAPID), `EmailUtils` (SMTP) |
40
40
  | **server utils** | `TOTPHelper` (MFA), `HTTPClient` (retry + circuit breaker), `MetricsUtils` (+ Prometheus, GPU), `makeMetricsRouter`, `getClientIp` |
41
- | **integrations** | `MessagingProvider` contract; `WhatsAppProvider` (zap-api), `TelegramProvider` (Bot API), `TwilioSmsProvider` (SMS) + webhook receivers |
41
+ | **integrations** | `MessagingProvider` contract; `WhatsAppProvider` (zap-api), `TelegramProvider` (Bot API), `TwilioSmsProvider` (SMS), `EmailProvider`, `MessagingHub` + `broadcastText`, webhook receivers |
42
42
  | **admin** | `AdminSite` + `makeAdminRouter` — JSON admin with auto-derived CRUD + introspection |
43
43
  | **api** | `createApp`, `runServer`, `registerExceptionHandlers`, `createOpenApiRegistry`, `generateOpenApiDocument`, `mountSwaggerUi`, `mountRedoc`, `makeHealthRouter` |
44
44
 
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var VERSION = "0.11.0";
3
+
4
+ export { VERSION };
5
+ //# sourceMappingURL=chunk-IHO6X75J.js.map
6
+ //# sourceMappingURL=chunk-IHO6X75J.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AACO,IAAM,OAAA,GAAU","file":"chunk-4QZZGHGV.js","sourcesContent":["/** The installed SDK version. Single source of truth for the barrel + CLI. */\nexport const VERSION = \"0.9.0\";\n"]}
1
+ {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AACO,IAAM,OAAA,GAAU","file":"chunk-IHO6X75J.js","sourcesContent":["/** The installed SDK version. Single source of truth for the barrel + CLI. */\nexport const VERSION = \"0.11.0\";\n"]}
package/dist/cli.cjs CHANGED
@@ -408,7 +408,7 @@ volumes:
408
408
  }
409
409
 
410
410
  // src/version.ts
411
- var VERSION = "0.9.0";
411
+ var VERSION = "0.11.0";
412
412
 
413
413
  // src/cli/index.ts
414
414
  var USAGE = `tempest-express \u2014 Express SDK CLI
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/template.ts","../src/version.ts","../src/cli/index.ts"],"names":["join","mkdir","dirname","writeFile","resolve","parseArgs","randomBytes"],"mappings":"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","file":"cli.cjs","sourcesContent":["/**\n * Project-template generator for the `new` command, mirroring `cli.new`.\n *\n * Produces a complete, runnable Express service that follows the SDK's layered\n * architecture (router → controller → service → repository → model) and is\n * pre-wired with `createApp`, native Swagger + Redoc, Zod validation, and a\n * `tempest-db-js` model. {@link projectFiles} returns a `path → contents` map\n * the CLI writes to disk.\n */\n\n/** SDK version the generated project depends on (kept in sync at release). */\nconst SDK_VERSION = \"^0.1.0\";\n\n/**\n * Build the file map for a new service named `name`.\n *\n * @param name - The project (and package) name.\n * @returns A map of relative file path to file contents.\n */\nexport function projectFiles(name: string): Record<string, string> {\n return {\n \"package.json\": `${JSON.stringify(\n {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: {\n dev: \"tsx watch main.ts\",\n start: \"tsx main.ts\",\n build: \"tsc -p tsconfig.json\",\n typecheck: \"tsc --noEmit\",\n },\n dependencies: {\n express: \"^5.1.0\",\n \"tempest-db-js\": \"^0.3.0\",\n \"tempest-express-sdk\": SDK_VERSION,\n zod: \"^3.24.1\",\n },\n devDependencies: {\n \"@types/express\": \"^5.0.0\",\n \"@types/node\": \"^22.10.0\",\n tsx: \"^4.19.2\",\n typescript: \"^5.7.0\",\n },\n },\n null,\n 2,\n )}\\n`,\n\n \"tsconfig.json\": `${JSON.stringify(\n {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"Bundler\",\n lib: [\"ES2022\"],\n strict: true,\n noUncheckedIndexedAccess: true,\n verbatimModuleSyntax: true,\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n outDir: \"dist\",\n paths: { \"@/*\": [\"./src/*\"] },\n },\n include: [\"src\", \"main.ts\"],\n },\n null,\n 2,\n )}\\n`,\n\n \".gitignore\": \"node_modules\\ndist\\n.env\\n*.log\\n\",\n\n \".env.example\":\n \"HOST=127.0.0.1\\nPORT=8000\\nDEBUG=false\\nDATABASE_URL=sqlite://./app.db\\nCORS_ORIGINS=*\\n\",\n\n \"main.ts\": `import { run } from \"@/index\";\n\nrun();\n`,\n\n \"src/index.ts\": `import { run } from \"@/server\";\n\nexport { run };\n`,\n\n \"src/core/settings.ts\": `import { baseAppSettingsShape, loadSettings, z } from \"tempest-express-sdk\";\n\n/** Application settings — extend the SDK base shape with project fields. */\nexport const settingsSchema = z.object({\n ...baseAppSettingsShape,\n});\n\nexport const settings = loadSettings(settingsSchema);\n`,\n\n \"src/db/models/itemModel.ts\": `import { BaseModel, column, tableNameFor } from \"tempest-express-sdk\";\n\n/** A sample domain model. Replace with your own. */\nexport class ItemModel extends BaseModel {\n static tablename = tableNameFor(\"ItemModel\");\n name = column.text().notNull();\n price = column.integer().notNull();\n}\n`,\n\n \"src/schemas/item.ts\": `import { baseResponseSchema, z } from \"tempest-express-sdk\";\n\n/** Request payload to create an item. */\nexport const itemCreateSchema = z\n .object({\n name: z.string().min(1).openapi({ description: \"The item name.\" }),\n price: z.number().int().min(0).openapi({ description: \"Price in cents.\" }),\n })\n .openapi(\"ItemCreate\");\n\n/** Response payload for an item (base columns + domain fields). */\nexport const itemResponseSchema = baseResponseSchema\n .extend({\n name: z.string(),\n price: z.number().int(),\n })\n .openapi(\"Item\");\n\nexport type ItemCreate = z.infer<typeof itemCreateSchema>;\nexport type ItemResponse = z.infer<typeof itemResponseSchema>;\n`,\n\n \"src/db/repositories/itemRepository.ts\": `import { type AsyncSession, BaseRepository } from \"tempest-express-sdk\";\nimport { ItemModel } from \"@/db/models/itemModel\";\n\n/** Data-access layer for items. */\nexport class ItemRepository extends BaseRepository<typeof ItemModel> {\n constructor(session: AsyncSession) {\n super(ItemModel, session);\n }\n}\n`,\n\n \"src/services/itemService.ts\": `import { BaseService } from \"tempest-express-sdk\";\nimport type { ItemRepository } from \"@/db/repositories/itemRepository\";\nimport type { ItemModel } from \"@/db/models/itemModel\";\nimport type { ItemResponse } from \"@/schemas/item\";\n\n/** Business logic for items. Maps raw rows to the response shape. */\nexport class ItemService extends BaseService<typeof ItemModel, ItemResponse> {\n constructor(repository: ItemRepository) {\n super(repository, (row) => ({\n id: row.id,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n name: row.name,\n price: row.price,\n }));\n }\n}\n`,\n\n \"src/controllers/itemController.ts\": `import { BaseController } from \"tempest-express-sdk\";\nimport type { ItemModel } from \"@/db/models/itemModel\";\nimport type { ItemResponse } from \"@/schemas/item\";\nimport type { ItemService } from \"@/services/itemService\";\n\n/** Orchestration boundary between the router and the item service. */\nexport class ItemController extends BaseController<typeof ItemModel, ItemResponse> {\n constructor(service: ItemService) {\n super(service);\n }\n}\n`,\n\n \"src/api/routers/items.ts\": `import { Router } from \"express\";\nimport type { OpenAPIRegistry } from \"tempest-express-sdk\";\nimport { itemCreateSchema, itemResponseSchema } from \"@/schemas/item\";\n\n/**\n * Build the items router and register its OpenAPI paths.\n *\n * NOTE: wire a real controller (with a DB session) here. This stub returns\n * static data so a freshly generated project boots without a database.\n */\nexport function makeItemsRouter(registry: OpenAPIRegistry): Router {\n const router = Router();\n\n registry.registerPath({\n method: \"get\",\n path: \"/api/items\",\n summary: \"List items\",\n responses: {\n 200: {\n description: \"The items\",\n content: { \"application/json\": { schema: itemResponseSchema.array() } },\n },\n },\n });\n\n registry.registerPath({\n method: \"post\",\n path: \"/api/items\",\n summary: \"Create an item\",\n request: {\n body: { content: { \"application/json\": { schema: itemCreateSchema } } },\n },\n responses: {\n 201: {\n description: \"The created item\",\n content: { \"application/json\": { schema: itemResponseSchema } },\n },\n },\n });\n\n router.get(\"/api/items\", (_req, res) => {\n res.json([]);\n });\n\n router.post(\"/api/items\", (req, res) => {\n const data = itemCreateSchema.parse(req.body);\n res.status(201).json({\n id: \"00000000-0000-0000-0000-000000000000\",\n isActive: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...data,\n });\n });\n\n return router;\n}\n`,\n\n \"src/api/app.ts\": `import type { Express } from \"express\";\nimport { createApp, createOpenApiRegistry } from \"tempest-express-sdk\";\nimport { settings } from \"@/core/settings\";\nimport { makeItemsRouter } from \"@/api/routers/items\";\n\n/** Build the configured Express application. */\nexport async function makeApp(): Promise<Express> {\n const registry = createOpenApiRegistry();\n\n return createApp({\n corsOrigins: settings.CORS_ORIGINS,\n openapi: {\n registry,\n info: { title: \"${name}\", version: \"0.1.0\", description: \"Powered by tempest-express-sdk.\" },\n },\n configure: (app) => {\n app.use(makeItemsRouter(registry));\n },\n });\n}\n`,\n\n \"src/server.ts\": `import { runServer } from \"tempest-express-sdk\";\nimport { settings } from \"@/core/settings\";\nimport { makeApp } from \"@/api/app\";\n\n/** Build the app and start listening. */\nexport async function run(): Promise<void> {\n const app = await makeApp();\n await runServer(app, { host: settings.HOST, port: settings.PORT });\n}\n`,\n\n \"docker-compose.yml\": dockerComposeFile(name),\n\n \"README.md\": `# ${name}\n\nGenerated with \\`tempest-express new\\` — an Express + Zod + tempest-db-js service.\n\n## Develop\n\n\\`\\`\\`bash\nnpm install\ncp .env.example .env\nnpm run dev\n\\`\\`\\`\n\n- API: http://127.0.0.1:8000/api/items\n- Swagger UI: http://127.0.0.1:8000/docs\n- Redoc: http://127.0.0.1:8000/redoc\n- Health: http://127.0.0.1:8000/health\n\\`\\`\\`\n`,\n };\n}\n\n/** Lowercase the first letter (PascalCase → camelCase). */\nfunction toCamel(name: string): string {\n return name.charAt(0).toLowerCase() + name.slice(1);\n}\n\n/** Convert `CamelCase` to `snake_case`. */\nfunction toSnake(name: string): string {\n return name.replace(/(?<!^)(?=[A-Z])/g, \"_\").toLowerCase();\n}\n\n/**\n * Build a full CRUD resource file map for a PascalCase resource name.\n *\n * Generates model + schema + repository + service + controller + router under\n * `src/`, mirroring the layered slice the `new` template ships with.\n *\n * @param pascal - The resource name in PascalCase (e.g. `Product`).\n * @returns A map of relative file path to file contents.\n */\nexport function resourceFiles(pascal: string): Record<string, string> {\n const camel = toCamel(pascal);\n const table = toSnake(pascal);\n\n return {\n [`src/db/models/${camel}Model.ts`]: `import { BaseModel, column, tableNameFor } from \"tempest-express-sdk\";\n\n/** The ${pascal} domain model. */\nexport class ${pascal}Model extends BaseModel {\n static tablename = tableNameFor(\"${pascal}Model\"); // \"${table}\"\n name = column.text().notNull();\n}\n`,\n\n [`src/schemas/${camel}.ts`]: `import { baseResponseSchema, z } from \"tempest-express-sdk\";\n\n/** Request payload to create a ${pascal}. */\nexport const ${camel}CreateSchema = z\n .object({ name: z.string().min(1) })\n .openapi(\"${pascal}Create\");\n\n/** Response payload for a ${pascal}. */\nexport const ${camel}ResponseSchema = baseResponseSchema\n .extend({ name: z.string() })\n .openapi(\"${pascal}\");\n\nexport type ${pascal}Create = z.infer<typeof ${camel}CreateSchema>;\nexport type ${pascal}Response = z.infer<typeof ${camel}ResponseSchema>;\n`,\n\n [`src/db/repositories/${camel}Repository.ts`]: `import { type AsyncSession, BaseRepository } from \"tempest-express-sdk\";\nimport { ${pascal}Model } from \"@/db/models/${camel}Model\";\n\n/** Data-access layer for ${pascal}. */\nexport class ${pascal}Repository extends BaseRepository<typeof ${pascal}Model> {\n constructor(session: AsyncSession) {\n super(${pascal}Model, session);\n }\n}\n`,\n\n [`src/services/${camel}Service.ts`]: `import { BaseService } from \"tempest-express-sdk\";\nimport type { ${pascal}Model } from \"@/db/models/${camel}Model\";\nimport type { ${pascal}Repository } from \"@/db/repositories/${camel}Repository\";\nimport type { ${pascal}Response } from \"@/schemas/${camel}\";\n\n/** Business logic for ${pascal}. */\nexport class ${pascal}Service extends BaseService<typeof ${pascal}Model, ${pascal}Response> {\n constructor(repository: ${pascal}Repository) {\n super(repository, (row) => ({\n id: row.id,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n name: row.name,\n }));\n }\n}\n`,\n\n [`src/controllers/${camel}Controller.ts`]: `import { BaseController } from \"tempest-express-sdk\";\nimport type { ${pascal}Model } from \"@/db/models/${camel}Model\";\nimport type { ${pascal}Response } from \"@/schemas/${camel}\";\nimport type { ${pascal}Service } from \"@/services/${camel}Service\";\n\n/** Orchestration boundary for ${pascal}. */\nexport class ${pascal}Controller extends BaseController<typeof ${pascal}Model, ${pascal}Response> {\n constructor(service: ${pascal}Service) {\n super(service);\n }\n}\n`,\n\n [`src/api/routers/${camel}s.ts`]: `import { Router } from \"express\";\nimport type { OpenAPIRegistry } from \"tempest-express-sdk\";\nimport { ${camel}CreateSchema, ${camel}ResponseSchema } from \"@/schemas/${camel}\";\n\n/** Build the ${pascal} router and register its OpenAPI paths. */\nexport function make${pascal}sRouter(registry: OpenAPIRegistry): Router {\n const router = Router();\n\n registry.registerPath({\n method: \"get\",\n path: \"/api/${camel}s\",\n summary: \"List ${camel}s\",\n responses: {\n 200: {\n description: \"OK\",\n content: { \"application/json\": { schema: ${camel}ResponseSchema.array() } },\n },\n },\n });\n registry.registerPath({\n method: \"post\",\n path: \"/api/${camel}s\",\n summary: \"Create a ${camel}\",\n request: {\n body: { content: { \"application/json\": { schema: ${camel}CreateSchema } } },\n },\n responses: {\n 201: {\n description: \"Created\",\n content: { \"application/json\": { schema: ${camel}ResponseSchema } },\n },\n },\n });\n\n router.get(\"/api/${camel}s\", (_req, res) => res.json([]));\n router.post(\"/api/${camel}s\", (req, res) => {\n const data = ${camel}CreateSchema.parse(req.body);\n res.status(201).json({\n id: \"00000000-0000-0000-0000-000000000000\",\n isActive: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...data,\n });\n });\n\n return router;\n}\n`,\n };\n}\n\n/** Build a `docker-compose.yml` with Postgres + Redis for local dev. */\nexport function dockerComposeFile(name: string): string {\n return `services:\n postgres:\n image: postgres:16-alpine\n environment:\n POSTGRES_USER: ${name}\n POSTGRES_PASSWORD: ${name}\n POSTGRES_DB: ${name}\n ports:\n - \"5432:5432\"\n volumes:\n - pgdata:/var/lib/postgresql/data\n redis:\n image: redis:7-alpine\n ports:\n - \"6379:6379\"\n\nvolumes:\n pgdata:\n`;\n}\n","/** The installed SDK version. Single source of truth for the barrel + CLI. */\nexport const VERSION = \"0.9.0\";\n","#!/usr/bin/env node\n/**\n * `tempest-express` command-line interface, mirroring `cli.main`.\n *\n * Commands:\n * - `new <name>` — scaffold a runnable Express service from the SDK template.\n * - `--version` — print the CLI/SDK version.\n * - `--help` — print usage.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { dockerComposeFile, projectFiles, resourceFiles } from \"@/cli/template\";\nimport { VERSION } from \"@/version\";\n\nconst USAGE = `tempest-express — Express SDK CLI\n\nUsage:\n tempest-express new <name> [--dir <path>] Scaffold a new service\n tempest-express generate <Name> [--dir <path>] Scaffold a CRUD resource\n tempest-express secret [--bytes <n>] Print a random secret\n tempest-express docker-compose [--dir <path>] Write a docker-compose.yml\n tempest-express db Migration guidance\n tempest-express --version Print the version\n tempest-express --help Show this help\n`;\n\nconst DB_HELP = `Migrations are handled by tempest-db-js (programmatic API):\n\n import { ... } from \"tempest-db-js/migrations\";\n\nSee https://www.npmjs.com/package/tempest-db-js for the migration workflow.\n`;\n\n/** Write a project file map under `root`, creating directories as needed. */\nasync function writeFiles(root: string, files: Record<string, string>): Promise<void> {\n for (const [relative, contents] of Object.entries(files)) {\n const target = join(root, relative);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, contents, \"utf8\");\n }\n}\n\n/** Scaffold a new project named `name` into `dir/name`. */\nasync function runNew(name: string, dir: string): Promise<void> {\n if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) {\n throw new Error(`Invalid project name: ${JSON.stringify(name)}`);\n }\n const root = resolve(dir, name);\n await writeFiles(root, projectFiles(name));\n process.stdout.write(\n `Created ${name} at ${root}\\n\\nNext steps:\\n cd ${name}\\n npm install\\n cp .env.example .env\\n npm run dev\\n`,\n );\n}\n\n/** Scaffold a CRUD resource into `dir` (PascalCase name required). */\nasync function runGenerate(name: string, dir: string): Promise<void> {\n if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) {\n throw new Error(`Resource name must be PascalCase, got ${JSON.stringify(name)}`);\n }\n const files = resourceFiles(name);\n await writeFiles(resolve(dir), files);\n const written = Object.keys(files)\n .map((path) => ` ${path}`)\n .join(\"\\n\");\n process.stdout.write(`Generated ${name} resource:\\n${written}\\n`);\n}\n\n/**\n * Parse `argv` and dispatch to the matching command.\n *\n * @param argv - Arguments after `node script` (defaults to `process.argv`).\n * @returns The process exit code.\n */\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n version: { type: \"boolean\", short: \"v\" },\n help: { type: \"boolean\", short: \"h\" },\n dir: { type: \"string\", default: \".\" },\n bytes: { type: \"string\", default: \"32\" },\n },\n });\n\n if (values.version) {\n process.stdout.write(`${VERSION}\\n`);\n return 0;\n }\n\n const [command, ...rest] = positionals;\n\n if (values.help || command === undefined || command === \"help\") {\n process.stdout.write(USAGE);\n return 0;\n }\n\n const dir = values.dir ?? \".\";\n\n if (command === \"new\") {\n const name = rest[0];\n if (!name) {\n process.stderr.write(`error: \\`new\\` requires a project name\\n\\n${USAGE}`);\n return 1;\n }\n await runNew(name, dir);\n return 0;\n }\n\n if (command === \"generate\" || command === \"g\") {\n const name = rest[0];\n if (!name) {\n process.stderr.write(`error: \\`generate\\` requires a resource name\\n\\n${USAGE}`);\n return 1;\n }\n await runGenerate(name, dir);\n return 0;\n }\n\n if (command === \"secret\") {\n const nbytes = Number.parseInt(values.bytes ?? \"32\", 10);\n if (!Number.isInteger(nbytes) || nbytes < 16) {\n process.stderr.write(\"error: --bytes must be an integer >= 16\\n\");\n return 1;\n }\n process.stdout.write(`${randomBytes(nbytes).toString(\"base64url\")}\\n`);\n return 0;\n }\n\n if (command === \"docker-compose\") {\n await writeFiles(resolve(dir), { \"docker-compose.yml\": dockerComposeFile(\"app\") });\n process.stdout.write(`Wrote ${resolve(dir, \"docker-compose.yml\")}\\n`);\n return 0;\n }\n\n if (command === \"db\") {\n process.stdout.write(DB_HELP);\n return 0;\n }\n\n process.stderr.write(`error: unknown command ${JSON.stringify(command)}\\n\\n${USAGE}`);\n return 1;\n}\n\nmain()\n .then((code) => {\n process.exitCode = code;\n })\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`error: ${message}\\n`);\n process.exitCode = 1;\n });\n"]}
1
+ {"version":3,"sources":["../src/cli/template.ts","../src/version.ts","../src/cli/index.ts"],"names":["join","mkdir","dirname","writeFile","resolve","parseArgs","randomBytes"],"mappings":"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","file":"cli.cjs","sourcesContent":["/**\n * Project-template generator for the `new` command, mirroring `cli.new`.\n *\n * Produces a complete, runnable Express service that follows the SDK's layered\n * architecture (router → controller → service → repository → model) and is\n * pre-wired with `createApp`, native Swagger + Redoc, Zod validation, and a\n * `tempest-db-js` model. {@link projectFiles} returns a `path → contents` map\n * the CLI writes to disk.\n */\n\n/** SDK version the generated project depends on (kept in sync at release). */\nconst SDK_VERSION = \"^0.1.0\";\n\n/**\n * Build the file map for a new service named `name`.\n *\n * @param name - The project (and package) name.\n * @returns A map of relative file path to file contents.\n */\nexport function projectFiles(name: string): Record<string, string> {\n return {\n \"package.json\": `${JSON.stringify(\n {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: {\n dev: \"tsx watch main.ts\",\n start: \"tsx main.ts\",\n build: \"tsc -p tsconfig.json\",\n typecheck: \"tsc --noEmit\",\n },\n dependencies: {\n express: \"^5.1.0\",\n \"tempest-db-js\": \"^0.3.0\",\n \"tempest-express-sdk\": SDK_VERSION,\n zod: \"^3.24.1\",\n },\n devDependencies: {\n \"@types/express\": \"^5.0.0\",\n \"@types/node\": \"^22.10.0\",\n tsx: \"^4.19.2\",\n typescript: \"^5.7.0\",\n },\n },\n null,\n 2,\n )}\\n`,\n\n \"tsconfig.json\": `${JSON.stringify(\n {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"Bundler\",\n lib: [\"ES2022\"],\n strict: true,\n noUncheckedIndexedAccess: true,\n verbatimModuleSyntax: true,\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n outDir: \"dist\",\n paths: { \"@/*\": [\"./src/*\"] },\n },\n include: [\"src\", \"main.ts\"],\n },\n null,\n 2,\n )}\\n`,\n\n \".gitignore\": \"node_modules\\ndist\\n.env\\n*.log\\n\",\n\n \".env.example\":\n \"HOST=127.0.0.1\\nPORT=8000\\nDEBUG=false\\nDATABASE_URL=sqlite://./app.db\\nCORS_ORIGINS=*\\n\",\n\n \"main.ts\": `import { run } from \"@/index\";\n\nrun();\n`,\n\n \"src/index.ts\": `import { run } from \"@/server\";\n\nexport { run };\n`,\n\n \"src/core/settings.ts\": `import { baseAppSettingsShape, loadSettings, z } from \"tempest-express-sdk\";\n\n/** Application settings — extend the SDK base shape with project fields. */\nexport const settingsSchema = z.object({\n ...baseAppSettingsShape,\n});\n\nexport const settings = loadSettings(settingsSchema);\n`,\n\n \"src/db/models/itemModel.ts\": `import { BaseModel, column, tableNameFor } from \"tempest-express-sdk\";\n\n/** A sample domain model. Replace with your own. */\nexport class ItemModel extends BaseModel {\n static tablename = tableNameFor(\"ItemModel\");\n name = column.text().notNull();\n price = column.integer().notNull();\n}\n`,\n\n \"src/schemas/item.ts\": `import { baseResponseSchema, z } from \"tempest-express-sdk\";\n\n/** Request payload to create an item. */\nexport const itemCreateSchema = z\n .object({\n name: z.string().min(1).openapi({ description: \"The item name.\" }),\n price: z.number().int().min(0).openapi({ description: \"Price in cents.\" }),\n })\n .openapi(\"ItemCreate\");\n\n/** Response payload for an item (base columns + domain fields). */\nexport const itemResponseSchema = baseResponseSchema\n .extend({\n name: z.string(),\n price: z.number().int(),\n })\n .openapi(\"Item\");\n\nexport type ItemCreate = z.infer<typeof itemCreateSchema>;\nexport type ItemResponse = z.infer<typeof itemResponseSchema>;\n`,\n\n \"src/db/repositories/itemRepository.ts\": `import { type AsyncSession, BaseRepository } from \"tempest-express-sdk\";\nimport { ItemModel } from \"@/db/models/itemModel\";\n\n/** Data-access layer for items. */\nexport class ItemRepository extends BaseRepository<typeof ItemModel> {\n constructor(session: AsyncSession) {\n super(ItemModel, session);\n }\n}\n`,\n\n \"src/services/itemService.ts\": `import { BaseService } from \"tempest-express-sdk\";\nimport type { ItemRepository } from \"@/db/repositories/itemRepository\";\nimport type { ItemModel } from \"@/db/models/itemModel\";\nimport type { ItemResponse } from \"@/schemas/item\";\n\n/** Business logic for items. Maps raw rows to the response shape. */\nexport class ItemService extends BaseService<typeof ItemModel, ItemResponse> {\n constructor(repository: ItemRepository) {\n super(repository, (row) => ({\n id: row.id,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n name: row.name,\n price: row.price,\n }));\n }\n}\n`,\n\n \"src/controllers/itemController.ts\": `import { BaseController } from \"tempest-express-sdk\";\nimport type { ItemModel } from \"@/db/models/itemModel\";\nimport type { ItemResponse } from \"@/schemas/item\";\nimport type { ItemService } from \"@/services/itemService\";\n\n/** Orchestration boundary between the router and the item service. */\nexport class ItemController extends BaseController<typeof ItemModel, ItemResponse> {\n constructor(service: ItemService) {\n super(service);\n }\n}\n`,\n\n \"src/api/routers/items.ts\": `import { Router } from \"express\";\nimport type { OpenAPIRegistry } from \"tempest-express-sdk\";\nimport { itemCreateSchema, itemResponseSchema } from \"@/schemas/item\";\n\n/**\n * Build the items router and register its OpenAPI paths.\n *\n * NOTE: wire a real controller (with a DB session) here. This stub returns\n * static data so a freshly generated project boots without a database.\n */\nexport function makeItemsRouter(registry: OpenAPIRegistry): Router {\n const router = Router();\n\n registry.registerPath({\n method: \"get\",\n path: \"/api/items\",\n summary: \"List items\",\n responses: {\n 200: {\n description: \"The items\",\n content: { \"application/json\": { schema: itemResponseSchema.array() } },\n },\n },\n });\n\n registry.registerPath({\n method: \"post\",\n path: \"/api/items\",\n summary: \"Create an item\",\n request: {\n body: { content: { \"application/json\": { schema: itemCreateSchema } } },\n },\n responses: {\n 201: {\n description: \"The created item\",\n content: { \"application/json\": { schema: itemResponseSchema } },\n },\n },\n });\n\n router.get(\"/api/items\", (_req, res) => {\n res.json([]);\n });\n\n router.post(\"/api/items\", (req, res) => {\n const data = itemCreateSchema.parse(req.body);\n res.status(201).json({\n id: \"00000000-0000-0000-0000-000000000000\",\n isActive: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...data,\n });\n });\n\n return router;\n}\n`,\n\n \"src/api/app.ts\": `import type { Express } from \"express\";\nimport { createApp, createOpenApiRegistry } from \"tempest-express-sdk\";\nimport { settings } from \"@/core/settings\";\nimport { makeItemsRouter } from \"@/api/routers/items\";\n\n/** Build the configured Express application. */\nexport async function makeApp(): Promise<Express> {\n const registry = createOpenApiRegistry();\n\n return createApp({\n corsOrigins: settings.CORS_ORIGINS,\n openapi: {\n registry,\n info: { title: \"${name}\", version: \"0.1.0\", description: \"Powered by tempest-express-sdk.\" },\n },\n configure: (app) => {\n app.use(makeItemsRouter(registry));\n },\n });\n}\n`,\n\n \"src/server.ts\": `import { runServer } from \"tempest-express-sdk\";\nimport { settings } from \"@/core/settings\";\nimport { makeApp } from \"@/api/app\";\n\n/** Build the app and start listening. */\nexport async function run(): Promise<void> {\n const app = await makeApp();\n await runServer(app, { host: settings.HOST, port: settings.PORT });\n}\n`,\n\n \"docker-compose.yml\": dockerComposeFile(name),\n\n \"README.md\": `# ${name}\n\nGenerated with \\`tempest-express new\\` — an Express + Zod + tempest-db-js service.\n\n## Develop\n\n\\`\\`\\`bash\nnpm install\ncp .env.example .env\nnpm run dev\n\\`\\`\\`\n\n- API: http://127.0.0.1:8000/api/items\n- Swagger UI: http://127.0.0.1:8000/docs\n- Redoc: http://127.0.0.1:8000/redoc\n- Health: http://127.0.0.1:8000/health\n\\`\\`\\`\n`,\n };\n}\n\n/** Lowercase the first letter (PascalCase → camelCase). */\nfunction toCamel(name: string): string {\n return name.charAt(0).toLowerCase() + name.slice(1);\n}\n\n/** Convert `CamelCase` to `snake_case`. */\nfunction toSnake(name: string): string {\n return name.replace(/(?<!^)(?=[A-Z])/g, \"_\").toLowerCase();\n}\n\n/**\n * Build a full CRUD resource file map for a PascalCase resource name.\n *\n * Generates model + schema + repository + service + controller + router under\n * `src/`, mirroring the layered slice the `new` template ships with.\n *\n * @param pascal - The resource name in PascalCase (e.g. `Product`).\n * @returns A map of relative file path to file contents.\n */\nexport function resourceFiles(pascal: string): Record<string, string> {\n const camel = toCamel(pascal);\n const table = toSnake(pascal);\n\n return {\n [`src/db/models/${camel}Model.ts`]: `import { BaseModel, column, tableNameFor } from \"tempest-express-sdk\";\n\n/** The ${pascal} domain model. */\nexport class ${pascal}Model extends BaseModel {\n static tablename = tableNameFor(\"${pascal}Model\"); // \"${table}\"\n name = column.text().notNull();\n}\n`,\n\n [`src/schemas/${camel}.ts`]: `import { baseResponseSchema, z } from \"tempest-express-sdk\";\n\n/** Request payload to create a ${pascal}. */\nexport const ${camel}CreateSchema = z\n .object({ name: z.string().min(1) })\n .openapi(\"${pascal}Create\");\n\n/** Response payload for a ${pascal}. */\nexport const ${camel}ResponseSchema = baseResponseSchema\n .extend({ name: z.string() })\n .openapi(\"${pascal}\");\n\nexport type ${pascal}Create = z.infer<typeof ${camel}CreateSchema>;\nexport type ${pascal}Response = z.infer<typeof ${camel}ResponseSchema>;\n`,\n\n [`src/db/repositories/${camel}Repository.ts`]: `import { type AsyncSession, BaseRepository } from \"tempest-express-sdk\";\nimport { ${pascal}Model } from \"@/db/models/${camel}Model\";\n\n/** Data-access layer for ${pascal}. */\nexport class ${pascal}Repository extends BaseRepository<typeof ${pascal}Model> {\n constructor(session: AsyncSession) {\n super(${pascal}Model, session);\n }\n}\n`,\n\n [`src/services/${camel}Service.ts`]: `import { BaseService } from \"tempest-express-sdk\";\nimport type { ${pascal}Model } from \"@/db/models/${camel}Model\";\nimport type { ${pascal}Repository } from \"@/db/repositories/${camel}Repository\";\nimport type { ${pascal}Response } from \"@/schemas/${camel}\";\n\n/** Business logic for ${pascal}. */\nexport class ${pascal}Service extends BaseService<typeof ${pascal}Model, ${pascal}Response> {\n constructor(repository: ${pascal}Repository) {\n super(repository, (row) => ({\n id: row.id,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n name: row.name,\n }));\n }\n}\n`,\n\n [`src/controllers/${camel}Controller.ts`]: `import { BaseController } from \"tempest-express-sdk\";\nimport type { ${pascal}Model } from \"@/db/models/${camel}Model\";\nimport type { ${pascal}Response } from \"@/schemas/${camel}\";\nimport type { ${pascal}Service } from \"@/services/${camel}Service\";\n\n/** Orchestration boundary for ${pascal}. */\nexport class ${pascal}Controller extends BaseController<typeof ${pascal}Model, ${pascal}Response> {\n constructor(service: ${pascal}Service) {\n super(service);\n }\n}\n`,\n\n [`src/api/routers/${camel}s.ts`]: `import { Router } from \"express\";\nimport type { OpenAPIRegistry } from \"tempest-express-sdk\";\nimport { ${camel}CreateSchema, ${camel}ResponseSchema } from \"@/schemas/${camel}\";\n\n/** Build the ${pascal} router and register its OpenAPI paths. */\nexport function make${pascal}sRouter(registry: OpenAPIRegistry): Router {\n const router = Router();\n\n registry.registerPath({\n method: \"get\",\n path: \"/api/${camel}s\",\n summary: \"List ${camel}s\",\n responses: {\n 200: {\n description: \"OK\",\n content: { \"application/json\": { schema: ${camel}ResponseSchema.array() } },\n },\n },\n });\n registry.registerPath({\n method: \"post\",\n path: \"/api/${camel}s\",\n summary: \"Create a ${camel}\",\n request: {\n body: { content: { \"application/json\": { schema: ${camel}CreateSchema } } },\n },\n responses: {\n 201: {\n description: \"Created\",\n content: { \"application/json\": { schema: ${camel}ResponseSchema } },\n },\n },\n });\n\n router.get(\"/api/${camel}s\", (_req, res) => res.json([]));\n router.post(\"/api/${camel}s\", (req, res) => {\n const data = ${camel}CreateSchema.parse(req.body);\n res.status(201).json({\n id: \"00000000-0000-0000-0000-000000000000\",\n isActive: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n ...data,\n });\n });\n\n return router;\n}\n`,\n };\n}\n\n/** Build a `docker-compose.yml` with Postgres + Redis for local dev. */\nexport function dockerComposeFile(name: string): string {\n return `services:\n postgres:\n image: postgres:16-alpine\n environment:\n POSTGRES_USER: ${name}\n POSTGRES_PASSWORD: ${name}\n POSTGRES_DB: ${name}\n ports:\n - \"5432:5432\"\n volumes:\n - pgdata:/var/lib/postgresql/data\n redis:\n image: redis:7-alpine\n ports:\n - \"6379:6379\"\n\nvolumes:\n pgdata:\n`;\n}\n","/** The installed SDK version. Single source of truth for the barrel + CLI. */\nexport const VERSION = \"0.11.0\";\n","#!/usr/bin/env node\n/**\n * `tempest-express` command-line interface, mirroring `cli.main`.\n *\n * Commands:\n * - `new <name>` — scaffold a runnable Express service from the SDK template.\n * - `--version` — print the CLI/SDK version.\n * - `--help` — print usage.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { dockerComposeFile, projectFiles, resourceFiles } from \"@/cli/template\";\nimport { VERSION } from \"@/version\";\n\nconst USAGE = `tempest-express — Express SDK CLI\n\nUsage:\n tempest-express new <name> [--dir <path>] Scaffold a new service\n tempest-express generate <Name> [--dir <path>] Scaffold a CRUD resource\n tempest-express secret [--bytes <n>] Print a random secret\n tempest-express docker-compose [--dir <path>] Write a docker-compose.yml\n tempest-express db Migration guidance\n tempest-express --version Print the version\n tempest-express --help Show this help\n`;\n\nconst DB_HELP = `Migrations are handled by tempest-db-js (programmatic API):\n\n import { ... } from \"tempest-db-js/migrations\";\n\nSee https://www.npmjs.com/package/tempest-db-js for the migration workflow.\n`;\n\n/** Write a project file map under `root`, creating directories as needed. */\nasync function writeFiles(root: string, files: Record<string, string>): Promise<void> {\n for (const [relative, contents] of Object.entries(files)) {\n const target = join(root, relative);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, contents, \"utf8\");\n }\n}\n\n/** Scaffold a new project named `name` into `dir/name`. */\nasync function runNew(name: string, dir: string): Promise<void> {\n if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) {\n throw new Error(`Invalid project name: ${JSON.stringify(name)}`);\n }\n const root = resolve(dir, name);\n await writeFiles(root, projectFiles(name));\n process.stdout.write(\n `Created ${name} at ${root}\\n\\nNext steps:\\n cd ${name}\\n npm install\\n cp .env.example .env\\n npm run dev\\n`,\n );\n}\n\n/** Scaffold a CRUD resource into `dir` (PascalCase name required). */\nasync function runGenerate(name: string, dir: string): Promise<void> {\n if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) {\n throw new Error(`Resource name must be PascalCase, got ${JSON.stringify(name)}`);\n }\n const files = resourceFiles(name);\n await writeFiles(resolve(dir), files);\n const written = Object.keys(files)\n .map((path) => ` ${path}`)\n .join(\"\\n\");\n process.stdout.write(`Generated ${name} resource:\\n${written}\\n`);\n}\n\n/**\n * Parse `argv` and dispatch to the matching command.\n *\n * @param argv - Arguments after `node script` (defaults to `process.argv`).\n * @returns The process exit code.\n */\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n version: { type: \"boolean\", short: \"v\" },\n help: { type: \"boolean\", short: \"h\" },\n dir: { type: \"string\", default: \".\" },\n bytes: { type: \"string\", default: \"32\" },\n },\n });\n\n if (values.version) {\n process.stdout.write(`${VERSION}\\n`);\n return 0;\n }\n\n const [command, ...rest] = positionals;\n\n if (values.help || command === undefined || command === \"help\") {\n process.stdout.write(USAGE);\n return 0;\n }\n\n const dir = values.dir ?? \".\";\n\n if (command === \"new\") {\n const name = rest[0];\n if (!name) {\n process.stderr.write(`error: \\`new\\` requires a project name\\n\\n${USAGE}`);\n return 1;\n }\n await runNew(name, dir);\n return 0;\n }\n\n if (command === \"generate\" || command === \"g\") {\n const name = rest[0];\n if (!name) {\n process.stderr.write(`error: \\`generate\\` requires a resource name\\n\\n${USAGE}`);\n return 1;\n }\n await runGenerate(name, dir);\n return 0;\n }\n\n if (command === \"secret\") {\n const nbytes = Number.parseInt(values.bytes ?? \"32\", 10);\n if (!Number.isInteger(nbytes) || nbytes < 16) {\n process.stderr.write(\"error: --bytes must be an integer >= 16\\n\");\n return 1;\n }\n process.stdout.write(`${randomBytes(nbytes).toString(\"base64url\")}\\n`);\n return 0;\n }\n\n if (command === \"docker-compose\") {\n await writeFiles(resolve(dir), { \"docker-compose.yml\": dockerComposeFile(\"app\") });\n process.stdout.write(`Wrote ${resolve(dir, \"docker-compose.yml\")}\\n`);\n return 0;\n }\n\n if (command === \"db\") {\n process.stdout.write(DB_HELP);\n return 0;\n }\n\n process.stderr.write(`error: unknown command ${JSON.stringify(command)}\\n\\n${USAGE}`);\n return 1;\n}\n\nmain()\n .then((code) => {\n process.exitCode = code;\n })\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`error: ${message}\\n`);\n process.exitCode = 1;\n });\n"]}
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { VERSION } from './chunk-4QZZGHGV.js';
2
+ import { VERSION } from './chunk-IHO6X75J.js';
3
3
  import { randomBytes } from 'crypto';
4
4
  import { mkdir, writeFile } from 'fs/promises';
5
5
  import { resolve, join, dirname } from 'path';
package/dist/index.cjs CHANGED
@@ -8584,6 +8584,133 @@ function makeTwilioWebhookRouter(options) {
8584
8584
  return router;
8585
8585
  }
8586
8586
 
8587
+ // src/integrations/email.ts
8588
+ var EmailProvider = class {
8589
+ email;
8590
+ subject;
8591
+ /**
8592
+ * @param options - The email sender and default subject.
8593
+ */
8594
+ constructor(options) {
8595
+ this.email = options.email;
8596
+ this.subject = options.subject ?? "Notification";
8597
+ }
8598
+ /**
8599
+ * Send a plain-text email.
8600
+ *
8601
+ * @param to - Recipient address.
8602
+ * @param text - Body text (also used as HTML).
8603
+ * @returns A sent result.
8604
+ */
8605
+ async sendText(to, text) {
8606
+ await this.email.send({ to, subject: this.subject, text });
8607
+ return { status: "sent" };
8608
+ }
8609
+ /**
8610
+ * Send an email linking to the media (caption becomes the lead text).
8611
+ *
8612
+ * @param to - Recipient address.
8613
+ * @param media - The media reference (URL) + optional caption.
8614
+ * @returns A sent result.
8615
+ */
8616
+ async sendMedia(to, media) {
8617
+ const caption = media.caption ?? "";
8618
+ await this.email.send({
8619
+ to,
8620
+ subject: this.subject,
8621
+ html: `${caption ? `<p>${caption}</p>` : ""}<p><a href="${media.media}">${media.media}</a></p>`
8622
+ });
8623
+ return { status: "sent" };
8624
+ }
8625
+ /** Always `"connected"` — SMTP reachability is verified on first send. */
8626
+ async status() {
8627
+ return "connected";
8628
+ }
8629
+ };
8630
+
8631
+ // src/integrations/broadcast.ts
8632
+ async function pool(items, limit, worker) {
8633
+ const results = new Array(items.length);
8634
+ let cursor = 0;
8635
+ const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
8636
+ while (cursor < items.length) {
8637
+ const index = cursor++;
8638
+ results[index] = await worker(items[index], index);
8639
+ }
8640
+ });
8641
+ await Promise.all(runners);
8642
+ return results;
8643
+ }
8644
+ function broadcastText(provider, recipients, text, options = {}) {
8645
+ const { concurrency = 10, ...sendOptions } = options;
8646
+ return pool(recipients, concurrency, async (to) => {
8647
+ try {
8648
+ const result = await provider.sendText(to, text, sendOptions);
8649
+ return { to, ok: true, result };
8650
+ } catch (error) {
8651
+ return {
8652
+ to,
8653
+ ok: false,
8654
+ error: error instanceof Error ? error.message : String(error)
8655
+ };
8656
+ }
8657
+ });
8658
+ }
8659
+ var MessagingHub = class {
8660
+ channels = /* @__PURE__ */ new Map();
8661
+ /**
8662
+ * Register a provider under a channel name.
8663
+ *
8664
+ * @param name - The channel name (e.g. `"whatsapp"`, `"sms"`).
8665
+ * @param provider - The provider implementation.
8666
+ * @returns The hub (chainable).
8667
+ */
8668
+ register(name, provider) {
8669
+ this.channels.set(name, provider);
8670
+ return this;
8671
+ }
8672
+ /**
8673
+ * Get a registered provider, throwing when the channel is unknown.
8674
+ *
8675
+ * @param name - The channel name.
8676
+ * @returns The provider.
8677
+ * @throws {Error} When no provider is registered under `name`.
8678
+ */
8679
+ get(name) {
8680
+ const provider = this.channels.get(name);
8681
+ if (!provider) throw new Error(`Unknown messaging channel: ${name}`);
8682
+ return provider;
8683
+ }
8684
+ /** The registered channel names. */
8685
+ channelNames() {
8686
+ return [...this.channels.keys()];
8687
+ }
8688
+ /**
8689
+ * Send text through a named channel.
8690
+ *
8691
+ * @param channel - The channel name.
8692
+ * @param to - The recipient.
8693
+ * @param text - The message body.
8694
+ * @param options - Send options.
8695
+ * @returns The provider result.
8696
+ */
8697
+ send(channel, to, text, options) {
8698
+ return this.get(channel).sendText(to, text, options);
8699
+ }
8700
+ /**
8701
+ * Broadcast text to many recipients on a named channel.
8702
+ *
8703
+ * @param channel - The channel name.
8704
+ * @param recipients - Recipient addresses/handles.
8705
+ * @param text - The message body.
8706
+ * @param options - Broadcast + send options.
8707
+ * @returns One result per recipient.
8708
+ */
8709
+ broadcast(channel, recipients, text, options) {
8710
+ return broadcastText(this.get(channel), recipients, text, options);
8711
+ }
8712
+ };
8713
+
8587
8714
  // src/admin/site.ts
8588
8715
  var AdminSite = class {
8589
8716
  /**
@@ -8723,6 +8850,10 @@ var mfaEnrollResponseSchema = zod.z.object({
8723
8850
  otpauthUri: zod.z.string().openapi({ description: "otpauth:// URI to render as QR." })
8724
8851
  }).openapi("MfaEnrollResponse");
8725
8852
  var mfaCodeSchema = zod.z.object({ code: zod.z.string().min(1).openapi({ description: "Authenticator code." }) }).openapi("MfaCode");
8853
+ var mfaChallengeSchema = zod.z.object({
8854
+ mfaToken: zod.z.string().min(1).openapi({ description: "Challenge token from login." }),
8855
+ code: zod.z.string().min(1).openapi({ description: "Authenticator code." })
8856
+ }).openapi("MfaChallenge");
8726
8857
  var activationSchema = zod.z.object({ token: zod.z.string().min(1).openapi({ description: "Activation token." }) }).openapi("Activation");
8727
8858
  var passwordResetRequestSchema = zod.z.object({ email: zod.z.string().email().openapi({ description: "Account email." }) }).openapi("PasswordResetRequest");
8728
8859
  var passwordResetConfirmSchema = zod.z.object({
@@ -8747,6 +8878,8 @@ var UserAuthService = class {
8747
8878
  passwordMinLength;
8748
8879
  accessTtlSeconds;
8749
8880
  refreshTtlSeconds;
8881
+ mfa;
8882
+ mfaChallengeTtlSeconds;
8750
8883
  /**
8751
8884
  * @param options - Store, password/JWT helpers and token policy.
8752
8885
  */
@@ -8757,6 +8890,8 @@ var UserAuthService = class {
8757
8890
  this.passwordMinLength = options.passwordMinLength ?? 12;
8758
8891
  this.accessTtlSeconds = options.accessTtlSeconds ?? 3600;
8759
8892
  this.refreshTtlSeconds = options.refreshTtlSeconds ?? 60 * 60 * 24 * 14;
8893
+ this.mfa = options.mfa;
8894
+ this.mfaChallengeTtlSeconds = options.mfaChallengeTtlSeconds ?? 300;
8760
8895
  }
8761
8896
  /** Mint a signed access + refresh token pair for `user`. */
8762
8897
  async issueTokens(user) {
@@ -8806,7 +8941,7 @@ var UserAuthService = class {
8806
8941
  * Authenticate a user by email + password.
8807
8942
  *
8808
8943
  * @param data - Validated login payload.
8809
- * @returns The public user and a fresh token pair.
8944
+ * @returns Full auth, or an {@link MfaChallenge} when MFA is enabled.
8810
8945
  * @throws {UnauthorizedException} On bad credentials or inactive account.
8811
8946
  */
8812
8947
  async login(data) {
@@ -8818,6 +8953,37 @@ var UserAuthService = class {
8818
8953
  if (!user.isActive) {
8819
8954
  throw new UnauthorizedException({ message: "Account is inactive" });
8820
8955
  }
8956
+ if (this.mfa && await this.mfa.isEnabled(user.id)) {
8957
+ const mfaToken = await this.jwt.encode(
8958
+ { sub: user.id, type: "mfa" },
8959
+ { ttlSeconds: this.mfaChallengeTtlSeconds }
8960
+ );
8961
+ return { mfaRequired: true, mfaToken };
8962
+ }
8963
+ return { user: toPublic(user), tokens: await this.issueTokens(user) };
8964
+ }
8965
+ /**
8966
+ * Complete an MFA login challenge: verify the code and issue tokens.
8967
+ *
8968
+ * @param mfaToken - The challenge token from {@link login}.
8969
+ * @param code - The authenticator code.
8970
+ * @returns The public user and a fresh token pair.
8971
+ * @throws {UnauthorizedException} When the challenge/code is invalid, MFA is
8972
+ * not configured, or the account no longer exists / is inactive.
8973
+ */
8974
+ async verifyMfaChallenge(mfaToken, code) {
8975
+ if (!this.mfa) throw new UnauthorizedException({ message: "MFA not configured" });
8976
+ const claims = await this.jwt.decodeOrNull(mfaToken);
8977
+ if (!claims || claims.type !== "mfa" || typeof claims.sub !== "string") {
8978
+ throw new UnauthorizedException({ message: "Invalid MFA challenge" });
8979
+ }
8980
+ if (!await this.mfa.verify(claims.sub, code)) {
8981
+ throw new UnauthorizedException({ message: "Invalid MFA code" });
8982
+ }
8983
+ const user = await this.store.findById(claims.sub);
8984
+ if (!user || !user.isActive) {
8985
+ throw new UnauthorizedException({ message: "Account is inactive" });
8986
+ }
8821
8987
  return { user: toPublic(user), tokens: await this.issueTokens(user) };
8822
8988
  }
8823
8989
  /**
@@ -8891,6 +9057,15 @@ var MfaService = class {
8891
9057
  const secret = await this.store.getSecret(userId);
8892
9058
  return secret ? this.totp.verify(secret, code) : false;
8893
9059
  }
9060
+ /**
9061
+ * Whether MFA is enabled for a user (used to gate the login challenge).
9062
+ *
9063
+ * @param userId - The user.
9064
+ * @returns `true` when MFA is enabled.
9065
+ */
9066
+ async isEnabled(userId) {
9067
+ return this.store.isEnabled(userId);
9068
+ }
8894
9069
  /**
8895
9070
  * Disable MFA after verifying a code.
8896
9071
  *
@@ -9138,6 +9313,10 @@ function makeAuthRouter(options) {
9138
9313
  }
9139
9314
  if (options.mfa) {
9140
9315
  const mfa = options.mfa;
9316
+ router.post(`${prefix}/mfa/challenge`, async (req, res) => {
9317
+ const { mfaToken, code } = mfaChallengeSchema.parse(req.body);
9318
+ res.json(await service.verifyMfaChallenge(mfaToken, code));
9319
+ });
9141
9320
  const requireUser = (req) => {
9142
9321
  const claims = getAuth(req);
9143
9322
  if (!claims || typeof claims.sub !== "string") {
@@ -9440,7 +9619,7 @@ function runServer(app, options = {}) {
9440
9619
  }
9441
9620
 
9442
9621
  // src/version.ts
9443
- var VERSION = "0.9.0";
9622
+ var VERSION = "0.11.0";
9444
9623
 
9445
9624
  Object.defineProperty(exports, "OpenAPIRegistry", {
9446
9625
  enumerable: true,
@@ -9608,6 +9787,7 @@ exports.CircuitOpenError = CircuitOpenError;
9608
9787
  exports.CompositeFeatureFlagBackend = CompositeFeatureFlagBackend;
9609
9788
  exports.ConflictException = ConflictException;
9610
9789
  exports.DEFAULT_LOCALE = DEFAULT_LOCALE;
9790
+ exports.EmailProvider = EmailProvider;
9611
9791
  exports.EmailUtils = EmailUtils;
9612
9792
  exports.EnvFeatureFlagBackend = EnvFeatureFlagBackend;
9613
9793
  exports.EventStream = EventStream;
@@ -9626,6 +9806,7 @@ exports.MemoryFeatureFlagBackend = MemoryFeatureFlagBackend;
9626
9806
  exports.MemorySessionStore = MemorySessionStore;
9627
9807
  exports.MemoryThrottleBackend = MemoryThrottleBackend;
9628
9808
  exports.MessageCatalog = MessageCatalog;
9809
+ exports.MessagingHub = MessagingHub;
9629
9810
  exports.MetricsUtils = MetricsUtils;
9630
9811
  exports.MfaService = MfaService;
9631
9812
  exports.NotFoundException = NotFoundException;
@@ -9664,6 +9845,7 @@ exports.baseAppSettingsSchema = baseAppSettingsSchema;
9664
9845
  exports.baseAppSettingsShape = baseAppSettingsShape;
9665
9846
  exports.baseResponseSchema = baseResponseSchema;
9666
9847
  exports.bearerToken = bearerToken;
9848
+ exports.broadcastText = broadcastText;
9667
9849
  exports.buildContentDisposition = buildContentDisposition;
9668
9850
  exports.cached = cached3;
9669
9851
  exports.cepField = cepField;
@@ -9716,6 +9898,7 @@ exports.makeSessionMiddleware = makeSessionMiddleware;
9716
9898
  exports.makeTwilioWebhookRouter = makeTwilioWebhookRouter;
9717
9899
  exports.makeUnhandledExceptionHandler = makeUnhandledExceptionHandler;
9718
9900
  exports.makeWhatsAppWebhookRouter = makeWhatsAppWebhookRouter;
9901
+ exports.mfaChallengeSchema = mfaChallengeSchema;
9719
9902
  exports.mfaCodeSchema = mfaCodeSchema;
9720
9903
  exports.mfaEnrollResponseSchema = mfaEnrollResponseSchema;
9721
9904
  exports.modifyDict = modifyDict;