create-newt-app 0.35.5 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { existsSync, promises, readdirSync } from "fs";
11
11
  import path from "path";
12
12
  import https from "node:https";
13
13
  //#region package.json
14
- var version = "0.35.5";
14
+ var version = "0.36.0";
15
15
  var engines = { "node": ">=24.0.0" };
16
16
  //#endregion
17
17
  //#region src/templates/root/index.ts
@@ -177,44 +177,71 @@ pnpm dev
177
177
  \`\`\`
178
178
 
179
179
  Open [http://localhost:3000](http://localhost:3000).
180
- <% if (deployment === 'spa') { -%>
180
+ <% if (deployment === 'none') { -%>
181
181
 
182
- ## Production build
182
+ ## Production
183
+
184
+ \`\`\`sh
185
+ pnpm db:migrate && pnpm build
186
+ pnpm --filter @<%= projectName %>/web start
187
+ \`\`\`
188
+
189
+ Open [http://localhost:3000](http://localhost:3000).
190
+ <% } else if (deployment === 'spa') { -%>
191
+
192
+ ## Production
183
193
 
184
194
  NestJS serves the static export and the API from one origin, so point \`BETTER_AUTH_URL\` at it:
185
195
 
186
196
  \`\`\`sh
187
- pnpm db:migrate
188
- pnpm build
197
+ pnpm db:migrate && pnpm build
189
198
  cd apps/api
190
199
  BETTER_AUTH_URL=http://localhost:3001 pnpm start:prod
191
200
  \`\`\`
192
201
 
193
202
  Open [http://localhost:3001](http://localhost:3001). In a real deployment, set \`BETTER_AUTH_URL\` to the public URL.
203
+ <% } else if (deployment === 'standalone') { -%>
204
+
205
+ ## Production
206
+
207
+ \`\`\`sh
208
+ docker compose up --build
209
+ \`\`\`
210
+
211
+ The \`migrate\` service applies migrations before the app starts. Open [http://localhost:3000](http://localhost:3000); set \`BETTER_AUTH_URL\` to the public URL in a real deployment.
194
212
  <% } -%>
195
213
 
196
- ## Apps
214
+ ## Commands
197
215
 
198
- - **web**: Next.js frontend (port 3000)
216
+ - \`pnpm dev\`: run in development
217
+ - \`pnpm build\`, \`pnpm typecheck\`, \`pnpm test\`: build, type-check, and test every workspace
218
+ - \`pnpm lint:check\`: lint (fails on errors); \`pnpm format:fix\`: apply formatting
219
+ - \`pnpm db:migrate\`: run migrations; \`pnpm db:make <name>\`: scaffold a new one
199
220
  <% if (nest === 'on') { -%>
200
- - **api**: NestJS backend (port 3001)
201
- <% } else if (nest === 'di-only') { -%>
202
- - **api**: NestJS providers, resolved from the web process (no HTTP server)
221
+ - \`pnpm --filter @<%= projectName %>/api test:e2e\`: run the e2e suite
203
222
  <% } -%>
204
223
 
205
- ## Packages
224
+ ## Environment
206
225
 
207
- - **\`@<%= projectName %>/auth\`**: better-auth config
208
- - **\`@<%= projectName %>/db\`**: Kysely client and migrations
209
- - **\`@<%= projectName %>/ui\`**: shared React components
210
- <% if (linter === 'eslint') { -%>
211
- - **\`@<%= projectName %>/eslint-config\`**: shared ESLint config
226
+ Set in \`.env\` (a committed \`.env.example\` documents each one):
227
+
228
+ - **BETTER_AUTH_URL**: the public origin of the app
229
+ - **BETTER_AUTH_SECRET**: a random secret used to sign sessions
230
+ <% if (database === 'postgres') { -%>
231
+ - **DATABASE_URL**: your Postgres connection string
232
+ <% } else { -%>
233
+ - **DATABASE_URL**: not set for SQLite (the app uses \`dev.db\` at the repo root); set it to a Postgres URL to use Postgres
212
234
  <% } -%>
213
- - **\`@<%= projectName %>/typescript-config\`**: shared tsconfig
214
235
 
215
- ## Formatting
236
+ ## Layout
216
237
 
217
- \`pnpm format\` checks without modifying files and fails if any file is unformatted; \`pnpm format:fix\` applies formatting.
238
+ - **\`apps/web\`**: Next.js frontend (port 3000)
239
+ <% if (nest === 'on') { -%>
240
+ - **\`apps/api\`**: NestJS backend (port 3001)
241
+ <% } else if (nest === 'di-only') { -%>
242
+ - **\`apps/api\`**: NestJS providers, resolved in-process by the web app
243
+ <% } -%>
244
+ - **\`packages/\`**: \`auth\`, \`db\`, \`ui\`<% if (linter === 'eslint') { %>, \`eslint-config\`<% } %>, and shared \`typescript-config\`
218
245
  `
