create-nifra 2.1.0 → 2.3.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.
Files changed (160) hide show
  1. package/README.md +4 -4
  2. package/dist/agent-files.d.ts +14 -14
  3. package/dist/agent-files.js +29 -29
  4. package/dist/agents.d.ts +4 -4
  5. package/dist/agents.js +63 -63
  6. package/dist/auth.d.ts +2 -2
  7. package/dist/auth.js +8 -8
  8. package/dist/cli.d.ts +6 -6
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +56 -35
  11. package/dist/cli.js.map +1 -1
  12. package/dist/db.d.ts +6 -6
  13. package/dist/db.d.ts.map +1 -1
  14. package/dist/db.js +138 -41
  15. package/dist/db.js.map +1 -1
  16. package/dist/scaffold/features.d.ts +41 -0
  17. package/dist/scaffold/features.d.ts.map +1 -0
  18. package/dist/scaffold/features.js +48 -0
  19. package/dist/scaffold/features.js.map +1 -0
  20. package/dist/scaffold/frameworks.d.ts +73 -0
  21. package/dist/scaffold/frameworks.d.ts.map +1 -0
  22. package/dist/scaffold/frameworks.js +100 -0
  23. package/dist/scaffold/frameworks.js.map +1 -0
  24. package/dist/scaffold/site-build.d.ts +60 -0
  25. package/dist/scaffold/site-build.d.ts.map +1 -0
  26. package/dist/scaffold/site-build.js +198 -0
  27. package/dist/scaffold/site-build.js.map +1 -0
  28. package/dist/scaffold/site-files.d.ts +16 -0
  29. package/dist/scaffold/site-files.d.ts.map +1 -0
  30. package/dist/scaffold/site-files.js +112 -0
  31. package/dist/scaffold/site-files.js.map +1 -0
  32. package/dist/scaffold/site.d.ts +33 -0
  33. package/dist/scaffold/site.d.ts.map +1 -0
  34. package/dist/scaffold/site.js +99 -0
  35. package/dist/scaffold/site.js.map +1 -0
  36. package/package.json +3 -2
  37. package/src/agent-files.ts +149 -0
  38. package/template/README.md +3 -3
  39. package/template/nifra.assurance.ts +80 -0
  40. package/template/package.json +5 -3
  41. package/template/src/app.ts +10 -11
  42. package/template/src/routes.ts +13 -0
  43. package/template-isr/README.md +1 -1
  44. package/template-isr/backend.ts +11 -15
  45. package/template-isr/nifra.assurance.ts +81 -0
  46. package/template-isr/package.json +8 -7
  47. package/template-isr/page.ts +12 -0
  48. package/template-isr/routes/_404.tsx +1 -1
  49. package/template-isr/routes/_layout.tsx +1 -1
  50. package/template-isr/routes/index.tsx +2 -2
  51. package/template-isr/server.ts +1 -1
  52. package/template-isr/worker.ts +2 -2
  53. package/template-isr/wrangler.toml +2 -2
  54. package/template-site/Dockerfile +1 -1
  55. package/template-site/README.md +6 -6
  56. package/template-site/backend.ts +11 -13
  57. package/template-site/counter.ts +16 -0
  58. package/template-site/nifra.assurance.ts +83 -0
  59. package/template-site/nifra.config.ts +1 -1
  60. package/template-site/routes/index.tsx +1 -1
  61. package/template-site/server-node.ts +1 -1
  62. package/template-site/server-vercel.ts +1 -1
  63. package/template-site-preact/README.md +7 -7
  64. package/template-site-preact/nifra.config.ts +1 -1
  65. package/template-site-preact/routes/index.tsx +1 -1
  66. package/template-site-solid/README.md +7 -7
  67. package/template-site-solid/nifra.config.ts +2 -2
  68. package/template-site-solid/routes/index.tsx +1 -1
  69. package/template-site-svelte/README.md +7 -7
  70. package/template-site-svelte/nifra.config.ts +2 -2
  71. package/template-site-svelte/routes/_layout.svelte +1 -1
  72. package/template-site-svelte/routes/index.svelte +1 -1
  73. package/template-site-vue/README.md +7 -7
  74. package/template-site-vue/nifra.config.ts +2 -2
  75. package/template-site-vue/routes/_layout.vue +2 -2
  76. package/template-site-vue/routes/index.vue +3 -3
  77. package/template-site/build-bun.ts +0 -27
  78. package/template-site/build-deno.ts +0 -25
  79. package/template-site/build-node.ts +0 -26
  80. package/template-site/build-vercel.ts +0 -45
  81. package/template-site/build.ts +0 -29
  82. package/template-site/framework.ts +0 -6
  83. package/template-site/package.json +0 -38
  84. package/template-site/tsconfig.json +0 -37
  85. package/template-site-preact/.dockerignore +0 -14
  86. package/template-site-preact/Dockerfile +0 -20
  87. package/template-site-preact/_worker.ts +0 -17
  88. package/template-site-preact/backend.ts +0 -15
  89. package/template-site-preact/build-bun.ts +0 -27
  90. package/template-site-preact/build-deno.ts +0 -25
  91. package/template-site-preact/build-node.ts +0 -26
  92. package/template-site-preact/build-vercel.ts +0 -45
  93. package/template-site-preact/build.ts +0 -29
  94. package/template-site-preact/deno.json +0 -7
  95. package/template-site-preact/framework.ts +0 -6
  96. package/template-site-preact/gitignore +0 -16
  97. package/template-site-preact/package.json +0 -35
  98. package/template-site-preact/server-bun.ts +0 -35
  99. package/template-site-preact/server-deno.ts +0 -38
  100. package/template-site-preact/server-node.ts +0 -40
  101. package/template-site-preact/server-vercel.ts +0 -17
  102. package/template-site-preact/tsconfig.json +0 -38
  103. package/template-site-preact/wrangler.toml +0 -4
  104. package/template-site-solid/.dockerignore +0 -14
  105. package/template-site-solid/Dockerfile +0 -20
  106. package/template-site-solid/_worker.ts +0 -17
  107. package/template-site-solid/backend.ts +0 -15
  108. package/template-site-solid/build-bun.ts +0 -33
  109. package/template-site-solid/build-deno.ts +0 -32
  110. package/template-site-solid/build-node.ts +0 -33
  111. package/template-site-solid/build-vercel.ts +0 -47
  112. package/template-site-solid/build.ts +0 -36
  113. package/template-site-solid/deno.json +0 -7
  114. package/template-site-solid/framework.ts +0 -6
  115. package/template-site-solid/gitignore +0 -16
  116. package/template-site-solid/package.json +0 -35
  117. package/template-site-solid/server-bun.ts +0 -35
  118. package/template-site-solid/server-deno.ts +0 -38
  119. package/template-site-solid/server-node.ts +0 -40
  120. package/template-site-solid/server-vercel.ts +0 -17
  121. package/template-site-solid/tsconfig.json +0 -38
  122. package/template-site-solid/wrangler.toml +0 -4
  123. package/template-site-svelte/.dockerignore +0 -14
  124. package/template-site-svelte/Dockerfile +0 -20
  125. package/template-site-svelte/_worker.ts +0 -17
  126. package/template-site-svelte/backend.ts +0 -15
  127. package/template-site-svelte/build-bun.ts +0 -32
  128. package/template-site-svelte/build-deno.ts +0 -31
  129. package/template-site-svelte/build-node.ts +0 -32
  130. package/template-site-svelte/build-vercel.ts +0 -46
  131. package/template-site-svelte/build.ts +0 -35
  132. package/template-site-svelte/deno.json +0 -7
  133. package/template-site-svelte/framework.ts +0 -6
  134. package/template-site-svelte/gitignore +0 -16
  135. package/template-site-svelte/package.json +0 -35
  136. package/template-site-svelte/server-bun.ts +0 -35
  137. package/template-site-svelte/server-deno.ts +0 -38
  138. package/template-site-svelte/server-node.ts +0 -40
  139. package/template-site-svelte/server-vercel.ts +0 -17
  140. package/template-site-svelte/tsconfig.json +0 -37
  141. package/template-site-svelte/wrangler.toml +0 -4
  142. package/template-site-vue/.dockerignore +0 -14
  143. package/template-site-vue/Dockerfile +0 -20
  144. package/template-site-vue/_worker.ts +0 -17
  145. package/template-site-vue/backend.ts +0 -15
  146. package/template-site-vue/build-bun.ts +0 -37
  147. package/template-site-vue/build-deno.ts +0 -36
  148. package/template-site-vue/build-node.ts +0 -37
  149. package/template-site-vue/build-vercel.ts +0 -54
  150. package/template-site-vue/build.ts +0 -40
  151. package/template-site-vue/deno.json +0 -7
  152. package/template-site-vue/framework.ts +0 -6
  153. package/template-site-vue/gitignore +0 -16
  154. package/template-site-vue/package.json +0 -36
  155. package/template-site-vue/server-bun.ts +0 -35
  156. package/template-site-vue/server-deno.ts +0 -38
  157. package/template-site-vue/server-node.ts +0 -40
  158. package/template-site-vue/server-vercel.ts +0 -17
  159. package/template-site-vue/tsconfig.json +0 -37
  160. package/template-site-vue/wrangler.toml +0 -4
