@dunx/create-app 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92,7 +92,7 @@ var FEATURES = [
92
92
  summary: "CRUD routes with zod validation. The smallest real feature.",
93
93
  requires: [],
94
94
  module: { klass: "NotesModule", from: "./notes/notes.module.js" },
95
- dependencies: ["zod"],
95
+ dependencies: ["@dunx/openapi", "zod"],
96
96
  config: []
97
97
  },
98
98
  {
@@ -128,7 +128,7 @@ var FEATURES = [
128
128
  summary: "drizzle over bun:sqlite, with a schema, seeds and migrations.",
129
129
  requires: [],
130
130
  module: { klass: "DatabaseModule", from: "./database/database.module.js" },
131
- dependencies: ["@dunx/infra", "drizzle-orm"],
131
+ dependencies: ["@dunx/infra", "drizzle-orm", "zod"],
132
132
  config: ["database"]
133
133
  },
134
134
  {
@@ -155,7 +155,7 @@ var FEATURES = [
155
155
  summary: "Bun.RedisClient behind a session store, degrading when absent.",
156
156
  requires: [],
157
157
  module: { klass: "CacheModule", from: "./cache/cache.module.js" },
158
- dependencies: ["@dunx/infra"],
158
+ dependencies: ["@dunx/infra", "zod"],
159
159
  config: ["redis"],
160
160
  service: "Redis or Valkey"
161
161
  },
@@ -175,7 +175,7 @@ var FEATURES = [
175
175
  summary: "Bun.Image resizing and format conversion behind a route.",
176
176
  requires: [],
177
177
  module: { klass: "PicturesModule", from: "./pictures/pictures.module.js" },
178
- dependencies: ["@dunx/infra"],
178
+ dependencies: ["@dunx/infra", "zod"],
179
179
  config: ["images"]
180
180
  },
181
181
  {
@@ -184,7 +184,7 @@ var FEATURES = [
184
184
  summary: "Uploads and downloads on Bun.file, with a workspace root.",
185
185
  requires: [],
186
186
  module: { klass: "StorageModule", from: "./storage/storage.module.js" },
187
- dependencies: ["@dunx/infra"],
187
+ dependencies: ["@dunx/infra", "zod"],
188
188
  config: []
189
189
  },
190
190
  {
@@ -193,10 +193,28 @@ var FEATURES = [
193
193
  summary: "bullmq queues and a worker, over Bun.RedisClient.",
194
194
  requires: ["images"],
195
195
  module: { klass: "JobsModule", from: "./jobs/jobs.module.js" },
196
- dependencies: ["@dunx/infra", "bullmq", "ioredis"],
196
+ dependencies: ["@dunx/infra", "bullmq", "ioredis", "zod"],
197
197
  config: ["redis"],
198
198
  service: "Redis or Valkey"
199
199
  },
200
+ {
201
+ name: "dashboard",
202
+ source: "dashboard",
203
+ summary: "bull-board at /queues, over the queue the jobs feature publishes to.",
204
+ requires: ["jobs"],
205
+ module: {
206
+ klass: "DashboardModule",
207
+ from: "./dashboard/dashboard.module.js"
208
+ },
209
+ dependencies: [
210
+ "@dunx/queue-dashboard",
211
+ "@bull-board/api",
212
+ "@bull-board/ui",
213
+ "ejs"
214
+ ],
215
+ config: ["appName"],
216
+ service: "Redis or Valkey"
217
+ },
200
218
  {
201
219
  name: "health",
202
220
  source: "health",
@@ -301,7 +319,10 @@ var THIRD_PARTY = Object.freeze({
301
319
  "drizzle-orm": "^0.45.2",
302
320
  "better-auth": "^1.6.25",
303
321
  bullmq: "^6.0.5",
304
- ioredis: "^6.0.0"
322
+ ioredis: "^6.0.0",
323
+ "@bull-board/api": "^8.5.0",
324
+ "@bull-board/ui": "^8.5.0",
325
+ ejs: "^3.1.10"
305
326
  });
306
327
  var versionOf = (dep) => THIRD_PARTY[dep] ?? "latest";
307
328
  var appModule = (name, features) => {
@@ -405,8 +426,10 @@ var bootstrap = (name, features) => {
405
426
  const openapi = has(features, "openapi");
406
427
  const websockets = has(features, "websockets");
407
428
  const http = has(features, "http");
429
+ const dashboard = has(features, "dashboard");
408
430
  const imports = [
409
431
  `import { HttpFactory${websockets ? ", RedisRelay" : ""}, type HttpApp } from '@dunx/http';`,
432
+ ...dashboard ? ["import { QueueDashboardMiddleware } from '@dunx/queue-dashboard';"] : [],
410
433
  ...openapi ? ["import { OpenApiModule } from '@dunx/openapi';"] : [],
411
434
  "import { AppModule } from './app.module.js';",
412
435
  `import { ${[
@@ -430,6 +453,12 @@ var bootstrap = (name, features) => {
430
453
  ] : [];
431
454
  const shaping = [
432
455
  "app.setGlobalPrefix('api');",
456
+ ...dashboard ? [
457
+ "// Global middleware, so it also runs in front of the unmatched-path",
458
+ "// fallback - which is where the board's paths land, since no controller",
459
+ "// declares them.",
460
+ "app.use(QueueDashboardMiddleware);"
461
+ ] : [],
433
462
  ...http ? [
434
463
  "app.use(RequestLoggerMiddleware);",
435
464
  "app.set('trust proxy', true);",
@@ -694,5 +723,5 @@ var scaffold = async (options) => {
694
723
 
695
724
  export { FEATURES, featureNames, impliedBy, TEMPLATES, VERSION_PLACEHOLDER, ScaffoldError, scaffold };
696
725
 
697
- //# debugId=ABE556EA5FD94D1364756E2164756E21
698
- //# sourceMappingURL=chunk-jgd5dmqh.js.map
726
+ //# debugId=FA7FFB8B72BB3F6B64756E2164756E21
727
+ //# sourceMappingURL=chunk-g157qb1g.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/features.ts", "../src/scaffold.ts", "../src/generate.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * The features a generated app can be composed from, each one a directory of\n * `examples/full` - the example CI boots and tours on every push.\n *\n * That is the whole point of sourcing them there rather than writing starter code\n * here: a template nobody runs rots, and this repo already runs `examples/full`\n * end to end. `bun run sync:templates` copies the directories in and\n * `features.test.ts` fails if a copy drifts, so what gets scaffolded is what CI\n * proved works.\n *\n * What is **not** copied is the wiring: `app.module.ts`, `config.ts`,\n * `bootstrap.ts` and `main.ts` in the full example name every feature at once, so\n * they are generated from the selection instead. See `generate.ts`.\n */\nexport interface Feature {\n /** Flag name, and the directory under `templates/features/`. */\n readonly name: string;\n /** The directory in `examples/full/src` this mirrors. */\n readonly source: string;\n readonly summary: string;\n /** Features this one imports from, pulled in automatically. */\n readonly requires: readonly string[];\n /** The module class to import, and the file it comes from. */\n readonly module: { readonly klass: string; readonly from: string };\n /** Runtime dependencies this feature adds to the generated manifest. */\n readonly dependencies: readonly string[];\n /** Config groups this feature reads, contributed to the generated config. */\n readonly config: readonly string[];\n /**\n * A service that has to be running for the feature to do anything. Named so the\n * prompt can say so and the generated README can list it, rather than the app\n * failing in a way the reader has to diagnose.\n */\n readonly service?: string;\n}\n\n/**\n * Config groups, keyed by the name a feature asks for. `env` is what lands in\n * `.env.example`, `schema` the zod line, `field` the `AppConfig` member and `map`\n * how the flat variable becomes the shaped one - the four things\n * `examples/full/src/config.ts` states for every group at once, split so a\n * selection can state only its own.\n */\nexport interface ConfigGroup {\n readonly schema: readonly string[];\n readonly field: string;\n readonly map: string;\n readonly env: readonly { readonly name: string; readonly value: string }[];\n}\n\nexport const CONFIG_GROUPS: Readonly<Record<string, ConfigGroup>> =\n Object.freeze({\n port: {\n schema: [\n 'PORT: z.coerce.number().int().min(0).max(65535).default(3000),',\n ],\n field: 'readonly port: number;',\n map: 'port: value.PORT,',\n env: [{ name: 'PORT', value: '3000' }],\n },\n appName: {\n schema: [],\n field: 'readonly appName: string;',\n map: \"appName: '__DUNX_APP_NAME__',\",\n env: [],\n },\n log: {\n schema: [\n 'LOG_LEVEL: z.enum(LogLevel).default(LogLevel.INFO),',\n '/** Unset means console only. Set it to also append JSON to a rotating file. */',\n 'LOG_FILE: z.string().optional(),',\n ],\n field:\n 'readonly log: { readonly level: LogLevel; readonly file: string | undefined };',\n map: 'log: { level: value.LOG_LEVEL, file: value.LOG_FILE },',\n env: [{ name: 'LOG_LEVEL', value: 'info' }],\n },\n corsOrigin: {\n schema: [\"CORS_ORIGIN: z.string().default('https://example.com'),\"],\n field: 'readonly corsOrigin: string;',\n map: 'corsOrigin: value.CORS_ORIGIN,',\n env: [{ name: 'CORS_ORIGIN', value: 'https://example.com' }],\n },\n database: {\n schema: [\n '/** `:memory:` needs no server and leaves nothing behind, so restarts are clean. */',\n \"DATABASE_FILE: z.string().default(':memory:'),\",\n ],\n field: 'readonly database: { readonly file: string };',\n map: 'database: { file: value.DATABASE_FILE },',\n env: [{ name: 'DATABASE_FILE', value: ':memory:' }],\n },\n redis: {\n schema: [\n '/** Absent is fine: the cache routes report themselves degraded instead of failing. */',\n 'REDIS_URL: z.string().optional(),',\n ],\n field: 'readonly redis: { readonly url: string | undefined };',\n map: 'redis: { url: value.REDIS_URL },',\n env: [{ name: 'REDIS_URL', value: 'redis://localhost:6379' }],\n },\n images: {\n schema: [\n 'IMAGE_QUALITY: z.coerce.number().int().min(1).max(100).default(82),',\n ],\n field: 'readonly images: { readonly quality: number };',\n map: 'images: { quality: value.IMAGE_QUALITY },',\n env: [{ name: 'IMAGE_QUALITY', value: '82' }],\n },\n auth: {\n schema: [\n '/** better-auth signs session cookies with this. 32 characters is its own minimum. */',\n \"AUTH_SECRET: z.string().min(32).default('dunx-development-secret-not-for-production'),\",\n ],\n field: 'readonly auth: { readonly secret: string };',\n map: 'auth: { secret: value.AUTH_SECRET },',\n env: [\n {\n name: 'AUTH_SECRET',\n value: 'change-me-to-at-least-32-characters-long',\n },\n ],\n },\n seedUsers: {\n schema: [],\n field: 'readonly seedUsers: readonly string[];',\n map: \"seedUsers: ['ada', 'grace'],\",\n env: [],\n },\n authorization: {\n schema: [],\n field: 'readonly authorization: { readonly enabled: boolean };',\n map: 'authorization: { enabled: true },',\n env: [],\n },\n });\n\n/** Always present, whatever is selected: the port and the logger need them. */\nexport const BASE_CONFIG: readonly string[] = ['appName', 'port', 'log'];\n\nexport const FEATURES: readonly Feature[] = [\n {\n name: 'notes',\n source: 'notes',\n summary: 'CRUD routes with zod validation. The smallest real feature.',\n requires: [],\n module: { klass: 'NotesModule', from: './notes/notes.module.js' },\n dependencies: ['@dunx/openapi', 'zod'],\n config: [],\n },\n {\n name: 'openapi',\n source: 'docs',\n summary: 'OpenAPI 3.1 from the routes own schemas, plus the explorer page.',\n requires: [],\n module: { klass: 'DocsModule', from: './docs/docs.module.js' },\n dependencies: ['@dunx/openapi', 'zod'],\n config: [],\n },\n {\n name: 'http',\n source: 'http',\n summary: 'CORS, a request-logging middleware and error mapping.',\n requires: [],\n module: { klass: 'HttpModule', from: './http/http.module.js' },\n dependencies: [],\n config: ['corsOrigin'],\n },\n {\n name: 'guards',\n source: 'guards',\n summary:\n 'Route guards with @Roles and @Public, and a protected controller.',\n requires: [],\n module: { klass: 'GuardsModule', from: './guards/guards.module.js' },\n dependencies: ['zod'],\n config: ['authorization'],\n },\n {\n name: 'database',\n source: 'database',\n summary: 'drizzle over bun:sqlite, with a schema, seeds and migrations.',\n requires: [],\n module: { klass: 'DatabaseModule', from: './database/database.module.js' },\n dependencies: ['@dunx/infra', 'drizzle-orm', 'zod'],\n config: ['database'],\n },\n {\n name: 'users',\n source: 'users',\n summary: 'A repository, a service and validated routes over the database.',\n requires: ['database'],\n module: { klass: 'UsersModule', from: './users/users.module.js' },\n dependencies: ['@dunx/infra', 'drizzle-orm', 'zod'],\n config: ['appName', 'seedUsers'],\n },\n {\n name: 'auth',\n source: 'auth',\n summary: 'better-auth mounted, with SessionGuard and an audit trail.',\n requires: ['database'],\n module: { klass: 'AccountsModule', from: './auth/auth.module.js' },\n dependencies: ['@dunx/auth', 'better-auth', 'drizzle-orm'],\n config: ['auth', 'port'],\n },\n {\n name: 'cache',\n source: 'cache',\n summary: 'Bun.RedisClient behind a session store, degrading when absent.',\n requires: [],\n module: { klass: 'CacheModule', from: './cache/cache.module.js' },\n dependencies: ['@dunx/infra', 'zod'],\n config: ['redis'],\n service: 'Redis or Valkey',\n },\n {\n name: 'websockets',\n source: 'chat',\n summary: 'A @Gateway with @OnMessage events, PubSub and a Redis relay.',\n requires: [],\n module: { klass: 'ChatModule', from: './chat/chat.module.js' },\n dependencies: ['@dunx/infra'],\n config: [],\n service: 'Redis or Valkey, for multi-node fan-out only',\n },\n {\n name: 'images',\n source: 'pictures',\n summary: 'Bun.Image resizing and format conversion behind a route.',\n requires: [],\n module: { klass: 'PicturesModule', from: './pictures/pictures.module.js' },\n dependencies: ['@dunx/infra', 'zod'],\n config: ['images'],\n },\n {\n name: 'files',\n source: 'storage',\n summary: 'Uploads and downloads on Bun.file, with a workspace root.',\n requires: [],\n module: { klass: 'StorageModule', from: './storage/storage.module.js' },\n dependencies: ['@dunx/infra', 'zod'],\n config: [],\n },\n {\n name: 'jobs',\n source: 'jobs',\n summary: 'bullmq queues and a worker, over Bun.RedisClient.',\n requires: ['images'],\n module: { klass: 'JobsModule', from: './jobs/jobs.module.js' },\n dependencies: ['@dunx/infra', 'bullmq', 'ioredis', 'zod'],\n config: ['redis'],\n service: 'Redis or Valkey',\n },\n {\n name: 'dashboard',\n source: 'dashboard',\n summary:\n 'bull-board at /queues, over the queue the jobs feature publishes to.',\n requires: ['jobs'],\n module: {\n klass: 'DashboardModule',\n from: './dashboard/dashboard.module.js',\n },\n dependencies: [\n '@dunx/queue-dashboard',\n '@bull-board/api',\n '@bull-board/ui',\n 'ejs',\n ],\n config: ['appName'],\n service: 'Redis or Valkey',\n },\n {\n name: 'health',\n source: 'health',\n summary: 'One endpoint reporting which parts are live and which degraded.',\n requires: ['cache', 'database'],\n module: { klass: 'HealthModule', from: './health/health.module.js' },\n dependencies: ['@dunx/infra'],\n config: ['appName'],\n },\n];\n\nexport const featureNames: readonly string[] = FEATURES.map(\n (feature) => feature.name,\n);\n\nconst byName = new Map(FEATURES.map((feature) => [feature.name, feature]));\n\nexport class UnknownFeatureError extends Error {\n override readonly name = 'UnknownFeatureError';\n}\n\n/**\n * The selection plus everything it requires, in **import order** - which is\n * construction order, and shutdown runs in reverse. A feature is emitted after\n * everything it requires, so the database outlives the features reading it, the\n * same ordering `examples/full/src/app.module.ts` states by hand.\n *\n * Depth-first over `requires`, with a visited set, so a diamond resolves once and\n * the result is stable whatever order the caller asked in.\n */\nexport const resolveFeatures = (\n requested: readonly string[],\n): readonly Feature[] => {\n const unknown = requested.filter((name) => !byName.has(name));\n if (unknown.length > 0) {\n throw new UnknownFeatureError(\n `Unknown feature${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}. ` +\n `Available: ${featureNames.join(', ')}.`,\n );\n }\n\n const ordered: Feature[] = [];\n const seen = new Set<string>();\n const rank = new Map(FEATURES.map((feature, at) => [feature.name, at]));\n\n const visit = (name: string): void => {\n if (seen.has(name)) return;\n seen.add(name);\n const feature = byName.get(name);\n if (!feature) return;\n // Requirements in **registry order**, not in the order this feature happens to\n // list them: two independent requirements would otherwise come out in the\n // order they were typed, which is not a statement about construction order and\n // would make `requires: ['cache', 'database']` build the cache first.\n for (const required of [...feature.requires].sort(\n (left, right) => (rank.get(left) ?? 0) - (rank.get(right) ?? 0),\n )) {\n visit(required);\n }\n ordered.push(feature);\n };\n\n // Registry order, not request order, so two runs asking for the same set in a\n // different order generate byte-identical files.\n for (const feature of FEATURES) {\n if (requested.includes(feature.name)) visit(feature.name);\n }\n\n return ordered;\n};\n\n/** Which of the resolved features the caller did not ask for. */\nexport const impliedBy = (\n requested: readonly string[],\n resolved: readonly Feature[],\n): readonly string[] =>\n resolved\n .map((feature) => feature.name)\n .filter((name) => !requested.includes(name));\n",
6
+ "import { existsSync, readdirSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Glob } from 'bun';\nimport { resolveFeatures, type Feature } from './features.js';\nimport {\n appModule,\n bootstrap,\n config,\n configGroupsFor,\n envExample,\n main,\n manifest,\n readme,\n worker,\n} from './generate.js';\n\n/** The templates that ship with the package, as `templates/<name>/`. */\nexport const TEMPLATES = Object.freeze(['minimal'] as const);\nexport type TemplateName = (typeof TEMPLATES)[number];\n\n/**\n * Every `@dunx/*` version in a template manifest is this placeholder. Versioning\n * is lockstep, so the right version to install is whatever version of\n * `@dunx/create-app` is doing the scaffolding - resolved at run time rather than\n * written into the template, which would go stale on the next release.\n */\nexport const VERSION_PLACEHOLDER = '__DUNX_VERSION__';\n\n/**\n * Names a package cannot ship as-is, so they ship prefixed and are renamed on write.\n *\n * `.gitignore` is the known one: npm renames a published copy to `.npmignore`.\n *\n * **`bunfig.toml` is the one that was silently missing.** It is stripped from the\n * tarball entirely - presumably so a dependency cannot hijack the installing\n * project's Bun config - and it is the single file dunx asks an app to have. Every\n * app scaffolded from a published `@dunx/create-app` therefore had no\n * `@dunx/transform/preload`, and failed at boot with the very error the guide\n * describes. Measured with `bun pm pack`, and `pack.test.ts` now measures it on\n * every run rather than trusting this comment.\n */\nconst RENAMED = Object.freeze({\n _gitignore: '.gitignore',\n '_bunfig.toml': 'bunfig.toml',\n});\n\n/**\n * Entries that do not make a directory non-empty for scaffolding purposes.\n *\n * `.git` is the one that matters: `git init` then scaffold into the repo is the\n * documented way to start, and refusing it blocks the flow outright. `.gitkeep`\n * exists only so git can track an otherwise empty directory, so it *means* empty.\n * `.DS_Store` appears from merely opening the folder in Finder. `LICENSE` is what\n * GitHub's create-a-repository flow leaves in a fresh clone.\n *\n * The list is deliberately short, and the test for it is whether the template\n * writes that name. It does not write any of these four, so ignoring them can\n * never destroy anything. `.gitignore` and `README.md` are excluded for exactly\n * that reason: the template writes both, and silently overwriting a user's copy\n * is what `--force` exists to gate.\n */\nconst IGNORED_WHEN_EMPTY: ReadonlySet<string> = new Set([\n '.DS_Store',\n '.git',\n '.gitkeep',\n 'LICENSE',\n]);\n\nexport interface ScaffoldOptions {\n /** Directory to create. Relative paths resolve against `cwd`. */\n readonly target: string;\n /** Package name for the generated app. Defaults to the target's basename. */\n readonly name?: string;\n readonly template?: TemplateName;\n /**\n * Features to compose the app from, by name. Anything they require is pulled in.\n *\n * Passing any switches from copying a fixed template to generating the wiring\n * around the chosen feature directories - see `generate.ts`. An empty list, or\n * none at all, scaffolds `template` unchanged, so the default behaviour is exactly\n * what it was.\n */\n readonly features?: readonly string[];\n /** Write into a directory that already has files in it. */\n readonly force?: boolean;\n readonly cwd?: string;\n /** Overrides the version written into the generated manifest. */\n readonly version?: string;\n}\n\nexport interface ScaffoldResult {\n readonly directory: string;\n readonly name: string;\n readonly template: TemplateName | 'composed';\n /** Resolved feature names, in import order. Empty for a fixed template. */\n readonly features: readonly string[];\n readonly files: readonly string[];\n}\n\nexport class ScaffoldError extends Error {\n override readonly name = 'ScaffoldError';\n}\n\n/**\n * `dist/index.js` and `dist/cli.js` both sit one level under the package root, so\n * `../templates` resolves the same from either. In the source tree it resolves\n * from `src/`, which is the same depth - so tests exercise the real path rather\n * than a special case.\n *\n * `fileURLToPath`, not `new URL(...).pathname`: the latter stays percent-encoded,\n * so an install under a directory with a space in it looks for `space%20test/`\n * and reports the template missing. On Windows it is worse - it yields a\n * leading-slash, drive-lettered path that resolves nowhere.\n */\nconst templatesRoot = (): string =>\n resolve(dirname(fileURLToPath(import.meta.url)), '..', 'templates');\n\n/**\n * npm forbids uppercase and a leading dot or underscore, and a scope is legal.\n * Checked here because the failure would otherwise surface as a confusing\n * `bun install` error inside a directory the user just created.\n */\nconst isValidPackageName = (name: string): boolean =>\n /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);\n\nconst readPackageVersion = async (): Promise<string> => {\n const file = Bun.file(join(templatesRoot(), '..', 'package.json'));\n const json = (await file.json()) as { version?: string };\n return json.version ?? '0.0.0';\n};\n\n/** Placeholders are substituted in every written file, generated or copied. */\nconst fill = (contents: string, name: string, version: string): string =>\n contents\n .replaceAll(VERSION_PLACEHOLDER, version)\n .replaceAll('__DUNX_APP_NAME__', name);\n\n/**\n * The four files a subset of features cannot copy, because the full example states\n * every feature at once in each of them.\n */\nconst generated = (\n name: string,\n features: readonly Feature[],\n): Readonly<Record<string, string>> => {\n const groups = configGroupsFor(features);\n const files: Record<string, string> = {\n 'package.json': manifest(features),\n 'README.md': readme(name, features),\n '.env.example': envExample(groups),\n 'src/main.ts': main(name, features),\n 'src/bootstrap.ts': bootstrap(name, features),\n 'src/app.module.ts': appModule(name, features),\n 'src/config.ts': config(name, groups),\n };\n if (features.some((feature) => feature.name === 'jobs')) {\n files['src/worker.ts'] = worker(name);\n }\n return files;\n};\n\nexport const scaffold = async (\n options: ScaffoldOptions,\n): Promise<ScaffoldResult> => {\n const template = options.template ?? 'minimal';\n if (!TEMPLATES.includes(template)) {\n throw new ScaffoldError(\n `Unknown template \"${template}\". Available: ${TEMPLATES.join(', ')}.`,\n );\n }\n\n // Resolved before anything is written, so an unknown feature name fails with the\n // list of real ones rather than half a directory.\n const requested = options.features ?? [];\n let features: readonly Feature[] = [];\n try {\n features = resolveFeatures(requested);\n } catch (error) {\n throw new ScaffoldError(\n error instanceof Error ? error.message : String(error),\n );\n }\n const composing = features.length > 0;\n\n const directory = resolve(options.cwd ?? process.cwd(), options.target);\n const name = options.name ?? basename(directory);\n\n if (!isValidPackageName(name)) {\n throw new ScaffoldError(\n `\"${name}\" is not a usable package name. Pass --name to choose one.`,\n );\n }\n\n if (existsSync(directory) && options.force !== true) {\n const blocking = readdirSync(directory).filter(\n (entry) => !IGNORED_WHEN_EMPTY.has(entry),\n );\n if (blocking.length > 0) {\n // Naming what blocked it, because `.git` used to block it and the message\n // gave no way to tell that from a directory of real work.\n const shown = blocking.sort().slice(0, 3).join(', ');\n const rest = blocking.length > 3 ? `, +${blocking.length - 3} more` : '';\n throw new ScaffoldError(\n `${directory} is not empty (${shown}${rest}). ` +\n `Pass --force to write into it anyway.`,\n );\n }\n }\n\n const version = options.version ?? `^${await readPackageVersion()}`;\n const written: string[] = [];\n\n /** Copies a directory of the package's own templates into the new app. */\n const copyTree = async (from: string, into: string): Promise<void> => {\n // `**/*` with `dot: true` so a template can carry a dotfile that npm did not\n // rename; the explicit `_gitignore` mapping covers the one that it does.\n for await (const relative of new Glob('**/*').scan({\n cwd: from,\n dot: true,\n onlyFiles: true,\n })) {\n const base = relative.split('/').at(-1) ?? relative;\n const renamed = (RENAMED as Record<string, string | undefined>)[base];\n const target = join(\n into,\n renamed === undefined ? relative : join(dirname(relative), renamed),\n );\n\n const contents = await Bun.file(join(from, relative)).text();\n // `Bun.write` creates parent directories, so there is no mkdir pass.\n await Bun.write(join(directory, target), fill(contents, name, version));\n written.push(target);\n }\n };\n\n if (!composing) {\n const source = join(templatesRoot(), template);\n if (!existsSync(source)) {\n throw new ScaffoldError(\n `Template \"${template}\" is missing from ${source}.`,\n );\n }\n await copyTree(source, '.');\n return {\n directory,\n name,\n template,\n features: [],\n files: written.sort(),\n };\n }\n\n // The base carries what every composed app needs and no feature owns: the\n // tsconfig, the transform preload, and the gitignore.\n const base = join(templatesRoot(), 'base');\n if (!existsSync(base)) {\n throw new ScaffoldError(\n `The base template is missing from ${base}. Run \\`bun run sync:templates\\`.`,\n );\n }\n await copyTree(base, '.');\n\n for (const feature of features) {\n const from = join(templatesRoot(), 'features', feature.source);\n if (!existsSync(from)) {\n throw new ScaffoldError(\n `Feature \"${feature.name}\" is missing from ${from}. ` +\n 'Run `bun run sync:templates`.',\n );\n }\n await copyTree(from, join('src', feature.source));\n }\n\n for (const [target, contents] of Object.entries(generated(name, features))) {\n await Bun.write(join(directory, target), fill(contents, name, version));\n written.push(target);\n }\n\n return {\n directory,\n name,\n template: 'composed',\n features: features.map((feature) => feature.name),\n files: written.sort(),\n };\n};\n",
7
+ "import { BASE_CONFIG, CONFIG_GROUPS, type Feature } from './features.js';\n\n/**\n * The wiring, generated from a feature selection.\n *\n * The full example states every feature at once in four files - `app.module.ts`,\n * `config.ts`, `bootstrap.ts` and `main.ts` - so those are the ones a subset cannot\n * copy. Everything else is the feature's own directory, copied verbatim.\n *\n * Generated rather than assembled by editing a copy on purpose: an edited copy\n * cannot be checked against the example it came from, and the byte-for-byte parity\n * test is what stops the vendored features drifting from the app CI actually boots.\n */\nconst HEADER = (name: string): string =>\n `// Generated by @dunx/create-app for ${name}. Yours to edit.\\n`;\n\nconst uniq = (values: readonly string[]): string[] => [...new Set(values)];\n\n/** Every config group the selection needs, base first, in a stable order. */\nexport const configGroupsFor = (\n features: readonly Feature[],\n): readonly string[] => {\n const wanted = uniq([\n ...BASE_CONFIG,\n ...features.flatMap((feature) => feature.config),\n ]);\n return Object.keys(CONFIG_GROUPS).filter((group) => wanted.includes(group));\n};\n\nexport const dependenciesFor = (\n features: readonly Feature[],\n): readonly string[] =>\n uniq([\n '@dunx/core',\n '@dunx/http',\n '@dunx/transform',\n '@dunx/infra',\n ...features.flatMap((feature) => feature.dependencies),\n ]).sort();\n\nconst DUNX = /^@dunx\\//;\n\nexport const manifest = (features: readonly Feature[]): string => {\n const deps = dependenciesFor(features);\n const dependencies: Record<string, string> = {};\n for (const dep of deps) {\n dependencies[dep] = DUNX.test(dep) ? '__DUNX_VERSION__' : versionOf(dep);\n }\n\n const scripts: Record<string, string> = {\n start: 'bun src/main.ts',\n test: 'bun test',\n typecheck: 'tsc --noEmit',\n };\n // A queue needs a process to drain it, and it is not the web one.\n if (features.some((feature) => feature.name === 'jobs')) {\n scripts['worker'] = 'bun src/worker.ts';\n }\n\n return `${JSON.stringify(\n {\n name: '__DUNX_APP_NAME__',\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts,\n dependencies,\n devDependencies: {\n '@dunx/testing': '__DUNX_VERSION__',\n '@types/bun': '>=1.3.0',\n typescript: '^5.7.0',\n },\n engines: { bun: '>=1.3.0' },\n },\n null,\n 2,\n )}\\n`;\n};\n\n/**\n * Third-party ranges, pinned here rather than read off `examples/full` at run time:\n * the generated app installs from npm and the example installs from the workspace,\n * so the example's manifest is not a statement about what a consumer should take.\n * `features.test.ts` checks these against the example's, which is what stops them\n * silently diverging from a version combination that is actually exercised.\n */\nexport const THIRD_PARTY: Readonly<Record<string, string>> = Object.freeze({\n zod: '^4.4.3',\n 'drizzle-orm': '^0.45.2',\n 'better-auth': '^1.6.25',\n bullmq: '^6.0.5',\n ioredis: '^6.0.0',\n '@bull-board/api': '^8.5.0',\n '@bull-board/ui': '^8.5.0',\n ejs: '^3.1.10',\n});\n\nconst versionOf = (dep: string): string => THIRD_PARTY[dep] ?? 'latest';\n\nexport const appModule = (\n name: string,\n features: readonly Feature[],\n): string => {\n const needsLogger = true;\n const imports = [\n \"import { ConfigModule, Module } from '@dunx/core';\",\n ...(needsLogger\n ? [\"import { LoggerModule } from '@dunx/infra/logger';\"]\n : []),\n \"import { AppConfigService, validate } from './config.js';\",\n ...features.map(\n (feature) =>\n `import { ${feature.module.klass} } from '${feature.module.from}';`,\n ),\n ];\n\n const moduleImports = [\n 'ConfigModule.forRoot({ validate, as: AppConfigService }),',\n '// The level comes from the validated config, which is the one thing a',\n '// zero-argument `forRoot` function cannot reach.',\n 'LoggerModule.forRootAsync(',\n ' {',\n ' useFactory: (config: AppConfigService) => ({',\n \" name: config.get('appName'),\",\n \" level: config.get('log').level,\",\n ' }),',\n ' inject: [AppConfigService] as const,',\n ' },',\n ' { captureGlobalErrors: true },',\n '),',\n ...features.map((feature) => `${feature.module.klass},`),\n ];\n\n return `${HEADER(name)}${imports.join('\\n')}\n\n/**\n * Import order is construction order, and shutdown runs in reverse - so config and\n * the logger are built first and torn down last, and anything a feature depends on\n * outlives it.\n */\n@Module({\n imports: [\n${moduleImports.map((line) => ` ${line}`).join('\\n')}\n ],\n})\nexport class AppModule {}\n`;\n};\n\nexport const config = (name: string, groups: readonly string[]): string => {\n const chosen = groups\n .map((group) => [group, CONFIG_GROUPS[group]] as const)\n .filter(\n (entry): entry is [string, (typeof CONFIG_GROUPS)[string]] =>\n entry[1] !== undefined,\n );\n\n const schema = chosen.flatMap(([, group]) => group.schema);\n const needsLogLevel = groups.includes('log');\n\n return `${HEADER(name)}import { ConfigService, type ConfigSource${\n needsLogLevel ? ', LogLevel' : ''\n } } from '@dunx/core';\nimport { z } from 'zod';\n\n/**\n * One validation function, which is the whole \\`ConfigModule\\` contract. dunx does\n * not pick the library - this is zod because the routes already use it, and a\n * hand-written function that throws would work identically.\n *\n * \\`.default()\\` is where a value comes from when the variable is unset, so a clean\n * checkout boots with no \\`.env\\` at all. Bun loads \\`.env\\` and \\`.env.local\\` itself,\n * so there is nothing here that reads a file.\n */\nconst envSchema = z.object({\n${schema.map((line) => ` ${line}`).join('\\n')}\n});\n\nexport interface AppConfig {\n${chosen.map(([, group]) => ` ${group.field}`).join('\\n')}\n}\n\n/**\n * One name for the typed config everywhere. A subclass rather than\n * \\`ConfigService<AppConfig>\\` at each site because a factory's \\`inject: [...]\\`\n * carries no type argument - the class does, and it is a real runtime value, so it\n * is both a precise token and a usable constructor annotation.\n */\nexport class AppConfigService extends ConfigService<AppConfig> {}\n\n/** The one broker channel the websocket relay carries every topic on. */\nexport const RELAY_CHANNEL = '__DUNX_APP_NAME__:ws';\n\n/** Flat variables in, a shaped object out. Nothing downstream reads \\`Bun.env\\`. */\nexport const validate = (env: ConfigSource): AppConfig => {\n const parsed = envSchema.safeParse(env);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => \\`\\${issue.path.join('.') || '(root)'}: \\${issue.message}\\`)\n .join('\\\\n - ');\n throw new Error(\\`Configuration is invalid:\\\\n - \\${issues}\\`);\n }\n const value = parsed.data;\n\n return {\n${chosen.map(([, group]) => ` ${group.map}`).join('\\n')}\n };\n};\n`;\n};\n\nconst has = (features: readonly Feature[], name: string): boolean =>\n features.some((feature) => feature.name === name);\n\nexport const bootstrap = (\n name: string,\n features: readonly Feature[],\n): string => {\n const openapi = has(features, 'openapi');\n const websockets = has(features, 'websockets');\n const http = has(features, 'http');\n\n const dashboard = has(features, 'dashboard');\n const imports = [\n `import { HttpFactory${websockets ? ', RedisRelay' : ''}, type HttpApp } from '@dunx/http';`,\n ...(dashboard\n ? [\"import { QueueDashboardMiddleware } from '@dunx/queue-dashboard';\"]\n : []),\n ...(openapi ? [\"import { OpenApiModule } from '@dunx/openapi';\"] : []),\n \"import { AppModule } from './app.module.js';\",\n `import { ${[\n ...(http ? ['AppConfigService'] : []),\n ...(websockets ? ['RELAY_CHANNEL'] : []),\n ].join(', ')} } from './config.js';`,\n ...(http\n ? [\"import { RequestLoggerMiddleware } from './http/request-log.js';\"]\n : []),\n ].filter((line) => !line.includes('{ }'));\n\n const root = openapi\n ? `OpenApiModule.forRoot({\n title: '__DUNX_APP_NAME__',\n version: '0.1.0',\n root: AppModule,\n })`\n : 'AppModule';\n\n const options = websockets\n ? [\n '// Multi-node websocket fan-out on `Bun.RedisClient`, so it costs no',\n '// dependency. With no Redis running this degrades to single-process',\n '// behaviour, logs one warning, and the app still boots.',\n 'websocket: { idleTimeout: 30 },',\n 'relay: new RedisRelay({ connectionTimeout: 500 }),',\n 'relayChannel: RELAY_CHANNEL,',\n ]\n : [];\n\n /**\n * Everything between `create()` and `listen()`. The prefix is set whatever is\n * selected, because the copied controllers declare paths under it and the URLs\n * `main.ts` prints assume it.\n *\n * `app.use` takes the middleware **class**, not an instance: the container\n * constructs it, which is what lets it have dependencies of its own.\n */\n const shaping = [\n \"app.setGlobalPrefix('api');\",\n ...(dashboard\n ? [\n '// Global middleware, so it also runs in front of the unmatched-path',\n \"// fallback - which is where the board's paths land, since no controller\",\n '// declares them.',\n 'app.use(QueueDashboardMiddleware);',\n ]\n : []),\n ...(http\n ? [\n 'app.use(RequestLoggerMiddleware);',\n \"app.set('trust proxy', true);\",\n 'app.enableCors({',\n \" origin: app.get(AppConfigService).get('corsOrigin'),\",\n ' credentials: true,',\n ' maxAge: 600,',\n '});',\n ]\n : []),\n ];\n\n return `${HEADER(name)}${imports.join('\\n')}\n\n/**\n * One app, built the same way for \\`bun start\\` and for the tests - so what the\n * tests exercise is what actually serves.\n *\n * \\`create()\\` boots the container and discovers routes and gateways; \\`listen()\\` is\n * what builds the \\`Bun.serve\\` route table. Everything between the two still gets to\n * shape it, and after \\`listen()\\` every one of those throws.\n */\nexport const createApp = async (): Promise<HttpApp> => {\n const app = await HttpFactory.create(\n ${root}${\n options.length === 0\n ? ',\\n'\n : `,\n {\n${options.map((line) => ` ${line}`).join('\\n')}\n },\n`\n } );\n\n${shaping.map((line) => ` ${line}`).join('\\n')}\n\n return app;\n};\n`;\n};\n\nexport const main = (name: string, features: readonly Feature[]): string => {\n const health = has(features, 'health');\n const openapi = has(features, 'openapi');\n\n const lines = [\n ...(openapi\n ? [\n \"logger.info(`docs ${new URL('api/docs', url).href}`);\",\n \"logger.info(`openapi ${new URL('api/openapi.json', url).href}`);\",\n ]\n : []),\n ...(health\n ? [\"logger.info(`health ${new URL('api/health', url).href}`);\"]\n : []),\n ];\n\n return `${HEADER(name)}import { Logger } from '@dunx/core';\nimport { createApp } from './bootstrap.js';\nimport { AppConfigService } from './config.js';\n\nasync function bootstrap(): Promise<void> {\n const app = await createApp();\n app.enableShutdownHooks();\n\n const config = app.get(AppConfigService);\n const logger = app.get(Logger);\n const url = await app.listen(config.get('port'));\n\n logger.info(\\`listening on \\${url}\\`);\n${lines.map((line) => ` ${line}`).join('\\n')}${lines.length > 0 ? '\\n' : ''}\n // Nothing else to do: the server holds the process open, and the shutdown hooks\n // resolve this once a signal arrives.\n await app.closed;\n}\n\nbootstrap().catch((error: unknown) => {\n console.error('failed to start', error);\n process.exit(1);\n});\n`;\n};\n\n/** The queue worker, only when a queue was asked for. */\nexport const worker = (name: string): string =>\n `${HEADER(name)}import { AppFactory } from '@dunx/core';\nimport { AppModule } from './app.module.js';\n\n/**\n * A queue needs a process to drain it, and it is deliberately not the web one: a\n * worker that shares the server's event loop competes with request handling.\n */\nconst app = await AppFactory.create(AppModule);\napp.enableShutdownHooks();\nawait app.closed;\n`;\n\nexport const envExample = (groups: readonly string[]): string => {\n const lines = groups\n .flatMap((group) => CONFIG_GROUPS[group]?.env ?? [])\n .map((entry) => `${entry.name}=${entry.value}`);\n\n return lines.length === 0\n ? '# Every variable has a default, so this file is optional.\\n'\n : `# Every variable here has a default, so the app boots with no .env at all.\\n${lines.join('\\n')}\\n`;\n};\n\nexport const readme = (name: string, features: readonly Feature[]): string => {\n const services = features.filter((feature) => feature.service !== undefined);\n\n return `# ${name}\n\nScaffolded with \\`bunx @dunx/create-app\\`.\n\n\\`\\`\\`bash\nbun install\nbun run start\n\\`\\`\\`\n\n## What is wired up\n\n${\n features.length === 0\n ? 'Nothing beyond the base app.'\n : features\n .map((feature) => `- **${feature.name}** - ${feature.summary}`)\n .join('\\n')\n}\n\n${\n services.length === 0\n ? ''\n : `## Services\n\nThese features need something running. Each one degrades rather than failing the\nboot, so the app still starts without them.\n\n${services.map((feature) => `- **${feature.name}** needs ${feature.service}`).join('\\n')}\n\n`\n}## Layout\n\n- \\`src/main.ts\\` - the entry point\n- \\`src/bootstrap.ts\\` - builds the app; shared by \\`start\\` and the tests\n- \\`src/app.module.ts\\` - the root module, importing every feature\n- \\`src/config.ts\\` - one validation function, flat env in and a shaped object out\n${features.map((feature) => `- \\`src/${feature.source}/\\` - ${feature.name}`).join('\\n')}\n\n\\`main.ts\\`, \\`bootstrap.ts\\`, \\`app.module.ts\\` and \\`config.ts\\` were generated for the\nfeatures you chose; everything else is copied from dunx's \\`examples/full\\`, which is\nrun and toured in CI on every push. The \\`*.demo.ts\\` files are that example's\nscripted walkthroughs - delete one and its \\`providers\\` entry when you do not want it.\n\n## Constructor injection\n\n\\`bunfig.toml\\` preloads \\`@dunx/transform\\`, which records each class's constructor\nparameter types so the container can resolve them. Without that line providers are\nbuilt with no arguments and boot fails saying so.\n`;\n};\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "FA7FFB8B72BB3F6B64756E2164756E21",
11
+ "names": []
12
+ }
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  featureNames,
8
8
  impliedBy,
9
9
  scaffold
10
- } from "./chunk-jgd5dmqh.js";
10
+ } from "./chunk-g157qb1g.js";
11
11
 
12
12
  // src/cli.ts
13
13
  import { parseArgs } from "util";
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  TEMPLATES,
5
5
  VERSION_PLACEHOLDER,
6
6
  scaffold
7
- } from "./chunk-jgd5dmqh.js";
7
+ } from "./chunk-g157qb1g.js";
8
8
  export {
9
9
  scaffold,
10
10
  VERSION_PLACEHOLDER,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunx/create-app",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "description": "Scaffold a new dunx application - bunx @dunx/create-app my-api",
5
5
  "keywords": [
6
6
  "bun",
@@ -0,0 +1,46 @@
1
+ import { Module } from '@dunx/core';
2
+ import { JobPublisher } from '@dunx/infra/queue';
3
+ import { QueueDashboardModule } from '@dunx/queue-dashboard';
4
+ import { AppConfigService } from '../config.js';
5
+ import { JobsModule } from '../jobs/jobs.module.js';
6
+ import { THUMBNAIL_QUEUE } from '../jobs/thumbnail.jobs.js';
7
+
8
+ /**
9
+ * bull-board at `/queues`, over the same queue the jobs feature publishes to.
10
+ *
11
+ * `forRootAsync` rather than `forRoot`, because the queue lives in the container -
12
+ * `JobPublisher.queue(name)` opens it on first use, so it cannot be named in a
13
+ * static call.
14
+ *
15
+ * `JobsModule` is imported for its `QueueModule.forRoot`, which is what binds
16
+ * `JobPublisher`. Importing it here rather than assuming the app already did keeps
17
+ * this module usable on its own.
18
+ */
19
+ @Module({
20
+ imports: [
21
+ JobsModule,
22
+ QueueDashboardModule.forRootAsync({
23
+ useFactory: (publisher: JobPublisher, config: AppConfigService) => ({
24
+ path: '/queues',
25
+ /**
26
+ * A thunk, not an array: constructing a bullmq `Queue` opens a connection, so
27
+ * naming it here would make this app connect to Redis at boot even when
28
+ * nobody opens the board. Called on the first dashboard request instead.
29
+ */
30
+ queues: () => [publisher.queue(THUMBNAIL_QUEUE)],
31
+ uiConfig: { boardTitle: `${config.get('appName')} queues` },
32
+ /**
33
+ * Every request is authorised, and this example lets them all through on
34
+ * purpose - there is no session to check and a demo that 404s its own
35
+ * dashboard teaches nothing. It is written out rather than omitted because
36
+ * omitting it is the same behaviour with none of the warning: a real
37
+ * deployment checks a session here, and `@dunx/auth`'s `SessionGuard` is
38
+ * what it would read.
39
+ */
40
+ authorize: () => true,
41
+ }),
42
+ inject: [JobPublisher, AppConfigService] as const,
43
+ }),
44
+ ],
45
+ })
46
+ export class DashboardModule {}
@@ -7,6 +7,7 @@ import {
7
7
  Post,
8
8
  type Input,
9
9
  } from '@dunx/http';
10
+ import { PAGINATION, type Page } from '@dunx/infra/pagination';
10
11
  import { z } from 'zod';
11
12
  import { Ledger } from './ledger.service.js';
12
13
  import type { Entry } from './schema.js';
@@ -42,6 +43,34 @@ const listEntries = {
42
43
  limit: z.coerce.number().int().min(1).max(100).default(20),
43
44
  }),
44
45
  } as const;
46
+ /**
47
+ * The page query, written as zod here rather than shipped by `@dunx/infra/pagination`.
48
+ * That package deliberately ships no schema - route validation targets Standard
49
+ * Schema, so the app picks the library - and stating it here is what puts the
50
+ * parameters in the OpenAPI document. `PAGINATION` supplies the bounds so they
51
+ * cannot drift from what `parsePageOptions` would enforce.
52
+ */
53
+ const pageQuery = z
54
+ .object({
55
+ take: z.coerce
56
+ .number()
57
+ .int()
58
+ .min(PAGINATION.MIN_TAKE)
59
+ .max(PAGINATION.MAX_TAKE)
60
+ .default(PAGINATION.DEFAULT_TAKE),
61
+ order: z.enum(['asc', 'desc']).default(PAGINATION.DEFAULT_ORDER),
62
+ direction: z
63
+ .enum(['forward', 'backward'])
64
+ .default(PAGINATION.DEFAULT_DIRECTION),
65
+ cursor: z
66
+ .string()
67
+ .max(PAGINATION.MAX_CURSOR)
68
+ .optional()
69
+ .describe('Opaque cursor from meta.nextCursor. Omit for the first page.'),
70
+ })
71
+ .meta({ id: 'LedgerPageQuery', title: 'Keyset pagination over the ledger' });
72
+
73
+ const pagedEntries = { query: pageQuery } as const;
45
74
  const oneEntry = { params: EntryIndex } as const;
46
75
  const createEntry = { body: CreateEntry } as const;
47
76
  const transfer = { body: Transfer } as const;
@@ -61,6 +90,16 @@ export class LedgerController {
61
90
  };
62
91
  }
63
92
 
93
+ /**
94
+ * The same rows as `GET /ledger`, walked by cursor. Declared **before** `/:id` for
95
+ * readability only - `Bun.serve` matches a static segment ahead of a parameter, so
96
+ * `/ledger/page` cannot be swallowed by `/ledger/:id`.
97
+ */
98
+ @Get('/page', pagedEntries)
99
+ page(input: Input<typeof pagedEntries>): Promise<Page<Entry>> {
100
+ return this.ledger.page(input.query);
101
+ }
102
+
64
103
  @Get('/:id', oneEntry)
65
104
  one(input: Input<typeof oneEntry>): Entry {
66
105
  const entry = this.ledger.find(input.params.id);
@@ -9,6 +9,7 @@ import {
9
9
  transactionSync,
10
10
  type SeedReport,
11
11
  } from '@dunx/infra/db';
12
+ import { paginate, type Page, type PageOptions } from '@dunx/infra/pagination';
12
13
  import { count, desc, eq, sql, sum } from 'drizzle-orm';
13
14
  import * as schema from './schema.js';
14
15
  import { ledger, type Entry } from './schema.js';
@@ -53,6 +54,26 @@ export class Ledger implements OnInit, OnShutdown {
53
54
  .all();
54
55
  }
55
56
 
57
+ /**
58
+ * The same rows, paginated by cursor instead of by `limit`.
59
+ *
60
+ * Keyset rather than `OFFSET`, which is what makes it correct while rows are being
61
+ * written: a cursor names the last row seen, so an insert between two requests
62
+ * cannot shift a page and serve the same entry twice. This table has no timestamp,
63
+ * so `paginate` falls back to the primary key - `id` is unique on its own, so no
64
+ * tie-break column is needed.
65
+ *
66
+ * `async` although bun-sqlite is synchronous, because `paginate` awaits the query
67
+ * builder - the one code path that serves both dialects.
68
+ */
69
+ page(options: PageOptions): Promise<Page<Entry>> {
70
+ return paginate<typeof ledger, Entry>({
71
+ db: this.db,
72
+ table: ledger,
73
+ options,
74
+ });
75
+ }
76
+
56
77
  find(id: number): Entry | undefined {
57
78
  return this.db.select().from(ledger).where(eq(ledger.id, id)).get();
58
79
  }
@@ -1,12 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/features.ts", "../src/scaffold.ts", "../src/generate.ts"],
4
- "sourcesContent": [
5
- "/**\n * The features a generated app can be composed from, each one a directory of\n * `examples/full` - the example CI boots and tours on every push.\n *\n * That is the whole point of sourcing them there rather than writing starter code\n * here: a template nobody runs rots, and this repo already runs `examples/full`\n * end to end. `bun run sync:templates` copies the directories in and\n * `features.test.ts` fails if a copy drifts, so what gets scaffolded is what CI\n * proved works.\n *\n * What is **not** copied is the wiring: `app.module.ts`, `config.ts`,\n * `bootstrap.ts` and `main.ts` in the full example name every feature at once, so\n * they are generated from the selection instead. See `generate.ts`.\n */\nexport interface Feature {\n /** Flag name, and the directory under `templates/features/`. */\n readonly name: string;\n /** The directory in `examples/full/src` this mirrors. */\n readonly source: string;\n readonly summary: string;\n /** Features this one imports from, pulled in automatically. */\n readonly requires: readonly string[];\n /** The module class to import, and the file it comes from. */\n readonly module: { readonly klass: string; readonly from: string };\n /** Runtime dependencies this feature adds to the generated manifest. */\n readonly dependencies: readonly string[];\n /** Config groups this feature reads, contributed to the generated config. */\n readonly config: readonly string[];\n /**\n * A service that has to be running for the feature to do anything. Named so the\n * prompt can say so and the generated README can list it, rather than the app\n * failing in a way the reader has to diagnose.\n */\n readonly service?: string;\n}\n\n/**\n * Config groups, keyed by the name a feature asks for. `env` is what lands in\n * `.env.example`, `schema` the zod line, `field` the `AppConfig` member and `map`\n * how the flat variable becomes the shaped one - the four things\n * `examples/full/src/config.ts` states for every group at once, split so a\n * selection can state only its own.\n */\nexport interface ConfigGroup {\n readonly schema: readonly string[];\n readonly field: string;\n readonly map: string;\n readonly env: readonly { readonly name: string; readonly value: string }[];\n}\n\nexport const CONFIG_GROUPS: Readonly<Record<string, ConfigGroup>> =\n Object.freeze({\n port: {\n schema: [\n 'PORT: z.coerce.number().int().min(0).max(65535).default(3000),',\n ],\n field: 'readonly port: number;',\n map: 'port: value.PORT,',\n env: [{ name: 'PORT', value: '3000' }],\n },\n appName: {\n schema: [],\n field: 'readonly appName: string;',\n map: \"appName: '__DUNX_APP_NAME__',\",\n env: [],\n },\n log: {\n schema: [\n 'LOG_LEVEL: z.enum(LogLevel).default(LogLevel.INFO),',\n '/** Unset means console only. Set it to also append JSON to a rotating file. */',\n 'LOG_FILE: z.string().optional(),',\n ],\n field:\n 'readonly log: { readonly level: LogLevel; readonly file: string | undefined };',\n map: 'log: { level: value.LOG_LEVEL, file: value.LOG_FILE },',\n env: [{ name: 'LOG_LEVEL', value: 'info' }],\n },\n corsOrigin: {\n schema: [\"CORS_ORIGIN: z.string().default('https://example.com'),\"],\n field: 'readonly corsOrigin: string;',\n map: 'corsOrigin: value.CORS_ORIGIN,',\n env: [{ name: 'CORS_ORIGIN', value: 'https://example.com' }],\n },\n database: {\n schema: [\n '/** `:memory:` needs no server and leaves nothing behind, so restarts are clean. */',\n \"DATABASE_FILE: z.string().default(':memory:'),\",\n ],\n field: 'readonly database: { readonly file: string };',\n map: 'database: { file: value.DATABASE_FILE },',\n env: [{ name: 'DATABASE_FILE', value: ':memory:' }],\n },\n redis: {\n schema: [\n '/** Absent is fine: the cache routes report themselves degraded instead of failing. */',\n 'REDIS_URL: z.string().optional(),',\n ],\n field: 'readonly redis: { readonly url: string | undefined };',\n map: 'redis: { url: value.REDIS_URL },',\n env: [{ name: 'REDIS_URL', value: 'redis://localhost:6379' }],\n },\n images: {\n schema: [\n 'IMAGE_QUALITY: z.coerce.number().int().min(1).max(100).default(82),',\n ],\n field: 'readonly images: { readonly quality: number };',\n map: 'images: { quality: value.IMAGE_QUALITY },',\n env: [{ name: 'IMAGE_QUALITY', value: '82' }],\n },\n auth: {\n schema: [\n '/** better-auth signs session cookies with this. 32 characters is its own minimum. */',\n \"AUTH_SECRET: z.string().min(32).default('dunx-development-secret-not-for-production'),\",\n ],\n field: 'readonly auth: { readonly secret: string };',\n map: 'auth: { secret: value.AUTH_SECRET },',\n env: [\n {\n name: 'AUTH_SECRET',\n value: 'change-me-to-at-least-32-characters-long',\n },\n ],\n },\n seedUsers: {\n schema: [],\n field: 'readonly seedUsers: readonly string[];',\n map: \"seedUsers: ['ada', 'grace'],\",\n env: [],\n },\n authorization: {\n schema: [],\n field: 'readonly authorization: { readonly enabled: boolean };',\n map: 'authorization: { enabled: true },',\n env: [],\n },\n });\n\n/** Always present, whatever is selected: the port and the logger need them. */\nexport const BASE_CONFIG: readonly string[] = ['appName', 'port', 'log'];\n\nexport const FEATURES: readonly Feature[] = [\n {\n name: 'notes',\n source: 'notes',\n summary: 'CRUD routes with zod validation. The smallest real feature.',\n requires: [],\n module: { klass: 'NotesModule', from: './notes/notes.module.js' },\n dependencies: ['zod'],\n config: [],\n },\n {\n name: 'openapi',\n source: 'docs',\n summary: 'OpenAPI 3.1 from the routes own schemas, plus the explorer page.',\n requires: [],\n module: { klass: 'DocsModule', from: './docs/docs.module.js' },\n dependencies: ['@dunx/openapi', 'zod'],\n config: [],\n },\n {\n name: 'http',\n source: 'http',\n summary: 'CORS, a request-logging middleware and error mapping.',\n requires: [],\n module: { klass: 'HttpModule', from: './http/http.module.js' },\n dependencies: [],\n config: ['corsOrigin'],\n },\n {\n name: 'guards',\n source: 'guards',\n summary:\n 'Route guards with @Roles and @Public, and a protected controller.',\n requires: [],\n module: { klass: 'GuardsModule', from: './guards/guards.module.js' },\n dependencies: ['zod'],\n config: ['authorization'],\n },\n {\n name: 'database',\n source: 'database',\n summary: 'drizzle over bun:sqlite, with a schema, seeds and migrations.',\n requires: [],\n module: { klass: 'DatabaseModule', from: './database/database.module.js' },\n dependencies: ['@dunx/infra', 'drizzle-orm'],\n config: ['database'],\n },\n {\n name: 'users',\n source: 'users',\n summary: 'A repository, a service and validated routes over the database.',\n requires: ['database'],\n module: { klass: 'UsersModule', from: './users/users.module.js' },\n dependencies: ['@dunx/infra', 'drizzle-orm', 'zod'],\n config: ['appName', 'seedUsers'],\n },\n {\n name: 'auth',\n source: 'auth',\n summary: 'better-auth mounted, with SessionGuard and an audit trail.',\n requires: ['database'],\n module: { klass: 'AccountsModule', from: './auth/auth.module.js' },\n dependencies: ['@dunx/auth', 'better-auth', 'drizzle-orm'],\n config: ['auth', 'port'],\n },\n {\n name: 'cache',\n source: 'cache',\n summary: 'Bun.RedisClient behind a session store, degrading when absent.',\n requires: [],\n module: { klass: 'CacheModule', from: './cache/cache.module.js' },\n dependencies: ['@dunx/infra'],\n config: ['redis'],\n service: 'Redis or Valkey',\n },\n {\n name: 'websockets',\n source: 'chat',\n summary: 'A @Gateway with @OnMessage events, PubSub and a Redis relay.',\n requires: [],\n module: { klass: 'ChatModule', from: './chat/chat.module.js' },\n dependencies: ['@dunx/infra'],\n config: [],\n service: 'Redis or Valkey, for multi-node fan-out only',\n },\n {\n name: 'images',\n source: 'pictures',\n summary: 'Bun.Image resizing and format conversion behind a route.',\n requires: [],\n module: { klass: 'PicturesModule', from: './pictures/pictures.module.js' },\n dependencies: ['@dunx/infra'],\n config: ['images'],\n },\n {\n name: 'files',\n source: 'storage',\n summary: 'Uploads and downloads on Bun.file, with a workspace root.',\n requires: [],\n module: { klass: 'StorageModule', from: './storage/storage.module.js' },\n dependencies: ['@dunx/infra'],\n config: [],\n },\n {\n name: 'jobs',\n source: 'jobs',\n summary: 'bullmq queues and a worker, over Bun.RedisClient.',\n requires: ['images'],\n module: { klass: 'JobsModule', from: './jobs/jobs.module.js' },\n dependencies: ['@dunx/infra', 'bullmq', 'ioredis'],\n config: ['redis'],\n service: 'Redis or Valkey',\n },\n {\n name: 'health',\n source: 'health',\n summary: 'One endpoint reporting which parts are live and which degraded.',\n requires: ['cache', 'database'],\n module: { klass: 'HealthModule', from: './health/health.module.js' },\n dependencies: ['@dunx/infra'],\n config: ['appName'],\n },\n];\n\nexport const featureNames: readonly string[] = FEATURES.map(\n (feature) => feature.name,\n);\n\nconst byName = new Map(FEATURES.map((feature) => [feature.name, feature]));\n\nexport class UnknownFeatureError extends Error {\n override readonly name = 'UnknownFeatureError';\n}\n\n/**\n * The selection plus everything it requires, in **import order** - which is\n * construction order, and shutdown runs in reverse. A feature is emitted after\n * everything it requires, so the database outlives the features reading it, the\n * same ordering `examples/full/src/app.module.ts` states by hand.\n *\n * Depth-first over `requires`, with a visited set, so a diamond resolves once and\n * the result is stable whatever order the caller asked in.\n */\nexport const resolveFeatures = (\n requested: readonly string[],\n): readonly Feature[] => {\n const unknown = requested.filter((name) => !byName.has(name));\n if (unknown.length > 0) {\n throw new UnknownFeatureError(\n `Unknown feature${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}. ` +\n `Available: ${featureNames.join(', ')}.`,\n );\n }\n\n const ordered: Feature[] = [];\n const seen = new Set<string>();\n const rank = new Map(FEATURES.map((feature, at) => [feature.name, at]));\n\n const visit = (name: string): void => {\n if (seen.has(name)) return;\n seen.add(name);\n const feature = byName.get(name);\n if (!feature) return;\n // Requirements in **registry order**, not in the order this feature happens to\n // list them: two independent requirements would otherwise come out in the\n // order they were typed, which is not a statement about construction order and\n // would make `requires: ['cache', 'database']` build the cache first.\n for (const required of [...feature.requires].sort(\n (left, right) => (rank.get(left) ?? 0) - (rank.get(right) ?? 0),\n )) {\n visit(required);\n }\n ordered.push(feature);\n };\n\n // Registry order, not request order, so two runs asking for the same set in a\n // different order generate byte-identical files.\n for (const feature of FEATURES) {\n if (requested.includes(feature.name)) visit(feature.name);\n }\n\n return ordered;\n};\n\n/** Which of the resolved features the caller did not ask for. */\nexport const impliedBy = (\n requested: readonly string[],\n resolved: readonly Feature[],\n): readonly string[] =>\n resolved\n .map((feature) => feature.name)\n .filter((name) => !requested.includes(name));\n",
6
- "import { existsSync, readdirSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Glob } from 'bun';\nimport { resolveFeatures, type Feature } from './features.js';\nimport {\n appModule,\n bootstrap,\n config,\n configGroupsFor,\n envExample,\n main,\n manifest,\n readme,\n worker,\n} from './generate.js';\n\n/** The templates that ship with the package, as `templates/<name>/`. */\nexport const TEMPLATES = Object.freeze(['minimal'] as const);\nexport type TemplateName = (typeof TEMPLATES)[number];\n\n/**\n * Every `@dunx/*` version in a template manifest is this placeholder. Versioning\n * is lockstep, so the right version to install is whatever version of\n * `@dunx/create-app` is doing the scaffolding - resolved at run time rather than\n * written into the template, which would go stale on the next release.\n */\nexport const VERSION_PLACEHOLDER = '__DUNX_VERSION__';\n\n/**\n * Names a package cannot ship as-is, so they ship prefixed and are renamed on write.\n *\n * `.gitignore` is the known one: npm renames a published copy to `.npmignore`.\n *\n * **`bunfig.toml` is the one that was silently missing.** It is stripped from the\n * tarball entirely - presumably so a dependency cannot hijack the installing\n * project's Bun config - and it is the single file dunx asks an app to have. Every\n * app scaffolded from a published `@dunx/create-app` therefore had no\n * `@dunx/transform/preload`, and failed at boot with the very error the guide\n * describes. Measured with `bun pm pack`, and `pack.test.ts` now measures it on\n * every run rather than trusting this comment.\n */\nconst RENAMED = Object.freeze({\n _gitignore: '.gitignore',\n '_bunfig.toml': 'bunfig.toml',\n});\n\n/**\n * Entries that do not make a directory non-empty for scaffolding purposes.\n *\n * `.git` is the one that matters: `git init` then scaffold into the repo is the\n * documented way to start, and refusing it blocks the flow outright. `.gitkeep`\n * exists only so git can track an otherwise empty directory, so it *means* empty.\n * `.DS_Store` appears from merely opening the folder in Finder. `LICENSE` is what\n * GitHub's create-a-repository flow leaves in a fresh clone.\n *\n * The list is deliberately short, and the test for it is whether the template\n * writes that name. It does not write any of these four, so ignoring them can\n * never destroy anything. `.gitignore` and `README.md` are excluded for exactly\n * that reason: the template writes both, and silently overwriting a user's copy\n * is what `--force` exists to gate.\n */\nconst IGNORED_WHEN_EMPTY: ReadonlySet<string> = new Set([\n '.DS_Store',\n '.git',\n '.gitkeep',\n 'LICENSE',\n]);\n\nexport interface ScaffoldOptions {\n /** Directory to create. Relative paths resolve against `cwd`. */\n readonly target: string;\n /** Package name for the generated app. Defaults to the target's basename. */\n readonly name?: string;\n readonly template?: TemplateName;\n /**\n * Features to compose the app from, by name. Anything they require is pulled in.\n *\n * Passing any switches from copying a fixed template to generating the wiring\n * around the chosen feature directories - see `generate.ts`. An empty list, or\n * none at all, scaffolds `template` unchanged, so the default behaviour is exactly\n * what it was.\n */\n readonly features?: readonly string[];\n /** Write into a directory that already has files in it. */\n readonly force?: boolean;\n readonly cwd?: string;\n /** Overrides the version written into the generated manifest. */\n readonly version?: string;\n}\n\nexport interface ScaffoldResult {\n readonly directory: string;\n readonly name: string;\n readonly template: TemplateName | 'composed';\n /** Resolved feature names, in import order. Empty for a fixed template. */\n readonly features: readonly string[];\n readonly files: readonly string[];\n}\n\nexport class ScaffoldError extends Error {\n override readonly name = 'ScaffoldError';\n}\n\n/**\n * `dist/index.js` and `dist/cli.js` both sit one level under the package root, so\n * `../templates` resolves the same from either. In the source tree it resolves\n * from `src/`, which is the same depth - so tests exercise the real path rather\n * than a special case.\n *\n * `fileURLToPath`, not `new URL(...).pathname`: the latter stays percent-encoded,\n * so an install under a directory with a space in it looks for `space%20test/`\n * and reports the template missing. On Windows it is worse - it yields a\n * leading-slash, drive-lettered path that resolves nowhere.\n */\nconst templatesRoot = (): string =>\n resolve(dirname(fileURLToPath(import.meta.url)), '..', 'templates');\n\n/**\n * npm forbids uppercase and a leading dot or underscore, and a scope is legal.\n * Checked here because the failure would otherwise surface as a confusing\n * `bun install` error inside a directory the user just created.\n */\nconst isValidPackageName = (name: string): boolean =>\n /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);\n\nconst readPackageVersion = async (): Promise<string> => {\n const file = Bun.file(join(templatesRoot(), '..', 'package.json'));\n const json = (await file.json()) as { version?: string };\n return json.version ?? '0.0.0';\n};\n\n/** Placeholders are substituted in every written file, generated or copied. */\nconst fill = (contents: string, name: string, version: string): string =>\n contents\n .replaceAll(VERSION_PLACEHOLDER, version)\n .replaceAll('__DUNX_APP_NAME__', name);\n\n/**\n * The four files a subset of features cannot copy, because the full example states\n * every feature at once in each of them.\n */\nconst generated = (\n name: string,\n features: readonly Feature[],\n): Readonly<Record<string, string>> => {\n const groups = configGroupsFor(features);\n const files: Record<string, string> = {\n 'package.json': manifest(features),\n 'README.md': readme(name, features),\n '.env.example': envExample(groups),\n 'src/main.ts': main(name, features),\n 'src/bootstrap.ts': bootstrap(name, features),\n 'src/app.module.ts': appModule(name, features),\n 'src/config.ts': config(name, groups),\n };\n if (features.some((feature) => feature.name === 'jobs')) {\n files['src/worker.ts'] = worker(name);\n }\n return files;\n};\n\nexport const scaffold = async (\n options: ScaffoldOptions,\n): Promise<ScaffoldResult> => {\n const template = options.template ?? 'minimal';\n if (!TEMPLATES.includes(template)) {\n throw new ScaffoldError(\n `Unknown template \"${template}\". Available: ${TEMPLATES.join(', ')}.`,\n );\n }\n\n // Resolved before anything is written, so an unknown feature name fails with the\n // list of real ones rather than half a directory.\n const requested = options.features ?? [];\n let features: readonly Feature[] = [];\n try {\n features = resolveFeatures(requested);\n } catch (error) {\n throw new ScaffoldError(\n error instanceof Error ? error.message : String(error),\n );\n }\n const composing = features.length > 0;\n\n const directory = resolve(options.cwd ?? process.cwd(), options.target);\n const name = options.name ?? basename(directory);\n\n if (!isValidPackageName(name)) {\n throw new ScaffoldError(\n `\"${name}\" is not a usable package name. Pass --name to choose one.`,\n );\n }\n\n if (existsSync(directory) && options.force !== true) {\n const blocking = readdirSync(directory).filter(\n (entry) => !IGNORED_WHEN_EMPTY.has(entry),\n );\n if (blocking.length > 0) {\n // Naming what blocked it, because `.git` used to block it and the message\n // gave no way to tell that from a directory of real work.\n const shown = blocking.sort().slice(0, 3).join(', ');\n const rest = blocking.length > 3 ? `, +${blocking.length - 3} more` : '';\n throw new ScaffoldError(\n `${directory} is not empty (${shown}${rest}). ` +\n `Pass --force to write into it anyway.`,\n );\n }\n }\n\n const version = options.version ?? `^${await readPackageVersion()}`;\n const written: string[] = [];\n\n /** Copies a directory of the package's own templates into the new app. */\n const copyTree = async (from: string, into: string): Promise<void> => {\n // `**/*` with `dot: true` so a template can carry a dotfile that npm did not\n // rename; the explicit `_gitignore` mapping covers the one that it does.\n for await (const relative of new Glob('**/*').scan({\n cwd: from,\n dot: true,\n onlyFiles: true,\n })) {\n const base = relative.split('/').at(-1) ?? relative;\n const renamed = (RENAMED as Record<string, string | undefined>)[base];\n const target = join(\n into,\n renamed === undefined ? relative : join(dirname(relative), renamed),\n );\n\n const contents = await Bun.file(join(from, relative)).text();\n // `Bun.write` creates parent directories, so there is no mkdir pass.\n await Bun.write(join(directory, target), fill(contents, name, version));\n written.push(target);\n }\n };\n\n if (!composing) {\n const source = join(templatesRoot(), template);\n if (!existsSync(source)) {\n throw new ScaffoldError(\n `Template \"${template}\" is missing from ${source}.`,\n );\n }\n await copyTree(source, '.');\n return {\n directory,\n name,\n template,\n features: [],\n files: written.sort(),\n };\n }\n\n // The base carries what every composed app needs and no feature owns: the\n // tsconfig, the transform preload, and the gitignore.\n const base = join(templatesRoot(), 'base');\n if (!existsSync(base)) {\n throw new ScaffoldError(\n `The base template is missing from ${base}. Run \\`bun run sync:templates\\`.`,\n );\n }\n await copyTree(base, '.');\n\n for (const feature of features) {\n const from = join(templatesRoot(), 'features', feature.source);\n if (!existsSync(from)) {\n throw new ScaffoldError(\n `Feature \"${feature.name}\" is missing from ${from}. ` +\n 'Run `bun run sync:templates`.',\n );\n }\n await copyTree(from, join('src', feature.source));\n }\n\n for (const [target, contents] of Object.entries(generated(name, features))) {\n await Bun.write(join(directory, target), fill(contents, name, version));\n written.push(target);\n }\n\n return {\n directory,\n name,\n template: 'composed',\n features: features.map((feature) => feature.name),\n files: written.sort(),\n };\n};\n",
7
- "import { BASE_CONFIG, CONFIG_GROUPS, type Feature } from './features.js';\n\n/**\n * The wiring, generated from a feature selection.\n *\n * The full example states every feature at once in four files - `app.module.ts`,\n * `config.ts`, `bootstrap.ts` and `main.ts` - so those are the ones a subset cannot\n * copy. Everything else is the feature's own directory, copied verbatim.\n *\n * Generated rather than assembled by editing a copy on purpose: an edited copy\n * cannot be checked against the example it came from, and the byte-for-byte parity\n * test is what stops the vendored features drifting from the app CI actually boots.\n */\nconst HEADER = (name: string): string =>\n `// Generated by @dunx/create-app for ${name}. Yours to edit.\\n`;\n\nconst uniq = (values: readonly string[]): string[] => [...new Set(values)];\n\n/** Every config group the selection needs, base first, in a stable order. */\nexport const configGroupsFor = (\n features: readonly Feature[],\n): readonly string[] => {\n const wanted = uniq([\n ...BASE_CONFIG,\n ...features.flatMap((feature) => feature.config),\n ]);\n return Object.keys(CONFIG_GROUPS).filter((group) => wanted.includes(group));\n};\n\nexport const dependenciesFor = (\n features: readonly Feature[],\n): readonly string[] =>\n uniq([\n '@dunx/core',\n '@dunx/http',\n '@dunx/transform',\n '@dunx/infra',\n ...features.flatMap((feature) => feature.dependencies),\n ]).sort();\n\nconst DUNX = /^@dunx\\//;\n\nexport const manifest = (features: readonly Feature[]): string => {\n const deps = dependenciesFor(features);\n const dependencies: Record<string, string> = {};\n for (const dep of deps) {\n dependencies[dep] = DUNX.test(dep) ? '__DUNX_VERSION__' : versionOf(dep);\n }\n\n const scripts: Record<string, string> = {\n start: 'bun src/main.ts',\n test: 'bun test',\n typecheck: 'tsc --noEmit',\n };\n // A queue needs a process to drain it, and it is not the web one.\n if (features.some((feature) => feature.name === 'jobs')) {\n scripts['worker'] = 'bun src/worker.ts';\n }\n\n return `${JSON.stringify(\n {\n name: '__DUNX_APP_NAME__',\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts,\n dependencies,\n devDependencies: {\n '@dunx/testing': '__DUNX_VERSION__',\n '@types/bun': '>=1.3.0',\n typescript: '^5.7.0',\n },\n engines: { bun: '>=1.3.0' },\n },\n null,\n 2,\n )}\\n`;\n};\n\n/**\n * Third-party ranges, pinned here rather than read off `examples/full` at run time:\n * the generated app installs from npm and the example installs from the workspace,\n * so the example's manifest is not a statement about what a consumer should take.\n * `features.test.ts` checks these against the example's, which is what stops them\n * silently diverging from a version combination that is actually exercised.\n */\nexport const THIRD_PARTY: Readonly<Record<string, string>> = Object.freeze({\n zod: '^4.4.3',\n 'drizzle-orm': '^0.45.2',\n 'better-auth': '^1.6.25',\n bullmq: '^6.0.5',\n ioredis: '^6.0.0',\n});\n\nconst versionOf = (dep: string): string => THIRD_PARTY[dep] ?? 'latest';\n\nexport const appModule = (\n name: string,\n features: readonly Feature[],\n): string => {\n const needsLogger = true;\n const imports = [\n \"import { ConfigModule, Module } from '@dunx/core';\",\n ...(needsLogger\n ? [\"import { LoggerModule } from '@dunx/infra/logger';\"]\n : []),\n \"import { AppConfigService, validate } from './config.js';\",\n ...features.map(\n (feature) =>\n `import { ${feature.module.klass} } from '${feature.module.from}';`,\n ),\n ];\n\n const moduleImports = [\n 'ConfigModule.forRoot({ validate, as: AppConfigService }),',\n '// The level comes from the validated config, which is the one thing a',\n '// zero-argument `forRoot` function cannot reach.',\n 'LoggerModule.forRootAsync(',\n ' {',\n ' useFactory: (config: AppConfigService) => ({',\n \" name: config.get('appName'),\",\n \" level: config.get('log').level,\",\n ' }),',\n ' inject: [AppConfigService] as const,',\n ' },',\n ' { captureGlobalErrors: true },',\n '),',\n ...features.map((feature) => `${feature.module.klass},`),\n ];\n\n return `${HEADER(name)}${imports.join('\\n')}\n\n/**\n * Import order is construction order, and shutdown runs in reverse - so config and\n * the logger are built first and torn down last, and anything a feature depends on\n * outlives it.\n */\n@Module({\n imports: [\n${moduleImports.map((line) => ` ${line}`).join('\\n')}\n ],\n})\nexport class AppModule {}\n`;\n};\n\nexport const config = (name: string, groups: readonly string[]): string => {\n const chosen = groups\n .map((group) => [group, CONFIG_GROUPS[group]] as const)\n .filter(\n (entry): entry is [string, (typeof CONFIG_GROUPS)[string]] =>\n entry[1] !== undefined,\n );\n\n const schema = chosen.flatMap(([, group]) => group.schema);\n const needsLogLevel = groups.includes('log');\n\n return `${HEADER(name)}import { ConfigService, type ConfigSource${\n needsLogLevel ? ', LogLevel' : ''\n } } from '@dunx/core';\nimport { z } from 'zod';\n\n/**\n * One validation function, which is the whole \\`ConfigModule\\` contract. dunx does\n * not pick the library - this is zod because the routes already use it, and a\n * hand-written function that throws would work identically.\n *\n * \\`.default()\\` is where a value comes from when the variable is unset, so a clean\n * checkout boots with no \\`.env\\` at all. Bun loads \\`.env\\` and \\`.env.local\\` itself,\n * so there is nothing here that reads a file.\n */\nconst envSchema = z.object({\n${schema.map((line) => ` ${line}`).join('\\n')}\n});\n\nexport interface AppConfig {\n${chosen.map(([, group]) => ` ${group.field}`).join('\\n')}\n}\n\n/**\n * One name for the typed config everywhere. A subclass rather than\n * \\`ConfigService<AppConfig>\\` at each site because a factory's \\`inject: [...]\\`\n * carries no type argument - the class does, and it is a real runtime value, so it\n * is both a precise token and a usable constructor annotation.\n */\nexport class AppConfigService extends ConfigService<AppConfig> {}\n\n/** The one broker channel the websocket relay carries every topic on. */\nexport const RELAY_CHANNEL = '__DUNX_APP_NAME__:ws';\n\n/** Flat variables in, a shaped object out. Nothing downstream reads \\`Bun.env\\`. */\nexport const validate = (env: ConfigSource): AppConfig => {\n const parsed = envSchema.safeParse(env);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => \\`\\${issue.path.join('.') || '(root)'}: \\${issue.message}\\`)\n .join('\\\\n - ');\n throw new Error(\\`Configuration is invalid:\\\\n - \\${issues}\\`);\n }\n const value = parsed.data;\n\n return {\n${chosen.map(([, group]) => ` ${group.map}`).join('\\n')}\n };\n};\n`;\n};\n\nconst has = (features: readonly Feature[], name: string): boolean =>\n features.some((feature) => feature.name === name);\n\nexport const bootstrap = (\n name: string,\n features: readonly Feature[],\n): string => {\n const openapi = has(features, 'openapi');\n const websockets = has(features, 'websockets');\n const http = has(features, 'http');\n\n const imports = [\n `import { HttpFactory${websockets ? ', RedisRelay' : ''}, type HttpApp } from '@dunx/http';`,\n ...(openapi ? [\"import { OpenApiModule } from '@dunx/openapi';\"] : []),\n \"import { AppModule } from './app.module.js';\",\n `import { ${[\n ...(http ? ['AppConfigService'] : []),\n ...(websockets ? ['RELAY_CHANNEL'] : []),\n ].join(', ')} } from './config.js';`,\n ...(http\n ? [\"import { RequestLoggerMiddleware } from './http/request-log.js';\"]\n : []),\n ].filter((line) => !line.includes('{ }'));\n\n const root = openapi\n ? `OpenApiModule.forRoot({\n title: '__DUNX_APP_NAME__',\n version: '0.1.0',\n root: AppModule,\n })`\n : 'AppModule';\n\n const options = websockets\n ? [\n '// Multi-node websocket fan-out on `Bun.RedisClient`, so it costs no',\n '// dependency. With no Redis running this degrades to single-process',\n '// behaviour, logs one warning, and the app still boots.',\n 'websocket: { idleTimeout: 30 },',\n 'relay: new RedisRelay({ connectionTimeout: 500 }),',\n 'relayChannel: RELAY_CHANNEL,',\n ]\n : [];\n\n /**\n * Everything between `create()` and `listen()`. The prefix is set whatever is\n * selected, because the copied controllers declare paths under it and the URLs\n * `main.ts` prints assume it.\n *\n * `app.use` takes the middleware **class**, not an instance: the container\n * constructs it, which is what lets it have dependencies of its own.\n */\n const shaping = [\n \"app.setGlobalPrefix('api');\",\n ...(http\n ? [\n 'app.use(RequestLoggerMiddleware);',\n \"app.set('trust proxy', true);\",\n 'app.enableCors({',\n \" origin: app.get(AppConfigService).get('corsOrigin'),\",\n ' credentials: true,',\n ' maxAge: 600,',\n '});',\n ]\n : []),\n ];\n\n return `${HEADER(name)}${imports.join('\\n')}\n\n/**\n * One app, built the same way for \\`bun start\\` and for the tests - so what the\n * tests exercise is what actually serves.\n *\n * \\`create()\\` boots the container and discovers routes and gateways; \\`listen()\\` is\n * what builds the \\`Bun.serve\\` route table. Everything between the two still gets to\n * shape it, and after \\`listen()\\` every one of those throws.\n */\nexport const createApp = async (): Promise<HttpApp> => {\n const app = await HttpFactory.create(\n ${root}${\n options.length === 0\n ? ',\\n'\n : `,\n {\n${options.map((line) => ` ${line}`).join('\\n')}\n },\n`\n } );\n\n${shaping.map((line) => ` ${line}`).join('\\n')}\n\n return app;\n};\n`;\n};\n\nexport const main = (name: string, features: readonly Feature[]): string => {\n const health = has(features, 'health');\n const openapi = has(features, 'openapi');\n\n const lines = [\n ...(openapi\n ? [\n \"logger.info(`docs ${new URL('api/docs', url).href}`);\",\n \"logger.info(`openapi ${new URL('api/openapi.json', url).href}`);\",\n ]\n : []),\n ...(health\n ? [\"logger.info(`health ${new URL('api/health', url).href}`);\"]\n : []),\n ];\n\n return `${HEADER(name)}import { Logger } from '@dunx/core';\nimport { createApp } from './bootstrap.js';\nimport { AppConfigService } from './config.js';\n\nasync function bootstrap(): Promise<void> {\n const app = await createApp();\n app.enableShutdownHooks();\n\n const config = app.get(AppConfigService);\n const logger = app.get(Logger);\n const url = await app.listen(config.get('port'));\n\n logger.info(\\`listening on \\${url}\\`);\n${lines.map((line) => ` ${line}`).join('\\n')}${lines.length > 0 ? '\\n' : ''}\n // Nothing else to do: the server holds the process open, and the shutdown hooks\n // resolve this once a signal arrives.\n await app.closed;\n}\n\nbootstrap().catch((error: unknown) => {\n console.error('failed to start', error);\n process.exit(1);\n});\n`;\n};\n\n/** The queue worker, only when a queue was asked for. */\nexport const worker = (name: string): string =>\n `${HEADER(name)}import { AppFactory } from '@dunx/core';\nimport { AppModule } from './app.module.js';\n\n/**\n * A queue needs a process to drain it, and it is deliberately not the web one: a\n * worker that shares the server's event loop competes with request handling.\n */\nconst app = await AppFactory.create(AppModule);\napp.enableShutdownHooks();\nawait app.closed;\n`;\n\nexport const envExample = (groups: readonly string[]): string => {\n const lines = groups\n .flatMap((group) => CONFIG_GROUPS[group]?.env ?? [])\n .map((entry) => `${entry.name}=${entry.value}`);\n\n return lines.length === 0\n ? '# Every variable has a default, so this file is optional.\\n'\n : `# Every variable here has a default, so the app boots with no .env at all.\\n${lines.join('\\n')}\\n`;\n};\n\nexport const readme = (name: string, features: readonly Feature[]): string => {\n const services = features.filter((feature) => feature.service !== undefined);\n\n return `# ${name}\n\nScaffolded with \\`bunx @dunx/create-app\\`.\n\n\\`\\`\\`bash\nbun install\nbun run start\n\\`\\`\\`\n\n## What is wired up\n\n${\n features.length === 0\n ? 'Nothing beyond the base app.'\n : features\n .map((feature) => `- **${feature.name}** - ${feature.summary}`)\n .join('\\n')\n}\n\n${\n services.length === 0\n ? ''\n : `## Services\n\nThese features need something running. Each one degrades rather than failing the\nboot, so the app still starts without them.\n\n${services.map((feature) => `- **${feature.name}** needs ${feature.service}`).join('\\n')}\n\n`\n}## Layout\n\n- \\`src/main.ts\\` - the entry point\n- \\`src/bootstrap.ts\\` - builds the app; shared by \\`start\\` and the tests\n- \\`src/app.module.ts\\` - the root module, importing every feature\n- \\`src/config.ts\\` - one validation function, flat env in and a shaped object out\n${features.map((feature) => `- \\`src/${feature.source}/\\` - ${feature.name}`).join('\\n')}\n\n\\`main.ts\\`, \\`bootstrap.ts\\`, \\`app.module.ts\\` and \\`config.ts\\` were generated for the\nfeatures you chose; everything else is copied from dunx's \\`examples/full\\`, which is\nrun and toured in CI on every push. The \\`*.demo.ts\\` files are that example's\nscripted walkthroughs - delete one and its \\`providers\\` entry when you do not want it.\n\n## Constructor injection\n\n\\`bunfig.toml\\` preloads \\`@dunx/transform\\`, which records each class's constructor\nparameter types so the container can resolve them. Without that line providers are\nbuilt with no arguments and boot fails saying so.\n`;\n};\n"
8
- ],
9
- "mappings": "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",
10
- "debugId": "ABE556EA5FD94D1364756E2164756E21",
11
- "names": []
12
- }