create-newt-app 0.31.0 → 0.31.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.
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ type Extra = "anti-slop";
5
5
  declare const TESTING_CHOICES: readonly ["jest", "vitest"];
6
6
  declare const DATABASE_CHOICES: readonly ["sqlite", "postgres"];
7
7
  declare const LINTER_CHOICES: readonly ["eslint", "oxc"];
8
- declare const DEPLOYMENT_CHOICES: readonly ["none", "standalone", "custom-server", "spa"];
8
+ declare const DEPLOYMENT_CHOICES: readonly ["none", "standalone", "spa"];
9
9
  type Testing = (typeof TESTING_CHOICES)[number];
10
10
  type Database = (typeof DATABASE_CHOICES)[number];
11
11
  type Linter = (typeof LINTER_CHOICES)[number];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/templates/types.ts","../src/index.ts"],"mappings":";KA+BY;;;cCfN;cACA;cACA;cACA;KAGD,kBAAkB;KAClB,mBAAmB;KACnB,iBAAiB;KACjB,qBAAqB;KAcrB;EACH;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,UAAU;EACV,QAAQ;EACR,YAAY;EACZ;EACA;EACA,iBAAiB;;iBAWG,OAAO,SAAS,UAAO"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/templates/types.ts","../src/index.ts"],"mappings":";KAgCY;;;cChBN;cACA;cACA;cACA;KAGD,kBAAkB;KAClB,mBAAmB;KACnB,iBAAiB;KACjB,qBAAqB;KAcrB;EACH;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,UAAU;EACV,QAAQ;EACR,YAAY;EACZ;EACA;EACA,iBAAiB;;iBAWG,OAAO,SAAS,UAAO"}
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import ejs from "ejs";
10
10
  import { existsSync, promises } from "fs";
11
11
  import path from "path";
12
12
  //#region package.json
13
- var version = "0.31.0";
13
+ var version = "0.31.1";
14
14
  var engines = { "node": ">=24.0.0" };
15
15
  //#endregion
16
16
  //#region src/templates/root/index.ts
@@ -102,7 +102,7 @@ dist
102
102
  template: ``
103
103
  },