package/dist/db.js CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
- * `--db <preset>` — wire a Drizzle data layer into a freshly scaffolded app, so a human (or a coding
2
+ * `--db <preset>` - wire a Drizzle data layer into a freshly scaffolded app, so a human (or a coding
3
3
  * agent) starts from a correct, production-grade DB setup instead of inventing one. nifra ships NO DB
4
- * abstraction (that belongs to Drizzle/libSQL, not a web framework) — this just bundles the existing
4
+ * abstraction (that belongs to Drizzle/libSQL, not a web framework) - this just bundles the existing
5
5
  * tool, the Redwood-style "batteries available" move: a starter schema, a typed client, a migration
6
6
  * config, scripts, and env, all rip-out-able.
7
7
  *
8
8
  * Three presets, by runtime fit:
9
- * - drizzle-libsql — SQLite that runs EVERYWHERE incl. the edge (local file, or Turso). The default
9
+ * - drizzle-libsql - SQLite that runs EVERYWHERE incl. the edge (local file, or Turso). The default
10
10
  * cross-runtime answer.
11
- * - drizzle-postgres — Postgres (postgres.js) on Bun/Node/Deno.
12
- * - drizzle-sqlite — Bun's built-in `bun:sqlite` (sync, local file). Bun-only.
11
+ * - drizzle-postgres - Postgres (postgres.js) on Bun/Node/Deno.
12
+ * - drizzle-sqlite - Bun's built-in `bun:sqlite` (sync, local file). Bun-only.
13
13
  *
14
14
  * The starter `notes` table follows the production-grade DB defaults for its dialect; what a dialect
15
15
  * can't express inline (CHECK constraints, RLS, uuidv7) is called out in a comment, per those rules.
@@ -50,12 +50,12 @@ export const notes = pgTable("notes", {
50
50
  export type Note = typeof notes.$inferSelect
51
51
  export type NewNote = typeof notes.$inferInsert
52
52
  `;
53
- // SQLite has no UUID/TIMESTAMPTZ/RLS — so: text id (app-generated UUID), millisecond-epoch timestamps
53
+ // SQLite has no UUID/TIMESTAMPTZ/RLS - so: text id (app-generated UUID), millisecond-epoch timestamps
54
54
  // (timestamp_ms mode → JS Date), NOT NULL by default, soft-delete via deleted_at. Shared by the
55
55
  // bun:sqlite and libSQL presets (same dialect). CHECK constraints are deferred to the migration.
56
56
  const SQLITE_SCHEMA = `import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"
57
57
 
58
- // Production-grade starter table (SQLite dialect — see the comment in your DB defaults for what the
58
+ // Production-grade starter table (SQLite dialect - see the comment in your DB defaults for what the
59
59
  // dialect can't enforce inline: CHECK constraints go in the generated migration).
60
60
  export const notes = sqliteTable("notes", {
61
61
  id: text("id")
@@ -77,12 +77,79 @@ export type NewNote = typeof notes.$inferInsert
77
77
  `;
78
78
  // --- typed clients (export \`db\` + re-export the schema) --------------------------------------------
79
79
  // Each prints the same usage header so an agent sees how to wire it (decorate) and query it.
80
- const WIRE_DOC = `// Wire it into your backend ONCE, then read \`c.db\` in handlers:
81
- // import { server } from "@nifrajs/core/server"
82
- // import { db, notes } from "./db"
83
- // export const app = server().decorate("db", db)
84
- // .get("/notes", async (c) => c.db.select().from(notes))
85
- // Never top-level-import this into a routes/ page file (server-only) — reach it via c.db / ctx.api.`;
80
+ // The connection is not imported by route modules directly. \`read.ts\` and \`write.ts\` sit in front of
81
+ // it, and routes import whichever one they need - which is what lets a GET route declare \`db.read\`
82
+ // and nothing else. See the header those files carry for why the split is load-bearing.
83
+ const WIRE_DOC = `// The connection. Route modules do NOT import this file: they import \`./read.ts\` or \`./write.ts\`, so
84
+ // what a route can reach matches what it declares. \`db/read-routes.ts\` shows the shape, and merging it
85
+ // is one line:
86
+ // import { notesRead } from "../db/read-routes.ts"
87
+ // export const app = server().merge(notesRead)
88
+ // Never top-level-import any of this into a routes/ page file (server-only) - reach it via ctx.api.`;
89
+ /**
90
+ * Why the seam is split by access rather than exported as one `db`.
91
+ *
92
+ * `nifra check` works out what a route can reach from the module that REGISTERS it, following its
93
+ * imports. A route may not reach further than it declares, and a GET route may not declare a domain
94
+ * write at all - so a GET registered in a module that can reach a write has no legal declaration and
95
+ * has to be moved. Splitting reads from writes at the seam, and again at the routes, is what keeps
96
+ * every route's reach equal to what it says about itself.
97
+ *
98
+ * The same shape is what makes the policy in `nifra.assurance.ts` bite: `db/write.ts` grants
99
+ * `db.write`, the `authenticated-write` rule demands authentication of anything holding it, and a POST
100
+ * that skips auth fails the check rather than shipping.
101
+ */
102
+ const SEAM_DOC = (access) => `// The ${access} half of the database seam. Routes that ${access === "read" ? "only read" : "write"} import THIS, never \`./index.ts\` -
103
+ // a module that can reach both is a module whose GET routes cannot declare what they reach. Keep the
104
+ // two halves import-disjoint and every route's declaration stays honest.`;
105
+ const DRIZZLE_READ = `${SEAM_DOC("read")}
106
+ import { isNull } from "drizzle-orm"
107
+ import { db } from "./index.ts"
108
+ import { type Note, notes } from "./schema.ts"
109
+
110
+ export const listNotes = async (): Promise<Note[]> =>
111
+ db.select().from(notes).where(isNull(notes.deletedAt))
112
+ `;
113
+ const DRIZZLE_WRITE = `${SEAM_DOC("write")}
114
+ import { db } from "./index.ts"
115
+ import { type NewNote, type Note, notes } from "./schema.ts"
116
+
117
+ export const createNote = async (note: NewNote): Promise<Note | undefined> =>
118
+ (await db.insert(notes).values(note).returning())[0]
119
+ `;
120
+ const READ_ROUTES = `import { server } from "@nifrajs/core/server"
121
+ import { t } from "@nifrajs/schema"
122
+ import { listNotes } from "./read.ts"
123
+
124
+ // Registered here rather than in your app module, because reach is per-module: this file can see the
125
+ // read half of the seam and nothing else, so \`db.read\` is the whole truth about it. Merge it with
126
+ // \`app.merge(notesRead)\`.
127
+ //
128
+ // The path is \`/db/notes\` rather than \`/notes\` on purpose. This module ships UNMERGED as a sample, and
129
+ // \`nifra check\` associates modules with routes by matching the registered PATH across your source - so
130
+ // a sample sharing a path with a route your template already registers would lend it this file's
131
+ // capability reach and fail the check on a route that never touches the database. Rename it to
132
+ // whatever you like once you merge it; just do not collide with a path already in the app.
133
+ export const notesRead = server().get(
134
+ "/db/notes",
135
+ {
136
+ capabilities: ["db.read"],
137
+ response: t.array(t.object({ id: t.string(), title: t.string(), body: t.string() })),
138
+ },
139
+ async () => (await listNotes()).map(({ id, title, body }) => ({ id, title, body })),
140
+ )
141
+
142
+ // Writes go in a SIBLING file that imports \`./write.ts\`, never this one:
143
+ //
144
+ // export const notesWrite = server().post(
145
+ // "/notes",
146
+ // { body: NoteInput, capabilities: ["db.write"] },
147
+ // async (c) => createNote(c.body),
148
+ // )
149
+ //
150
+ // Expect it to fail \`nifra assure\` until it is authenticated - the starter policy requires proof of
151
+ // who asked before anything writes business state. Scaffold auth with \`--auth\`.
152
+ `;
86
153
  const PG_CLIENT = `import { drizzle } from "drizzle-orm/postgres-js"
87
154
  import postgres from "postgres"
88
155
  import * as schema from "./schema.ts"
@@ -91,10 +158,10 @@ ${WIRE_DOC}
91
158
 
92
159
  const url = process.env.DATABASE_URL
93
160
  if (url === undefined || url === "") {
94
- throw new Error("DATABASE_URL is not set — copy .env.example to .env and fill it in.")
161
+ throw new Error("DATABASE_URL is not set - copy .env.example to .env and fill it in.")
95
162
  }
96
163
 
97
- // One pooled client per process (per instance in a multi-instance deploy — fine for Postgres).
164
+ // One pooled client per process (per instance in a multi-instance deploy - fine for Postgres).
98
165
  export const db = drizzle(postgres(url), { schema })
99
166
  export * from "./schema.ts"
100
167
  `;
@@ -104,7 +171,7 @@ import * as schema from "./schema.ts"
104
171
 
105
172
  ${WIRE_DOC}
106
173
 
107
- // Bun's built-in SQLite — sync + fast, local file. (Bun-only; for Node/Deno/edge use the libsql preset.)
174
+ // Bun's built-in SQLite - sync + fast, local file. (Bun-only; for Node/Deno/edge use the libsql preset.)
108
175
  export const db = drizzle(new Database(process.env.DATABASE_URL ?? "local.db"), { schema })
109
176
  export * from "./schema.ts"
110
177
  `;
@@ -114,7 +181,7 @@ import * as schema from "./schema.ts"
114
181
 
115
182
  ${WIRE_DOC}
116
183
 
117
- // libSQL runs everywhere — a local file (file:local.db), a remote Turso URL (libsql://…) with an auth
184
+ // libSQL runs everywhere - a local file (file:local.db), a remote Turso URL (libsql://…) with an auth
118
185
  // token, or an embedded replica. The one SQLite client that also works on the edge (Cloudflare Workers).
119
186
  const token = process.env.DATABASE_AUTH_TOKEN
120
187
  export const db = drizzle(
@@ -172,7 +239,7 @@ DATABASE_URL="file:local.db"
172
239
  # DATABASE_AUTH_TOKEN="your-token"
173
240
  `;
174
241
  // --- Prisma presets ---------------------------------------------------------------------------------
175
- // Prisma owns its schema DSL (prisma/schema.prisma), client codegen, and migration engine — so the
242
+ // Prisma owns its schema DSL (prisma/schema.prisma), client codegen, and migration engine - so the
176
243
  // scaffold is schema + a singleton client + the prisma scripts (no drizzle-kit equivalent needed).
177
244
  const PRISMA_CLIENT_VERSION = "^6.5.0";
178
245
  const PRISMA_SCRIPTS = {
@@ -213,7 +280,7 @@ generator client {
213
280
  provider = "prisma-client-js"
214
281
  }
215
282
 
216
- // Production-grade starter model (SQLite dialect — no native UUID/TIMESTAMPTZ/RLS; Prisma stores the
283
+ // Production-grade starter model (SQLite dialect - no native UUID/TIMESTAMPTZ/RLS; Prisma stores the
217
284
  // String id + DateTime stamps for you). NOT NULL by default, soft-delete via deletedAt. CHECK
218
285
  // constraints are deferred to the generated migration SQL.
219
286
  model Note {
@@ -227,14 +294,20 @@ model Note {
227
294
  @@map("notes")
228
295
  }
229
296
  `;
297
+ const PRISMA_READ = `${SEAM_DOC("read")}
298
+ import { db } from "./index.ts"
299
+
300
+ export const listNotes = async () => db.note.findMany({ where: { deletedAt: null } })
301
+ `;
302
+ const PRISMA_WRITE = `${SEAM_DOC("write")}
303
+ import { db } from "./index.ts"
304
+
305
+ export const createNote = async (note: { title: string; body?: string }) =>
306
+ db.note.create({ data: note })
307
+ `;
230
308
  const PRISMA_CLIENT = `import { PrismaClient } from "@prisma/client"
231
309
 
232
- // Wire it into your backend ONCE, then read \`c.db\` in handlers:
233
- // import { server } from "@nifrajs/core/server"
234
- // import { db } from "./db"
235
- // export const app = server().decorate("db", db)
236
- // .get("/notes", async (c) => c.db.note.findMany({ where: { deletedAt: null } }))
237
- // Never top-level-import this into a routes/ page file (server-only) — reach it via c.db / ctx.api.
310
+ ${WIRE_DOC}
238
311
 
239
312
  // One PrismaClient per process. The globalThis guard stops dev hot-reload from opening a new connection
240
313
  // pool on every reload (which exhausts the DB); production gets a single fresh instance.
@@ -274,24 +347,30 @@ export interface DB {
274
347
  notes: NotesTable
275
348
  }
276
349
  `;
350
+ const KYSELY_READ = `${SEAM_DOC("read")}
351
+ import { db } from "./index.ts"
352
+
353
+ export const listNotes = async () =>
354
+ db.selectFrom("notes").selectAll().where("deleted_at", "is", null).execute()
355
+ `;
356
+ const KYSELY_WRITE = `${SEAM_DOC("write")}
357
+ import { db } from "./index.ts"
358
+
359
+ export const createNote = async (note: { title: string; body?: string }) =>
360
+ db.insertInto("notes").values(note).returningAll().executeTakeFirst()
361
+ `;
277
362
  const KYSELY_PG_CLIENT = `import { Kysely, PostgresDialect } from "kysely"
278
363
  import { Pool } from "pg"
279
364
  import type { DB } from "./schema.ts"
280
365
 
281
- // Wire it into your backend ONCE, then read \`c.db\` in handlers:
282
- // import { server } from "@nifrajs/core/server"
283
- // import { db } from "./db"
284
- // export const app = server().decorate("db", db)
285
- // .get("/notes", async (c) =>
286
- // c.db.selectFrom("notes").selectAll().where("deleted_at", "is", null).execute())
287
- // Never top-level-import this into a routes/ page file (server-only) — reach it via c.db / ctx.api.
366
+ ${WIRE_DOC}
288
367
 
289
368
  const url = process.env.DATABASE_URL
290
369
  if (url === undefined || url === "") {
291
- throw new Error("DATABASE_URL is not set — copy .env.example to .env and fill it in.")
370
+ throw new Error("DATABASE_URL is not set - copy .env.example to .env and fill it in.")
292
371
  }
293
372
 
294
- // One pooled client per process (per instance in a multi-instance deploy — fine for Postgres).
373
+ // One pooled client per process (per instance in a multi-instance deploy - fine for Postgres).
295
374
  export const db = new Kysely<DB>({
296
375
  dialect: new PostgresDialect({ pool: new Pool({ connectionString: url }) }),
297
376
  })
@@ -299,7 +378,7 @@ export type { DB } from "./schema.ts"
299
378
  `;
300
379
  const KYSELY_MIGRATION = `import { type Kysely, sql } from "kysely"
301
380
 
302
- // Production-grade starter table. Postgres: UUID PK (gen_random_uuid — swap to gen_uuidv7() for insert
381
+ // Production-grade starter table. Postgres: UUID PK (gen_random_uuid - swap to gen_uuidv7() for insert
303
382
  // locality on hot tables once available), TIMESTAMPTZ stamps, NOT NULL by default, soft-delete via
304
383
  // deleted_at. Add CHECK constraints (e.g. length caps) and RLS here per your DB defaults.
305
384
  export async function up(db: Kysely<unknown>): Promise<void> {
@@ -356,6 +435,9 @@ export const DB_PRESETS = {
356
435
  files: {
357
436
  "db/schema.ts": SQLITE_SCHEMA,
358
437
  "db/index.ts": LIBSQL_CLIENT,
438
+ "db/read.ts": DRIZZLE_READ,
439
+ "db/write.ts": DRIZZLE_WRITE,
440
+ "db/read-routes.ts": READ_ROUTES,
359
441
  "drizzle.config.ts": LIBSQL_CONFIG,
360
442
  ".env.example": LIBSQL_ENV,
361
443
  },
@@ -364,13 +446,16 @@ export const DB_PRESETS = {
364
446
  label: "Drizzle + Postgres",
365
447
  orm: "drizzle",
366
448
  dialect: "postgres",
367
- note: "Postgres (postgres.js) on Bun/Node/Deno — not the edge.",
449
+ note: "Postgres (postgres.js) on Bun/Node/Deno - not the edge.",
368
450
  deps: { "drizzle-orm": DRIZZLE_ORM, postgres: "^3.4.5" },
369
451
  devDeps: { "drizzle-kit": DRIZZLE_KIT },
370
452
  scripts: SCRIPTS,
371
453
  files: {
372
454
  "db/schema.ts": PG_SCHEMA,
373
455
  "db/index.ts": PG_CLIENT,
456
+ "db/read.ts": DRIZZLE_READ,
457
+ "db/write.ts": DRIZZLE_WRITE,
458
+ "db/read-routes.ts": READ_ROUTES,
374
459
  "drizzle.config.ts": PG_CONFIG,
375
460
  ".env.example": PG_ENV,
376
461
  },
@@ -379,13 +464,16 @@ export const DB_PRESETS = {
379
464
  label: "Drizzle + SQLite (bun:sqlite)",
380
465
  orm: "drizzle",
381
466
  dialect: "sqlite",
382
- note: "Bun's built-in SQLite — local file, Bun-only.",
467
+ note: "Bun's built-in SQLite - local file, Bun-only.",
383
468
  deps: { "drizzle-orm": DRIZZLE_ORM },
384
469
  devDeps: { "drizzle-kit": DRIZZLE_KIT },
385
470
  scripts: SCRIPTS,
386
471
  files: {
387
472
  "db/schema.ts": SQLITE_SCHEMA,
388
473
  "db/index.ts": SQLITE_CLIENT,
474
+ "db/read.ts": DRIZZLE_READ,
475
+ "db/write.ts": DRIZZLE_WRITE,
476
+ "db/read-routes.ts": READ_ROUTES,
389
477
  "drizzle.config.ts": SQLITE_CONFIG,
390
478
  ".env.example": SQLITE_ENV,
391
479
  },
@@ -394,13 +482,16 @@ export const DB_PRESETS = {
394
482
  label: "Prisma + Postgres",
395
483
  orm: "prisma",
396
484
  dialect: "postgres",
397
- note: "Prisma ORM on Postgres (Bun/Node/Deno) — own schema DSL, migrate engine, and Studio.",
485
+ note: "Prisma ORM on Postgres (Bun/Node/Deno) - own schema DSL, migrate engine, and Studio.",
398
486
  deps: { "@prisma/client": PRISMA_CLIENT_VERSION },
399
487
  devDeps: { prisma: PRISMA_CLIENT_VERSION },
400
488
  scripts: PRISMA_SCRIPTS,
401
489
  files: {
402
490
  "prisma/schema.prisma": PRISMA_PG_SCHEMA,
403
491
  "db/index.ts": PRISMA_CLIENT,
492
+ "db/read.ts": PRISMA_READ,
493
+ "db/write.ts": PRISMA_WRITE,
494
+ "db/read-routes.ts": READ_ROUTES,
404
495
  ".env.example": PRISMA_PG_ENV,
405
496
  },
406
497
  },
@@ -408,13 +499,16 @@ export const DB_PRESETS = {
408
499
  label: "Prisma + SQLite",
409
500
  orm: "prisma",
410
501
  dialect: "sqlite",
411
- note: "Prisma ORM on a local SQLite file — fastest start; migrate to Postgres later by swapping the datasource.",
502
+ note: "Prisma ORM on a local SQLite file - fastest start; migrate to Postgres later by swapping the datasource.",
412
503
  deps: { "@prisma/client": PRISMA_CLIENT_VERSION },
413
504
  devDeps: { prisma: PRISMA_CLIENT_VERSION },
414
505
  scripts: PRISMA_SCRIPTS,
415
506
  files: {
416
507
  "prisma/schema.prisma": PRISMA_SQLITE_SCHEMA,
417
508
  "db/index.ts": PRISMA_CLIENT,
509
+ "db/read.ts": PRISMA_READ,
510
+ "db/write.ts": PRISMA_WRITE,
511
+ "db/read-routes.ts": READ_ROUTES,
418
512
  ".env.example": PRISMA_SQLITE_ENV,
419
513
  },
420
514
  },
@@ -422,13 +516,16 @@ export const DB_PRESETS = {
422
516
  label: "Kysely + Postgres",
423
517
  orm: "kysely",
424
518
  dialect: "postgres",
425
- note: "Kysely typed query builder on Postgres (node-postgres) — you own the schema types + migrations.",
519
+ note: "Kysely typed query builder on Postgres (node-postgres) - you own the schema types + migrations.",
426
520
  deps: { kysely: KYSELY_VERSION, pg: "^8.13.1" },
427
521
  devDeps: { "@types/pg": "^8.11.10" },
428
522
  scripts: KYSELY_SCRIPTS,
429
523
  files: {
430
524
  "db/schema.ts": KYSELY_PG_SCHEMA,
431
525
  "db/index.ts": KYSELY_PG_CLIENT,
526
+ "db/read.ts": KYSELY_READ,
527
+ "db/write.ts": KYSELY_WRITE,
528
+ "db/read-routes.ts": READ_ROUTES,
432
529
  "db/migrate.ts": KYSELY_MIGRATE_RUNNER,
433
530
  "db/migrations/0001_create_notes.ts": KYSELY_MIGRATION,
434
531
  ".env.example": PG_ENV,
@@ -458,7 +555,7 @@ export async function writeDbFiles(target, choice) {
458
555
  current = await readFile(gitignorePath, "utf8");
459
556
  }
460
557
  catch {
461
- // No .gitignore in this template — create one with just the DB block.
558
+ // No .gitignore in this template - create one with just the DB block.
462
559
  }
463
560
  if (!current.includes("local.db")) {
464
561
  await writeFile(gitignorePath, `${current}${GITIGNORE_BLOCK}`);
package/dist/db.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * What a feature adds to a scaffold's manifest, and the one place those additions are merged.
3
+ *
4
+ * `--db`, `--auth`, `--deploy` and `--ci` each used to reach into the parsed `package.json` and spread
5
+ * themselves over it, in an order fixed by the line they appeared on. That works until two of them
6
+ * want the same key: the later spread wins, silently, and a preset that shadowed the scaffold's own
7
+ * `check` script would remove the assurance gate from every project scaffolded with it. No preset does
8
+ * that today - all six were checked - which is exactly when to put the rail in.
9
+ *
10
+ * So a contribution says what it adds, and REPLACING an existing key has to be declared. A collision
11
+ * nobody declared is an error rather than a last-writer-wins race between two option handlers.
12
+ */
13
+ export interface FeatureContribution {
14
+ /** How the feature names itself in a collision error, e.g. `--db drizzle-libsql`. */
15
+ readonly label: string;
16
+ readonly dependencies?: Readonly<Record<string, string>>;
17
+ readonly devDependencies?: Readonly<Record<string, string>>;
18
+ readonly scripts?: Readonly<Record<string, string>>;
19
+ /**
20
+ * Keys this feature intends to overwrite. `--deploy` repoints `build` and `deploy` at the chosen
21
+ * target, which is the whole point of the flag - so it says so, and every other collision stays an
22
+ * error. The distinction is the feature: declared replacement is a decision, silent replacement is
23
+ * the bug this exists to catch.
24
+ */
25
+ readonly replaces?: readonly string[];
26
+ }
27
+ export interface ScaffoldManifest {
28
+ name?: string;
29
+ scripts?: Record<string, string>;
30
+ dependencies?: Record<string, string>;
31
+ devDependencies?: Record<string, string>;
32
+ }
33
+ /**
34
+ * Merge every feature's contribution into the scaffold's manifest.
35
+ *
36
+ * Applied in order, but the order no longer decides anything: a key two features both want, or a key a
37
+ * feature would take from the scaffold without saying so, throws naming both sides. That turns a
38
+ * question you would have to reason about into one the scaffolder answers.
39
+ */
40
+ export declare function applyFeatures(manifest: ScaffoldManifest, contributions: readonly FeatureContribution[]): void;
41
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../src/scaffold/features.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,mBAAmB;IAClC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzC;AAID;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,SAAS,mBAAmB,EAAE,GAC5C,IAAI,CA4BN"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * What a feature adds to a scaffold's manifest, and the one place those additions are merged.
3
+ *
4
+ * `--db`, `--auth`, `--deploy` and `--ci` each used to reach into the parsed `package.json` and spread
5
+ * themselves over it, in an order fixed by the line they appeared on. That works until two of them
6
+ * want the same key: the later spread wins, silently, and a preset that shadowed the scaffold's own
7
+ * `check` script would remove the assurance gate from every project scaffolded with it. No preset does
8
+ * that today - all six were checked - which is exactly when to put the rail in.
9
+ *
10
+ * So a contribution says what it adds, and REPLACING an existing key has to be declared. A collision
11
+ * nobody declared is an error rather than a last-writer-wins race between two option handlers.
12
+ */
13
+ const SECTIONS = ["scripts", "dependencies", "devDependencies"];
14
+ /**
15
+ * Merge every feature's contribution into the scaffold's manifest.
16
+ *
17
+ * Applied in order, but the order no longer decides anything: a key two features both want, or a key a
18
+ * feature would take from the scaffold without saying so, throws naming both sides. That turns a
19
+ * question you would have to reason about into one the scaffolder answers.
20
+ */
21
+ export function applyFeatures(manifest, contributions) {
22
+ /** Who last wrote each key, so a collision can name the other side rather than just the winner. */
23
+ const owner = new Map();
24
+ for (const section of SECTIONS) {
25
+ for (const key of Object.keys(manifest[section] ?? {}))
26
+ owner.set(`${section}.${key}`, "the scaffold");
27
+ }
28
+ for (const contribution of contributions) {
29
+ const declared = new Set(contribution.replaces ?? []);
30
+ for (const section of SECTIONS) {
31
+ const additions = contribution[section];
32
+ if (additions === undefined)
33
+ continue;
34
+ manifest[section] ??= {};
35
+ const target = manifest[section];
36
+ for (const [key, value] of Object.entries(additions)) {
37
+ const previous = owner.get(`${section}.${key}`);
38
+ if (previous !== undefined && !declared.has(key) && target[key] !== value) {
39
+ throw new Error(`${contribution.label} would overwrite ${section}.${key} from ${previous}. ` +
40
+ "Declare it in `replaces` if that is intended.");
41
+ }
42
+ target[key] = value;
43
+ owner.set(`${section}.${key}`, contribution.label);
44
+ }
45
+ }
46
+ }
47
+ }
48
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/scaffold/features.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAwBH,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAU,CAAA;AAExE;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA0B,EAC1B,aAA6C;IAE7C,mGAAmG;IACnG,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAA;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACpD,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,GAAG,EAAE,EAAE,cAAc,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;QACrD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACvC,IAAI,SAAS,KAAK,SAAS;gBAAE,SAAQ;YACrC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;YAChC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;gBACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;gBAC/C,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;oBAC1E,MAAM,IAAI,KAAK,CACb,GAAG,YAAY,CAAC,KAAK,oBAAoB,OAAO,IAAI,GAAG,SAAS,QAAQ,IAAI;wBAC1E,+CAA+C,CAClD,CAAA;gBACH,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;gBACnB,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,GAAG,EAAE,EAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YACpD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * What a frontend framework contributes to a site scaffold.
3
+ *
4
+ * The five site templates were five directories of 26 files each, and 13 of those 26 were
5
+ * byte-identical in all five - the Dockerfile, every server entry, the worker, the assurance config.
6
+ * Editing the runtime story meant editing it five times and hoping. This session made the same
7
+ * one-line `package.json` edit in eight files, which is the whole argument.
8
+ *
9
+ * So the runtime knowledge lives once (see `site.ts`), and a framework contributes only what is
10
+ * genuinely its own: an adapter, a bundler plugin, the resolve conditions and defines its compiler
11
+ * needs, and its dependency set. The prose a framework needs to explain ITSELF - why Solid wants a
12
+ * `"solid"` resolve condition, what `@preact/preset-vite` is - stays in a real file next to it. That
13
+ * is the line: mechanical differences are modelled, explanations are written.
14
+ */
15
+ /** A `plugins: [x("dom")]` entry the framework's compiler needs in a Bun build. */
16
+ export interface BunPluginSpec {
17
+ /** Module the plugin factory is imported from. */
18
+ readonly specifier: string;
19
+ /** The factory's exported name. */
20
+ readonly name: string;
21
+ /** Trailing comment on the call, when the framework has something to say about it. */
22
+ readonly note?: {
23
+ readonly dom: string;
24
+ readonly ssr: string;
25
+ };
26
+ }
27
+ export interface FrameworkSpec {
28
+ readonly id: string;
29
+ /** The adapter export, e.g. `reactAdapter`. */
30
+ readonly adapter: string;
31
+ /** The adapter's package, e.g. `@nifrajs/web-react`. */
32
+ readonly package: string;
33
+ /** Compiler plugin for `.vue`/`.svelte`/Solid JSX. Absent for the JSX-native frameworks. */
34
+ readonly bunPlugin?: BunPluginSpec;
35
+ /** Resolve conditions this framework adds beyond the runtime's own. */
36
+ readonly conditions?: {
37
+ readonly client?: readonly string[];
38
+ readonly ssr?: readonly string[];
39
+ };
40
+ /** Build-time defines beyond `process.env.NODE_ENV`, in emission order. */
41
+ readonly define?: Readonly<Record<string, string>>;
42
+ /** Comment above the hoisted `define`, when the framework's flags need explaining. */
43
+ readonly defineNote?: string;
44
+ /** Runtime dependencies beyond the shared Nifra set, in emission order. */
45
+ readonly runtimeDependencies: Readonly<Record<string, string>>;
46
+ /** Dev dependencies beyond `@nifrajs/cli`, `typescript` and `vite`, in emission order. */
47
+ readonly devDependencies: Readonly<Record<string, string>>;
48
+ /** What this framework needs from `tsconfig.json`. */
49
+ readonly typescript: {
50
+ readonly jsx?: string;
51
+ readonly jsxImportSource?: string;
52
+ readonly types?: readonly string[];
53
+ /** False when routes are not `.tsx` - Svelte's are `.svelte`, so the glob would match nothing. */
54
+ readonly includeTsx?: boolean;
55
+ };
56
+ }
57
+ /**
58
+ * The `@nifrajs/*` range a scaffolded site installs.
59
+ *
60
+ * One constant, because it used to be a regex sweep over eight `package.json` files in the release
61
+ * script with nothing checking the result - and the script's own comment warns that a missed bump
62
+ * ships templates installing the PREVIOUS release. `scaffold-version.test.ts` now fails when this
63
+ * drifts from what core is publishing, so the footgun is a red test rather than a silent regression.
64
+ */
65
+ export declare const NIFRA_DEP_RANGE = "^2.3.0";
66
+ /**
67
+ * React is first because it is the default (`--framework` omitted scaffolds it), and because the
68
+ * other four are most easily read as deltas from it.
69
+ */
70
+ export declare const FRAMEWORK_SPECS: Readonly<Record<string, FrameworkSpec>>;
71
+ export declare const FRAMEWORK_IDS: string[];
72
+ export declare function frameworkSpec(id: string): FrameworkSpec;
73
+ //# sourceMappingURL=frameworks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../../src/scaffold/frameworks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAA;IAC/F,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAClD,sFAAsF;IACtF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9D,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1D,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE;QACnB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;QACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAClC,kGAAkG;QAClG,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAC9B,CAAA;CACF;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,WAAW,CAAA;AAEvC;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAgEnE,CAAA;AAED,eAAO,MAAM,aAAa,UAA+B,CAAA;AAEzD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAMvD"}