219
246
  },
220
247
  {
@@ -252,7 +279,24 @@ Read \`docs/README.md\` inside that installed package first, then read the relev
252
279
  This block is written and re-added by \`turbo\` before repository-scoped commands when an AI agent is detected. In the Turborepo source repository, its template is defined in \`crates/turborepo-cli/src/cli/agent_guidance.rs\`. Removing the managed block while updates are enabled means a later qualifying invocation will add it again. Set \`"agentGuidance": false\` in the root \`turbo.json\` or \`turbo.jsonc\` to opt out; this does not remove an existing block. Keep the block committed with your work to avoid an uncommitted change on the next agent invocation.
253
280
  <!-- END:turborepo-agent-rules --><% if (shadcn) { %>
254
281
 
255
- After making changes, run \`pnpm lint:check\` and fix all errors.<% } %>`
282
+ After making changes, run \`pnpm lint:check\` and fix all errors.<% } %>
283
+
284
+ # Project notes
285
+
286
+ - **web** runs on port 3000<% if (nest === 'on') { %>; **api** (NestJS) runs on port 3001<% } %>.
287
+ <% if (nest === 'on') { -%>
288
+ - In development, \`apps/web\` rewrites \`/api/*\` to \`http://localhost:3001/api/*\` (see \`apps/web/next.config.js\`). The backend is a separate process; start both from the repo root with \`pnpm dev\`.
289
+ <% } else if (nest === 'di-only') { -%>
290
+ - There is no separate backend process. API routes are Next.js route handlers that resolve NestJS providers in-process.
291
+ <% } else { -%>
292
+ - There is no backend. API routes are served in-process by Next.js route handlers.
293
+ <% } -%>
294
+ - Migrations live in \`packages/db\`. Run \`pnpm db:migrate\`; scaffold a new one with \`pnpm db:make <name>\`.
295
+ - Environment is read from the root \`.env\` (see \`.env.example\`): \`DATABASE_URL\`, \`BETTER_AUTH_URL\`, \`BETTER_AUTH_SECRET\`.
296
+ <% if (nest !== 'off') { -%>
297
+ - NestJS controllers must validate request bodies with a schema (the api registers a global \`StandardSchemaValidationPipe\`); keep the todo controller as the reference for how to do it.
298
+ <% } -%>
299
+ `
256
300
  },
257
301
  {
258
302
  filename: "CLAUDE.md",
@@ -260,13 +304,11 @@ After making changes, run \`pnpm lint:check\` and fix all errors.<% } %>`
260
304
  }
261
305
  ] };
262
306
  //#endregion