104
104
  {
105
- when: (s) => s.deployment !== "standalone" && s.deployment !== "custom-server",
105
+ when: (s) => s.deployment !== "standalone",
106
106
  filename: "turbo.json",
107
107
  template: `{
108
108
  "$schema": "https://turborepo.dev/schema.json",
@@ -207,7 +207,7 @@ This version has breaking changes — APIs, conventions, and file structure may
207
207
  const web$1 = {
208
208
  templates: [
209
209
  {
210
- when: (s) => !s.nestDiOnly && s.deployment !== "custom-server",
210
+ when: (s) => !s.nestDiOnly,
211
211
  filename: "apps/web/package.json",
212
212
  template: `{
213
213
  "name": "web",
@@ -350,7 +350,7 @@ export default nextConfig;`
350
350
  template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
351
351
  },
352
352
  {
353
- when: (s) => !s.nestDiOnly && s.deployment !== "custom-server",
353
+ when: (s) => !s.nestDiOnly,
354
354
  filename: "apps/web/tsconfig.json",
355
355
  template: `{
356
356
  "extends": "@<%= projectName %>/typescript-config/nextjs.json",
@@ -751,7 +751,7 @@ export const authClient: ReturnType<typeof createAuthClient> = createAuthClient(
751
751
  //#region src/templates/api/index.ts
752
752
  const api$1 = { templates: [
753
753
  {
754
- when: (s) => !s.nestDiOnly && s.deployment !== "spa" && s.deployment !== "custom-server",
754
+ when: (s) => !s.nestDiOnly && s.deployment !== "spa",
755
755
  filename: "apps/api/package.json",
756
756
  template: `{
757
757
  "name": "api",
@@ -896,8 +896,8 @@ NestJS backend for the monorepo.
896
896
  \`\`\`sh
897
897
  pnpm dev # watch mode
898
898
  pnpm build # production build
899
- pnpm test # unit tests
900
- pnpm test:e2e # e2e tests
899
+ pnpm test # unit tests<% if (!nestDiOnly) { %>
900
+ pnpm test:e2e # e2e tests<% } %>
901
901
  \`\`\``
902
902
  }
903
903
  ] };
@@ -10978,252 +10978,6 @@ export default nextConfig;`
10978
10978
  }
10979
10979
  ] };
10980
10980
  //#endregion
10981
- //#region src/templates/single-process-custom-server/index.ts
10982
- const singleProcessCustomServer = { templates: [
10983
- {
10984
- filename: "apps/api/package.json",
10985
- template: `{
10986
- "name": "@<%= projectName %>/api",
10987
- "version": "0.0.1",
10988
- "description": "",
10989
- "author": "",
10990
- "private": true,
10991
- "license": "UNLICENSED",
10992
- "exports": {
10993
- ".": "./dist/index.js"
10994
- },
10995
- "scripts": {
10996
- "build": "nest build",
10997
- "start": "nest start",
10998
- "start:dev": "nest start --watch",
10999
- "start:debug": "nest start --debug --watch",
11000
- "start:prod": "node dist/main"
11001
- },
11002
- "dependencies": {
11003
- "@nestjs/common": "<%= versions["@nestjs/common"] %>",
11004
- "@nestjs/core": "<%= versions["@nestjs/core"] %>",
11005
- "@nestjs/platform-express": "<%= versions["@nestjs/platform-express"] %>",
11006
- "@<%= projectName %>/auth": "workspace:*",
11007
- "@<%= projectName %>/db": "workspace:*",
11008
- "@thallesp/nestjs-better-auth": "<%= versions["@thallesp/nestjs-better-auth"] %>",
11009
- "dotenv": "<%= versions.dotenv %>",
11010
- "reflect-metadata": "<%= versions["reflect-metadata"] %>",
11011
- "rxjs": "<%= versions.rxjs %>"
11012
- },
11013
- "devDependencies": {
11014
- "@nestjs/cli": "<%= versions["@nestjs/cli"] %>",
11015
- "@nestjs/schematics": "<%= versions["@nestjs/schematics"] %>",
11016
- "@nestjs/testing": "<%= versions["@nestjs/testing"] %>",
11017
- "@types/express": "<%= versions["@types/express"] %>",
11018
- "@types/node": "<%= versions["@types/node"] %>",
11019
- "@types/supertest": "<%= versions["@types/supertest"] %>",
11020
- "supertest": "<%= versions.supertest %>",
11021
- "ts-node": "<%= versions["ts-node"] %>",
11022
- "tsconfig-paths": "<%= versions["tsconfig-paths"] %>",
11023
- "typescript": "<%= versions.typescript %>"
11024
- }
11025
- }`
11026
- },
11027
- {
11028
- filename: "apps/api/src/index.ts",
11029
- template: `export { AppModule } from './app.module';`
11030
- },
11031
- {
11032
- filename: "apps/web/server.ts",
11033
- template: `import 'reflect-metadata';
11034
- import dotenv from 'dotenv';
11035
- import { resolve } from 'path';
11036
-
11037
- // Load root .env first, then local .env (local takes precedence)
11038
- dotenv.config({ path: resolve(process.cwd(), '../../.env') });
11039
- dotenv.config({ path: resolve(process.cwd(), '.env') });
11040
-
11041
- import { NestFactory } from '@nestjs/core';
11042
- import { AppModule } from '@<%= projectName %>/api';
11043
- import next from 'next';
11044
- import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
11045
-
11046
- const dev = process.env.NODE_ENV !== 'production';
11047
- const port = parseInt(process.env.PORT ?? '3000', 10);
11048
-
11049
- async function main() {
11050
- const nextApp = next({ dev, port });
11051
- const handle = nextApp.getRequestHandler();
11052
-
11053
- await nextApp.prepare();
11054
-
11055
- const nestApp = await NestFactory.create(AppModule);
11056
- // apps/api/src/main.ts never runs here, so its prefix is set again
11057
- nestApp.setGlobalPrefix('api');
11058
- await nestApp.init();
11059
-
11060
- const nestListener = nestApp
11061
- .getHttpServer()
11062
- .listeners('request')[0] as (req: IncomingMessage, res: ServerResponse) => void;
11063
-
11064
- const server = createServer((req, res) => {
11065
- if (req.url?.startsWith('/api/')) {
11066
- nestListener(req, res);
11067
- } else {
11068
- handle(req, res);
11069
- }
11070
- });
11071
-
11072
- server.listen(port, () => {
11073
- console.log(\`> Server ready on http://localhost:\${port}\`);
11074
- });
11075
- }
11076
-
11077
- main().catch(console.error);`
11078
- },
11079
- {
11080
- filename: "apps/web/package.json",
11081
- template: `{
11082
- "name": "web",
11083
- "version": "0.1.0",
11084
- "type": "module",
11085
- "private": true,
11086
- "scripts": {
11087
- "dev": "tsx watch --tsconfig tsconfig.server.json server.ts",
11088
- "build": "next build && tsc -p tsconfig.server.json",
11089
- "start": "node dist/server.js",
11090
- "db:migrate": "better-auth migrate"
11091
- },
11092
- "dependencies": {
11093
- "@<%= projectName %>/api": "workspace:*",
11094
- "@<%= projectName %>/auth": "workspace:*",
11095
- "@<%= projectName %>/ui": "workspace:*",
11096
- "@nestjs/core": "<%= versions["@nestjs/core"] %>",
11097
- "@tailwindcss/postcss": "<%= versions["@tailwindcss/postcss"] %>",
11098
- "dotenv": "<%= versions.dotenv %>",
11099
- "@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
11100
- "@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
11101
- "better-auth": "<%= versions["better-auth"] %>",
11102
- "next": "<%= versions.next %>",
11103
- "react": "<%= versions.react %>",
11104
- "react-dom": "<%= versions["react-dom"] %>",
11105
- "reflect-metadata": "<%= versions["reflect-metadata"] %>",
11106
- "tailwindcss": "<%= versions.tailwindcss %>"
11107
- },
11108
- "devDependencies": {
11109
- "@<%= projectName %>/typescript-config": "workspace:*",
11110
- "@types/node": "<%= versions["@types/node"] %>",
11111
- "@types/react": "<%= versions["@types/react"] %>",
11112
- "@types/react-dom": "<%= versions["@types/react-dom"] %>",
11113
- "tsx": "<%= versions.tsx %>",
11114
- "typescript": "<%= versions.typescript %>"
11115
- }
11116
- }`
11117
- },
11118
- {
11119
- when: (s) => !s.nestDiOnly,
11120
- filename: "apps/web/next.config.js",
11121
- template: `import dotenv from 'dotenv';
11122
- import { resolve } from 'path';
11123
-
11124
- // Load root .env first, then local .env (local takes precedence)
11125
- dotenv.config({ path: resolve(process.cwd(), '../../.env') });
11126
- dotenv.config({ path: resolve(process.cwd(), '.env') });
11127
-
11128
- // No output setting: server.ts is the server, so Next runs in-process rather
11129
- // than through its own standalone entrypoint.
11130
- /** @type {import('next').NextConfig} */
11131
- const nextConfig = {};
11132
-
11133
- export default nextConfig;`
11134
- },
11135
- {
11136
- filename: "apps/web/tsconfig.json",
11137
- template: `{
11138
- "extends": "@<%= projectName %>/typescript-config/nextjs.json",
11139
- "compilerOptions": {
11140
- "plugins": [
11141
- {
11142
- "name": "next"
11143
- }
11144
- ],
11145
- "strictNullChecks": true,
11146
- "paths": {
11147
- "@/*": ["./*"]
11148
- }
11149
- },
11150
- "include": [
11151
- "**/*.ts",
11152
- "**/*.tsx",
11153
- "next-env.d.ts",
11154
- "next.config.js",
11155
- ".next/types/**/*.ts"
11156
- ],
11157
- "exclude": ["node_modules", "server.ts"]
11158
- }`
11159
- },
11160
- {
11161
- filename: "apps/web/tsconfig.server.json",
11162
- template: `{
11163
- "compilerOptions": {
11164
- "module": "esnext",
11165
- "moduleResolution": "bundler",
11166
- "outDir": "dist",
11167
- "target": "ES2023",
11168
- "esModuleInterop": true,
11169
- "emitDecoratorMetadata": true,
11170
- "experimentalDecorators": true,
11171
- "allowSyntheticDefaultImports": true,
11172
- "skipLibCheck": true,
11173
- "strictNullChecks": true,
11174
- "noImplicitAny": false
11175
- },
11176
- "include": ["server.ts"],
11177
- "exclude": ["node_modules"]
11178
- }`
11179
- },
11180
- {
11181
- filename: "turbo.json",
11182
- template: `{
11183
- "$schema": "https://turborepo.dev/schema.json",
11184
- "ui": "tui",
11185
- "tasks": {
11186
- "build": {
11187
- "env": ["DATABASE_URL", "PORT"],
11188
- "dependsOn": ["^build"],
11189
- "inputs": ["$TURBO_DEFAULT$", ".env*"],
11190
- "outputs": [".next/**", "!.next/cache/**", "dist/**"]
11191
- },
11192
- "typecheck": {
11193
- "dependsOn": ["^build"]
11194
- },<% if (linter !== "oxc") { %>
11195
- "lint": {
11196
- "dependsOn": ["^lint"],
11197
- "env": ["NODE_ENV"]
11198
- },
11199
- "lint:check": {
11200
- "dependsOn": ["^lint:check"],
11201
- "env": ["NODE_ENV"]
11202
- },<% } %>
11203
- "test": {
11204
- "dependsOn": ["^build"],
11205
- "outputs": ["coverage/**"]
11206
- },
11207
- "dev": {
11208
- "env": ["DATABASE_URL", "PORT"],
11209
- "dependsOn": ["^migrate", "^build"],
11210
- "cache": false,
11211
- "persistent": true
11212
- },
11213
- "migrate": {
11214
- "env": ["DATABASE_URL"],
11215
- "dependsOn": ["^migrate"],
11216
- "cache": false
11217
- },
11218
- "generate": {
11219
- "env": ["DATABASE_URL"],
11220
- "cache": false
11221
- }
11222
- }
11223
- }`
11224
- }
11225
- ] };
11226
- //#endregion
11227
10981
  //#region src/templates/single-process-static-export/index.ts
11228
10982
  const singleProcessStaticExport = { templates: [{
11229
10983
  filename: "apps/api/package.json",
@@ -11278,24 +11032,22 @@ dotenv.config({ path: resolve(process.cwd(), '.env') });
11278
11032
 
11279
11033
  const isProduction = process.env.NODE_ENV === 'production';
11280
11034
 
11035
+ // Static export in production — served by NestJS via ServeStaticModule.
11036
+ // rewrites() is incompatible with output: "export", so dev uses the proxy
11037
+ // and production uses the static files.
11281
11038
  /** @type {import('next').NextConfig} */
11282
- const nextConfig = {
11283
- // Static export in production — served by NestJS via ServeStaticModule.
11284
- // rewrites() is incompatible with output: "export", so dev uses the proxy
11285
- // and production uses the static files.
11286
- ...(isProduction
11287
- ? { output: 'export' }
11288
- : {
11289
- async rewrites() {
11290
- return [
11291
- {
11292
- source: '/api/:path*',
11293
- destination: 'http://localhost:3001/api/:path*',
11294
- },
11295
- ];
11296
- },
11297
- }),
11298
- };
11039
+ const nextConfig = isProduction
11040
+ ? { output: 'export' }
11041
+ : {
11042
+ async rewrites() {
11043
+ return [
11044
+ {
11045
+ source: '/api/:path*',
11046
+ destination: 'http://localhost:3001/api/:path*',
11047
+ },
11048
+ ];
11049
+ },
11050
+ };
11299
11051
 
11300
11052
  export default nextConfig;`
11301
11053
  }] };
@@ -11362,7 +11114,7 @@ const nestDiOnly = { templates: [
11362
11114
  "noImplicitAny": false,
11363
11115
  "strictBindCallApply": false,
11364
11116
  "noFallthroughCasesInSwitch": false,
11365
- "types": [<% if (testing === 'jest') { %>"jest", <% } %>"node"]
11117
+ "types": [<% if (testing === 'jest') { %>"jest", <% } %><% if (testing === 'vitest') { %>"vitest/globals", <% } %>"node"]
11366
11118
  },
11367
11119
  "include": ["src/**/*"],
11368
11120
  "exclude": ["node_modules", "dist"]
@@ -12612,13 +12364,24 @@ fileURLToPath(staticDir);
12612
12364
  function getStaticFilePath(name) {
12613
12365
  return fileURLToPath(new URL(`./static/${name}`, import.meta.url));
12614
12366
  }
12367
+ const E2E_FILES = [
12368
+ "apps/api/test/app.e2e-spec.ts",
12369
+ "apps/api/test/jest-e2e.json",
12370
+ "apps/api/vitest.config.e2e.mts"
12371
+ ];
12615
12372
  function selectModules(selection) {
12616
12373
  const { deployment, nestDiOnly: nestDiOnly$1, todoExample, shadcn, database, linter, testing, extras } = selection;
12617
- const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "custom-server" ? singleProcessCustomServer : deployment === "spa" ? singleProcessStaticExport : null;
12374
+ const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "spa" ? singleProcessStaticExport : null;
12618
12375
  const webModule = deployment === "spa" ? {
12619
12376
  ...web$1,
12620
12377
  templates: web$1.templates.filter((t) => t.filename !== "apps/web/app/api/auth/[...all]/route.ts")
12621
12378
  } : web$1;
12379
+ const selectedTesting = testing === "vitest" ? testingVitest : testingJest;
12380
+ const testingModule = nestDiOnly$1 ? {
12381
+ ...selectedTesting,
12382
+ templates: selectedTesting.templates.filter((t) => !E2E_FILES.includes(t.filename)),
12383
+ scripts: selectedTesting.scripts?.filter((s) => s.name !== "test:e2e")
12384
+ } : selectedTesting;
12622
12385
  return [
12623
12386
  root$2,
12624
12387
  webModule,
@@ -12629,7 +12392,7 @@ function selectModules(selection) {
12629
12392
  linter === "oxc" ? oxc : eslintConfig,
12630
12393
  ...extras.includes("anti-slop") ? [antiSlop] : [],
12631
12394
  typescriptConfig,
12632
- testing === "vitest" ? testingVitest : testingJest,
12395
+ testingModule,
12633
12396
  ...deploymentModule ? [deploymentModule] : [],
12634
12397
  ...nestDiOnly$1 ? [nestDiOnly] : [apiControllers],
12635
12398
  ...nestDiOnly$1 && deployment === "standalone" ? [deploymentStandaloneDi] : [],
@@ -12748,10 +12511,6 @@ function validateDeploymentCombo(deployment, nestDiOnly) {
12748
12511
  valid: false,
12749
12512
  error: "--deployment spa cannot be combined with --nest-di-only.\nSPA mode statically exports Next.js (output: 'export'), which cannot include the\nAPI route handlers that DI-only mode depends on. Pick one: drop --nest-di-only to\nget SPA mode with NestJS controllers, or drop --deployment spa."
12750
12513
  };
12751
- if (deployment === "custom-server" && nestDiOnly) return {
12752
- valid: false,
12753
- error: "--deployment custom-server cannot be combined with --nest-di-only.\nDI-only keeps Next.js as the server and calls Nest in-process, so it overwrites the\nscripts that would run the custom server — apps/web/server.ts would be generated but\nnever invoked. Both already run Nest inside the Next.js process; pick one."
12754
- };
12755
12514
  return { valid: true };
12756
12515
  }
12757
12516
  const TOOL_HINTS = {
@@ -12811,6 +12570,7 @@ async function scaffold(modules, options) {
12811
12570
  }
12812
12571
  const templateData = {
12813
12572
  projectName: options.name,
12573
+ nestDiOnly: options.selection.nestDiOnly,
12814
12574
  testing: options.testing,
12815
12575
  database: options.database,
12816
12576
  deployment: options.deployment,
@@ -12858,7 +12618,6 @@ const LINTER_CHOICES = ["eslint", "oxc"];
12858
12618
  const DEPLOYMENT_CHOICES = [
12859
12619
  "none",
12860
12620
  "standalone",
12861
- "custom-server",
12862
12621
  "spa"
12863
12622
  ];
12864
12623
  const EXTRAS_CHOICES = ["anti-slop"];
@@ -12948,10 +12707,6 @@ async function doInit(options) {
12948
12707
  hint: "Dockerfiles + docker-compose.yml"
12949
12708
  },
12950
12709
  ...results.nestDiOnly ? [] : [{
12951
- value: "custom-server",
12952
- label: "Custom Server",
12953
- hint: "single process, single port"
12954
- }, {
12955
12710
  value: "spa",
12956
12711
  label: "SPA Mode",
12957
12712
  hint: "static export served by NestJS"
@@ -13047,7 +12802,7 @@ async function doInit(options) {
13047
12802
  }
13048
12803
  }
13049
12804
  const program = new Command();
13050
- program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: standalone, custom-server, spa", "none").option("--nest-di-only", "Use NestJS for dependency injection only", false).option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
12805
+ program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: standalone, spa", "none").option("--nest-di-only", "Use NestJS for dependency injection only", false).option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
13051
12806
  intro(`Create a ${chalk.blue("newt")} app.`);
13052
12807
  const nonInteractive = [
13053
12808
  "shadcn",