263
- //#region src/templates/web/index.ts
264
- const web$1 = {
265
- templates: [
266
- {
267
- when: (s) => s.nest !== "di-only" && !s.stylex,
268
- filename: "apps/web/package.json",
269
- template: `{
307
+ //#region src/templates/web/templates/package-json.ts
308
+ var package_json_default$7 = {
309
+ when: (s) => s.nest !== "di-only" && !s.stylex,
310
+ filename: "apps/web/package.json",
311
+ template: `{
270
312
  "name": "web",
271
313
  "version": "0.1.0",
272
314
  "type": "module",
@@ -298,10 +340,12 @@ const web$1 = {
298
340
  "typescript": "<%= versions.typescript %>"
299
341
  }
300
342
  }`
301
- },
302
- {
303
- filename: "apps/web/.gitignore",
304
- template: `# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
343
+ };
344
+ //#endregion
345
+ //#region src/templates/web/templates/gitignore.ts
346
+ var gitignore_default = {
347
+ filename: "apps/web/.gitignore",
348
+ template: `# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
305
349
 
306
350
  # dependencies
307
351
  /node_modules
@@ -337,50 +381,13 @@ yarn-error.log*
337
381
  # typescript
338
382
  *.tsbuildinfo
339
383
  next-env.d.ts`
340
- },
341
- {
342
- filename: "apps/web/README.md",
343
- template: `This is a [Next.js](https://nextjs.org) project bootstrapped with [\`create-next-app\`](https://nextjs.org/docs/app/api-reference/create-next-app).
344
-
345
- ## Getting Started
346
-
347
- First, run the development server:
348
-
349
- \`\`\`bash
350
- npm run dev
351
- # or
352
- yarn dev
353
- # or
354
- pnpm dev
355
- # or
356
- bun dev
357
- \`\`\`
358
-
359
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
360
-
361
- You can start editing the page by modifying \`app/page.tsx\`. The page auto-updates as you edit the file.
362
-
363
- This project uses [\`next/font\`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font.
364
-
365
- ## Learn More
366
-
367
- To learn more about Next.js, take a look at the following resources:
368
-
369
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
370
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
371
-
372
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
373
-
374
- ## Deploy on Vercel
375
-
376
- The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
377
-
378
- Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.`
379
- },
380
- {
381
- when: (s) => s.deployment === "none" && s.nest === "on",
382
- filename: "apps/web/next.config.js",
383
- template: `import dotenv from 'dotenv';
384
+ };
385
+ //#endregion
386
+ //#region src/templates/web/templates/next-config.ts
387
+ var next_config_default$2 = {
388
+ when: (s) => s.deployment === "none" && s.nest === "on",
389
+ filename: "apps/web/next.config.js",
390
+ template: `import dotenv from 'dotenv';
384
391
  import { resolve } from 'path';
385
392
 
386
393
  // Load root .env first, then local .env (local takes precedence)
@@ -400,16 +407,20 @@ const nextConfig = {
400
407
  };
401
408
 
402
409
  export default nextConfig;`
403
- },
404
- {
405
- when: (s) => !s.stylex,
406
- filename: "apps/web/postcss.config.mjs",
407
- template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
408
- },
409
- {
410
- when: (s) => s.nest !== "di-only",
411
- filename: "apps/web/tsconfig.json",
412
- template: `{
410
+ };
411
+ //#endregion
412
+ //#region src/templates/web/templates/postcss-config.ts
413
+ var postcss_config_default$3 = {
414
+ when: (s) => !s.stylex,
415
+ filename: "apps/web/postcss.config.mjs",
416
+ template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
417
+ };
418
+ //#endregion
419
+ //#region src/templates/web/templates/tsconfig.ts
420
+ var tsconfig_default$5 = {
421
+ when: (s) => s.nest !== "di-only",
422
+ filename: "apps/web/tsconfig.json",
423
+ template: `{
413
424
  "extends": "@<%= projectName %>/typescript-config/nextjs.json",
414
425
  "compilerOptions": {
415
426
  "plugins": [
@@ -431,11 +442,13 @@ export default nextConfig;`
431
442
  ],
432
443
  "exclude": ["node_modules"]
433
444
  }`
434
- },
435
- {
436
- when: (s) => !s.shadcn && !s.stylex,
437
- filename: "apps/web/app/layout.tsx",
438
- template: `import type { Metadata } from "next";
445
+ };
446
+ //#endregion
447
+ //#region src/templates/web/templates/layout.ts
448
+ var layout_default$2 = {
449
+ when: (s) => !s.shadcn && !s.stylex,
450
+ filename: "apps/web/app/layout.tsx",
451
+ template: `import type { Metadata } from "next";
439
452
  import localFont from "next/font/local";
440
453
  import Providers from "@/app/providers";
441
454
  import "@<%= projectName %>/ui/globals.css";
@@ -478,11 +491,13 @@ export default function RootLayout({
478
491
  </html>
479
492
  );
480
493
  }`
481
- },
482
- {
483
- when: (s) => !s.todoExample && !s.shadcn && !s.stylex,
484
- filename: "apps/web/app/page.tsx",
485
- template: `'use client';
494
+ };
495
+ //#endregion
496
+ //#region src/templates/web/templates/page.ts
497
+ var page_default$2 = {
498
+ when: (s) => !s.todoExample && !s.shadcn && !s.stylex,
499
+ filename: "apps/web/app/page.tsx",
500
+ template: `'use client';
486
501
 
487
502
  import { useQuery } from '@tanstack/react-query';
488
503
  import { authClient } from '@/lib/auth-client';
@@ -590,11 +605,13 @@ export default function Home() {
590
605
  </main>
591
606
  );
592
607
  }`
593
- },
594
- {
595
- when: (s) => !s.shadcn,
596
- filename: "apps/web/app/providers.tsx",
597
- template: `'use client';
608
+ };
609
+ //#endregion
610
+ //#region src/templates/web/templates/providers.ts
611
+ var providers_default$1 = {
612
+ when: (s) => !s.shadcn,
613
+ filename: "apps/web/app/providers.tsx",
614
+ template: `'use client';
598
615
 
599
616
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
600
617
  import { useState } from 'react';
@@ -603,11 +620,13 @@ export default function Providers({ children }: { children: React.ReactNode }) {
603
620
  const [client] = useState(() => new QueryClient());
604
621
  return <QueryClientProvider client={client}>{children}</QueryClientProvider>;
605
622
  }`
606
- },
607
- {
608
- when: (s) => !s.shadcn && !s.stylex,
609
- filename: "apps/web/app/auth-form.tsx",
610
- template: `'use client';
623
+ };
624
+ //#endregion
625
+ //#region src/templates/web/templates/auth-form.ts
626
+ var auth_form_default$2 = {
627
+ when: (s) => !s.shadcn && !s.stylex,
628
+ filename: "apps/web/app/auth-form.tsx",
629
+ template: `'use client';
611
630
 
612
631
  import { useForm } from '@tanstack/react-form';
613
632
  import { useState } from 'react';
@@ -735,23 +754,29 @@ export function AuthForm() {
735
754
  </>
736
755
  );
737
756
  }`
738
- },
739
- {
740
- filename: "apps/web/app/api/auth/[...all]/route.ts",
741
- template: `import { auth } from "@<%= projectName %>/auth";
757
+ };
758
+ //#endregion
759
+ //#region src/templates/web/templates/auth-route.ts
760
+ var auth_route_default = {
761
+ filename: "apps/web/app/api/auth/[...all]/route.ts",
762
+ template: `import { auth } from "@<%= projectName %>/auth";
742
763
  import { toNextJsHandler } from "better-auth/next-js";
743
764
 
744
765
  export const { GET, POST } = toNextJsHandler(auth);`
745
- },
746
- {
747
- filename: "apps/web/lib/auth-client.ts",
748
- template: `import { createAuthClient } from "better-auth/react";
766
+ };
767
+ //#endregion
768
+ //#region src/templates/web/templates/auth-client.ts
769
+ var auth_client_default = {
770
+ filename: "apps/web/lib/auth-client.ts",
771
+ template: `import { createAuthClient } from "better-auth/react";
749
772
 
750
773
  export const authClient = createAuthClient();`
751
- },
752
- {
753
- filename: "apps/web/app/manifest.json",
754
- template: `{
774
+ };
775
+ //#endregion
776
+ //#region src/templates/web/templates/manifest.ts
777
+ var manifest_default = {
778
+ filename: "apps/web/app/manifest.json",
779
+ template: `{
755
780
  "name": "<%= projectName %>",
756
781
  "short_name": "<%= projectName %>",
757
782
  "icons": [
@@ -772,7 +797,109 @@ export const authClient = createAuthClient();`
772
797
  "background_color": "#ffffff",
773
798
  "display": "standalone"
774
799
  }`
775
- }
800
+ };
801
+ //#endregion
802
+ //#region src/templates/versions.ts
803
+ const versions = {
804
+ "@babel/plugin-proposal-decorators": "^8.0.2",
805
+ "@babel/plugin-transform-class-properties": "^8.0.1",
806
+ "@base-ui/react": "^1.6.0",
807
+ "@eslint/js": "^9.39.1",
808
+ "@nestjs/cli": "^12.0.7",
809
+ "@nestjs/common": "^12.1.0",
810
+ "@nestjs/core": "^12.1.0",
811
+ "@nestjs/platform-express": "^12.1.0",
812
+ "@nestjs/schematics": "^12.0.5",
813
+ "@nestjs/serve-static": "^12.0.0",
814
+ "@nestjs/testing": "^12.1.0",
815
+ "@next/eslint-plugin-next": "^16.4.0",
816
+ "@oxlint/plugins": "^1.74.0",
817
+ "@shadcn/lint": "^0.1.0",
818
+ "@shadcn/react": "^0.2.1",
819
+ "@stylexjs/babel-plugin": "0.19.0",
820
+ "@stylexjs/postcss-plugin": "0.19.0",
821
+ "@stylexjs/stylex": "0.19.0",
822
+ "@swc/core": "^1.10.0",
823
+ "@tailwindcss/postcss": "^4.2.1",
824
+ "@tanstack/react-form": "^1.28.5",
825
+ "@tanstack/react-query": "^5.90.21",
826
+ "@thallesp/nestjs-better-auth": "^2.8.0",
827
+ "@types/better-sqlite3": "^7.6.13",
828
+ "@types/express": "^5.0.0",
829
+ "@types/jest": "^30.0.0",
830
+ "@types/node": "^24.13.3",
831
+ "@types/pg": "^8.11.13",
832
+ "@types/react": "19.2.14",
833
+ "@types/react-dom": "19.2.3",
834
+ "@types/supertest": "^6.0.2",
835
+ "@vitest/coverage-v8": "^4.1.10",
836
+ auth: "^1.5.5",
837
+ "babel-plugin-transform-typescript-metadata": "^0.4.0",
838
+ "better-auth": "^1.2.8",
839
+ "better-sqlite3": "^12.11.1",
840
+ "class-variance-authority": "^0.7.1",
841
+ clsx: "^2.1.1",
842
+ cmdk: "^1.1.1",
843
+ cn: "^0.3.0",
844
+ "date-fns": "^4.2.1",
845
+ dotenv: "^17.3.1",
846
+ "dotenv-cli": "^11.0.0",
847
+ "embla-carousel-react": "^8.6.0",
848
+ eslint: "^9.39.1",
849
+ "eslint-config-prettier": "^10.1.1",
850
+ "eslint-plugin-only-warn": "^1.1.0",
851
+ "eslint-plugin-react": "^7.37.5",
852
+ "eslint-plugin-react-hooks": "^5.2.0",
853
+ "eslint-plugin-turbo": "^2.7.1",
854
+ globals: "^16.5.0",
855
+ "input-otp": "^1.4.2",
856
+ jest: "^30.0.0",
857
+ kysely: "^0.28.2",
858
+ "lucide-react": "^1.16.0",
859
+ next: "16.4.0",
860
+ "next-themes": "^0.4.6",
861
+ oxfmt: "^0.59.0",
862
+ oxlint: "^1.80.0",
863
+ pg: "^8.14.1",
864
+ prettier: "^3.7.4",
865
+ react: "^19.2.4",
866
+ "react-day-picker": "^10.0.1",
867
+ "react-dom": "^19.2.4",
868
+ "react-resizable-panels": "^4.11.1",
869
+ recharts: "^3.8.0",
870
+ "reflect-metadata": "^0.2.2",
871
+ rxjs: "^7.8.1",
872
+ shadcn: "^4.7.0",
873
+ sonner: "^2.0.7",
874
+ supertest: "^7.0.0",
875
+ "tailwind-merge": "^3.6.0",
876
+ tailwindcss: "^4.2.1",
877
+ "ts-jest": "^29.2.5",
878
+ tsx: "^4.19.4",
879
+ turbo: "^2.8.16",
880
+ "tw-animate-css": "^1.4.0",
881
+ typescript: "6.0.2",
882
+ "typescript-eslint": "^8.50.0",
883
+ "unplugin-swc": "^1.5.9",
884
+ vitest: "^4.1.10",
885
+ zod: "^4.6.5"
886
+ };
887
+ //#endregion
888
+ //#region src/templates/web/index.ts
889
+ const web$1 = {
890
+ templates: [
891
+ package_json_default$7,
892
+ gitignore_default,
893
+ next_config_default$2,
894
+ postcss_config_default$3,
895
+ tsconfig_default$5,
896
+ layout_default$2,
897
+ page_default$2,
898
+ providers_default$1,
899
+ auth_form_default$2,
900
+ auth_route_default,
901
+ auth_client_default,
902
+ manifest_default
776
903
  ],
777
904
  staticFiles: [
778
905
  {
@@ -807,15 +934,21 @@ export const authClient = createAuthClient();`
807
934
  src: "web/static/public/web-app-manifest-512x512.png",
808
935
  filename: "apps/web/public/web-app-manifest-512x512.png"
809
936
  }
810
- ]
937
+ ],
938
+ packages: [{
939
+ package: "zod",
940
+ module: "apps/web",
941
+ version: versions.zod
942
+ }]
811
943
  };
812
944
  //#endregion
813
945
  //#region src/templates/api/index.ts
814
- const api$1 = { templates: [
815
- {
816
- when: (s) => s.nest === "on" && s.deployment !== "spa",
817
- filename: "apps/api/package.json",
818
- template: `{
946
+ const api$1 = {
947
+ templates: [
948
+ {
949
+ when: (s) => s.nest === "on" && s.deployment !== "spa",
950
+ filename: "apps/api/package.json",
951
+ template: `{
819
952
  "name": "api",
820
953
  "version": "0.0.1",
821
954
  "private": true,
@@ -849,10 +982,10 @@ const api$1 = { templates: [
849
982
  "typescript": "<%= versions.typescript %>"
850
983
  }
851
984
  }`
852
- },
853
- {
854
- filename: "apps/api/nest-cli.json",
855
- template: `{
985
+ },
986
+ {
987
+ filename: "apps/api/nest-cli.json",
988
+ template: `{
856
989
  "$schema": "https://json.schemastore.org/nest-cli",
857
990
  "collection": "@nestjs/schematics",
858
991
  "sourceRoot": "src",
@@ -860,11 +993,11 @@ const api$1 = { templates: [
860
993
  "deleteOutDir": true
861
994
  }
862
995
  }`
863
- },
864
- {
865
- when: (s) => s.nest === "on",
866
- filename: "apps/api/tsconfig.json",
867
- template: `{
996
+ },
997
+ {
998
+ when: (s) => s.nest === "on",
999
+ filename: "apps/api/tsconfig.json",
1000
+ template: `{
868
1001
  "compilerOptions": {
869
1002
  "module": "nodenext",
870
1003
  "moduleResolution": "nodenext",
@@ -888,28 +1021,28 @@ const api$1 = { templates: [
888
1021
  },
889
1022
  "exclude": ["vitest.config.mts", "vitest.config.e2e.mts", "node_modules", "dist"]
890
1023
  }`
891
- },
892
- {
893
- filename: "apps/api/tsconfig.build.json",
894
- template: `{
1024
+ },
1025
+ {
1026
+ filename: "apps/api/tsconfig.build.json",
1027
+ template: `{
895
1028
  "extends": "./tsconfig.json",
896
1029
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "vitest.config.mts", "vitest.config.e2e.mts", "jest.config.ts"]
897
1030
  }`
898
- },
899
- {
900
- when: (s) => s.nest === "di-only" && !s.todoExample,
901
- filename: "apps/api/src/app.module.ts",
902
- template: `import { Module } from '@nestjs/common';
1031
+ },
1032
+ {
1033
+ when: (s) => s.nest === "di-only" && !s.todoExample,
1034
+ filename: "apps/api/src/app.module.ts",
1035
+ template: `import { Module } from '@nestjs/common';
903
1036
  import { AppService } from './app.service';
904
1037
 
905
1038
  @Module({
906
1039
  providers: [AppService],
907
1040
  })
908
1041
  export class AppModule {}`
909
- },
910
- {
911
- filename: "apps/api/src/app.service.ts",
912
- template: `import { Injectable } from '@nestjs/common';
1042
+ },
1043
+ {
1044
+ filename: "apps/api/src/app.service.ts",
1045
+ template: `import { Injectable } from '@nestjs/common';
913
1046
 
914
1047
  @Injectable()
915
1048
  export class AppService {
@@ -917,10 +1050,10 @@ export class AppService {
917
1050
  return 'Hello from Nest';
918
1051
  }
919
1052
  }`
920
- },
921
- {
922
- filename: "apps/api/src/app.service.spec.ts",
923
- template: `import { Test, TestingModule } from '@nestjs/testing';
1053
+ },
1054
+ {
1055
+ filename: "apps/api/src/app.service.spec.ts",
1056
+ template: `import { Test, TestingModule } from '@nestjs/testing';
924
1057
  import { AppService } from './app.service';
925
1058
 
926
1059
  describe('AppService', () => {
@@ -938,23 +1071,14 @@ describe('AppService', () => {
938
1071
  expect(service).toBeDefined();
939
1072
  });
940
1073
  });`
941
- },
942
- {
943
- filename: "apps/api/README.md",
944
- template: `# API
945
-
946
- NestJS backend for the monorepo.
947
-
948
- ## Scripts
949
-
950
- \`\`\`sh
951
- pnpm dev # watch mode
952
- pnpm build # production build
953
- pnpm test # unit tests<% if (nest === 'on') { %>
954
- pnpm test:e2e # e2e tests<% } %>
955
- \`\`\``
956
- }
957
- ] };
1074
+ }
1075
+ ],
1076
+ packages: [{
1077
+ package: "zod",
1078
+ module: "apps/api",
1079
+ version: versions.zod
1080
+ }]
1081
+ };
958
1082
  //#endregion
959
1083
  //#region src/templates/auth/index.ts
960
1084
  const auth = { templates: [
@@ -1106,12 +1230,21 @@ import { FileMigrationProvider, Migrator } from "kysely";
1106
1230
  import { db } from "./index.js";
1107
1231
 
1108
1232
  async function main() {
1233
+ const migrationFolder = path.join(process.cwd(), "src/migrations");
1234
+ try {
1235
+ await fs.access(migrationFolder);
1236
+ } catch {
1237
+ console.log("no migrations yet");
1238
+ await db.destroy();
1239
+ return;
1240
+ }
1241
+
1109
1242
  const migrator = new Migrator({
1110
1243
  db,
1111
1244
  provider: new FileMigrationProvider({
1112
1245
  fs,
1113
1246
  path,
1114
- migrationFolder: path.join(process.cwd(), "src/migrations"),
1247
+ migrationFolder,
1115
1248
  }),
1116
1249
  });
1117
1250
 
@@ -1178,23 +1311,6 @@ async function main() {
1178
1311
  main();`
1179
1312
  };
1180
1313
  //#endregion
1181
- //#region src/templates/db/templates/migrations-readme.ts
1182
- var migrations_readme_default = {
1183
- filename: "packages/db/src/migrations/README.md",
1184
- template: `# Migrations
1185
-
1186
- Kysely migrations run in filename order. Each file exports \`up\` and \`down\`.
1187
-
1188
- \`\`\`bash
1189
- pnpm db:make add_widgets # scaffold a new migration
1190
- pnpm db:migrate # apply pending migrations
1191
- \`\`\`
1192
-
1193
- Migrations are written with Kysely's schema builder, so one file compiles to
1194
- both SQLite (dev) and Postgres (prod). Prefer dialect-agnostic column types
1195
- (\`text\`, \`integer\`) and app-generated string ids over auto-increment.`
1196
- };
1197
- //#endregion
1198
1314
  //#region src/templates/db/templates/package-json-sqlite.ts
1199
1315
  var package_json_sqlite_default = {
1200
1316
  filename: "packages/db/package.json",
@@ -1310,8 +1426,7 @@ const shared = [
1310
1426
  tsconfig_default$2,
1311
1427
  src_schema_default,
1312
1428
  src_migrate_default,
1313
- scripts_new_migration_default,
1314
- migrations_readme_default
1429
+ scripts_new_migration_default
1315
1430
  ];
1316
1431
  const dbSqlite = { templates: [
1317
1432
  ...shared,
@@ -1545,92 +1660,6 @@ const ui$1 = { templates: [
1545
1660
  tsconfig_default$1
1546
1661
  ] };
1547
1662
  //#endregion
1548
- //#region src/templates/versions.ts
1549
- const versions = {
1550
- "@babel/plugin-proposal-decorators": "^8.0.2",
1551
- "@babel/plugin-transform-class-properties": "^8.0.1",
1552
- "@base-ui/react": "^1.6.0",
1553
- "@eslint/js": "^9.39.1",
1554
- "@nestjs/cli": "^12.0.7",
1555
- "@nestjs/common": "^12.1.0",
1556
- "@nestjs/core": "^12.1.0",
1557
- "@nestjs/platform-express": "^12.1.0",
1558
- "@nestjs/schematics": "^12.0.5",
1559
- "@nestjs/serve-static": "^12.0.0",
1560
- "@nestjs/testing": "^12.1.0",
1561
- "@next/eslint-plugin-next": "^16.3.4",
1562
- "@oxlint/plugins": "^1.74.0",
1563
- "@shadcn/lint": "^0.1.0",
1564
- "@shadcn/react": "^0.2.1",
1565
- "@stylexjs/babel-plugin": "0.19.0",
1566
- "@stylexjs/postcss-plugin": "0.19.0",
1567
- "@stylexjs/stylex": "0.19.0",
1568
- "@swc/core": "^1.10.0",
1569
- "@tailwindcss/postcss": "^4.2.1",
1570
- "@tanstack/react-form": "^1.28.5",
1571
- "@tanstack/react-query": "^5.90.21",
1572
- "@thallesp/nestjs-better-auth": "^2.8.0",
1573
- "@types/better-sqlite3": "^7.6.13",
1574
- "@types/express": "^5.0.0",
1575
- "@types/jest": "^30.0.0",
1576
- "@types/node": "^24.13.3",
1577
- "@types/pg": "^8.11.13",
1578
- "@types/react": "19.2.14",
1579
- "@types/react-dom": "19.2.3",
1580
- "@types/supertest": "^6.0.2",
1581
- "@vitest/coverage-v8": "^4.1.10",
1582
- auth: "^1.5.5",
1583
- "babel-plugin-transform-typescript-metadata": "^0.4.0",
1584
- "better-auth": "^1.2.8",
1585
- "better-sqlite3": "^12.11.1",
1586
- "class-variance-authority": "^0.7.1",
1587
- clsx: "^2.1.1",
1588
- cmdk: "^1.1.1",
1589
- cn: "^0.3.0",
1590
- "date-fns": "^4.2.1",
1591
- dotenv: "^17.3.1",
1592
- "dotenv-cli": "^11.0.0",
1593
- "embla-carousel-react": "^8.6.0",
1594
- eslint: "^9.39.1",
1595
- "eslint-config-prettier": "^10.1.1",
1596
- "eslint-plugin-only-warn": "^1.1.0",
1597
- "eslint-plugin-react": "^7.37.5",
1598
- "eslint-plugin-react-hooks": "^5.2.0",
1599
- "eslint-plugin-turbo": "^2.7.1",
1600
- globals: "^16.5.0",
1601
- "input-otp": "^1.4.2",
1602
- jest: "^30.0.0",
1603
- kysely: "^0.28.2",
1604
- "lucide-react": "^1.16.0",
1605
- next: "16.3.4",
1606
- "next-themes": "^0.4.6",
1607
- oxfmt: "^0.59.0",
1608
- oxlint: "^1.80.0",
1609
- pg: "^8.14.1",
1610
- prettier: "^3.7.4",
1611
- react: "^19.2.4",
1612
- "react-day-picker": "^10.0.1",
1613
- "react-dom": "^19.2.4",
1614
- "react-resizable-panels": "^4.11.1",
1615
- recharts: "^3.8.0",
1616
- "reflect-metadata": "^0.2.2",
1617
- rxjs: "^7.8.1",
1618
- shadcn: "^4.7.0",
1619
- sonner: "^2.0.7",
1620
- supertest: "^7.0.0",
1621
- "tailwind-merge": "^3.6.0",
1622
- tailwindcss: "^4.2.1",
1623
- "ts-jest": "^29.2.5",
1624
- tsx: "^4.19.4",
1625
- turbo: "^2.8.16",
1626
- "tw-animate-css": "^1.4.0",
1627
- typescript: "6.0.2",
1628
- "typescript-eslint": "^8.50.0",
1629
- "unplugin-swc": "^1.5.9",
1630
- vitest: "^4.1.10",
1631
- zod: "^4.6.5"
1632
- };
1633
- //#endregion
1634
1663
  //#region src/templates/shadcn-ui/index.ts
1635
1664
  const shadcnUi = {
1636
1665
  templates: [
@@ -11275,37 +11304,10 @@ var plugin_package_json_default = {
11275
11304
  }`
11276
11305
  };
11277
11306
  //#endregion
11278
- //#region src/templates/anti-slop/templates/plugin-readme.ts
11279
- var plugin_readme_default = {
11280
- filename: "tools/oxlint/anti-slop/README.md",
11281
- template: `# anti-slop
11282
-
11283
- Oxlint rules that reject low-evidence TypeScript patterns, vendored from
11284
- [dmmulroy/anti-slop](https://github.com/dmmulroy/anti-slop) at \`6d538555cb15\` (MIT, see LICENSE).
11285
-
11286
- Upstream ships these to be vendored rather than depended on, so these files are
11287
- yours: read them, change the messages, delete the rules you disagree with.
11288
-
11289
- \`.oxlintrc.json\` registers the plugin and turns every rule on as an error.
11290
- Turn one off there:
11291
-
11292
- \`\`\`json
11293
- {
11294
- "rules": {
11295
- "anti-slop/no-runtime-typeof": "off"
11296
- }
11297
- }
11298
- \`\`\`
11299
-
11300
- Vendored shadcn components under \`packages/ui/src/components\` are exempt, since
11301
- they are upstream code you re-pull rather than write.
11302
- `
11303
- };
11304
- //#endregion
11305
11307
  //#region src/templates/anti-slop/index.ts
11306
11308
  const plugin = "tools/oxlint/anti-slop";
11307
11309
  const antiSlop = {
11308
- templates: [plugin_package_json_default, plugin_readme_default],
11310
+ templates: [plugin_package_json_default],
11309
11311
  staticFiles: [
11310
11312
  {
11311
11313
  src: "anti-slop/static/LICENSE",
@@ -13847,18 +13849,11 @@ const todoExampleApi = { templates: [
13847
13849
  db_schema_default,
13848
13850
  db_migration_todos_default
13849
13851
  ] };
13850
- const todoExampleControllers = {
13851
- templates: [
13852
- todos_controller_default,
13853
- todos_module_controllers_default,
13854
- app_module_controllers_default
13855
- ],
13856
- packages: [{
13857
- package: "zod",
13858
- module: "apps/api",
13859
- version: versions.zod
13860
- }]
13861
- };
13852
+ const todoExampleControllers = { templates: [
13853
+ todos_controller_default,
13854
+ todos_module_controllers_default,
13855
+ app_module_controllers_default
13856
+ ] };
13862
13857
  const todoExampleDi = { templates: [
13863
13858
  web_todos_route_default,
13864
13859
  web_todos_id_route_default,