create-newt-app 0.31.2 → 0.31.3

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.
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/templates/types.ts","../src/index.ts"],"mappings":";KAgCY;;;cCdN;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.2";
13
+ var version = "0.31.3";
14
14
  var engines = { "node": ">=24.0.0" };
15
15
  //#endregion
16
16
  //#region src/templates/root/index.ts
@@ -112,7 +112,7 @@ dist
112
112
  "env": ["DATABASE_URL"],
113
113
  "dependsOn": ["^build"],
114
114
  "inputs": ["$TURBO_DEFAULT$", ".env*"],
115
- "outputs": [".next/**", "!.next/cache/**"]
115
+ "outputs": [".next/**", "!.next/cache/**", "dist/**"]
116
116
  },
117
117
  "typecheck": {
118
118
  "dependsOn": ["^build"]
@@ -126,8 +126,7 @@ dist
126
126
  "env": ["NODE_ENV"]
127
127
  },<% } %>
128
128
  "test": {
129
- "dependsOn": ["^build"],
130
- "outputs": ["coverage/**"]
129
+ "dependsOn": ["^build"]
131
130
  },
132
131
  "dev": {
133
132
  "dependsOn": ["^migrate"],
@@ -187,7 +186,16 @@ Open [http://localhost:3000](http://localhost:3000).
187
186
  template: `<% if (database === 'postgres') { %>DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
188
187
  <% } else { %># Local SQLite database, written to dev.db at the repo root
189
188
  <% } %>BETTER_AUTH_URL=http://localhost:3000
190
- BETTER_AUTH_SECRET=<%= authSecret %>`
189
+ BETTER_AUTH_SECRET=<%= authSecret %>
190
+ `
191
+ },
192
+ {
193
+ filename: ".env.example",
194
+ template: `<% if (database === 'postgres') { %>DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
195
+ <% } else { %># Local SQLite database, written to dev.db at the repo root
196
+ <% } %>BETTER_AUTH_URL=http://localhost:3000
197
+ BETTER_AUTH_SECRET=generate-with-openssl-rand-base64-32
198
+ `
191
199
  },
192
200
  {
193
201
  filename: "AGENTS.md",
@@ -587,6 +595,7 @@ export function AuthForm() {
587
595
  <label className="text-sm font-medium">Name</label>
588
596
  <input
589
597
  type="text"
598
+ autoComplete="name"
590
599
  value={field.state.value}
591
600
  onChange={(e) => field.handleChange(e.target.value)}
592
601
  required
@@ -603,6 +612,7 @@ export function AuthForm() {
603
612
  <label className="text-sm font-medium">Email</label>
604
613
  <input
605
614
  type="email"
615
+ autoComplete="email"
606
616
  value={field.state.value}
607
617
  onChange={(e) => field.handleChange(e.target.value)}
608
618
  required
@@ -618,6 +628,9 @@ export function AuthForm() {
618
628
  <label className="text-sm font-medium">Password</label>
619
629
  <input
620
630
  type="password"
631
+ autoComplete={
632
+ tab === 'signin' ? 'current-password' : 'new-password'
633
+ }
621
634
  value={field.state.value}
622
635
  onChange={(e) => field.handleChange(e.target.value)}
623
636
  required
@@ -1514,7 +1527,7 @@ const versions = {
1514
1527
  "@nestjs/schematics": "^11.0.0",
1515
1528
  "@nestjs/serve-static": "^5.0.0",
1516
1529
  "@nestjs/testing": "^11.0.1",
1517
- "@next/eslint-plugin-next": "^16.3.2",
1530
+ "@next/eslint-plugin-next": "^16.3.3",
1518
1531
  "@oxlint/plugins": "^1.74.0",
1519
1532
  "@shadcn/react": "^0.2.1",
1520
1533
  "@swc/core": "^1.10.0",
@@ -1552,7 +1565,7 @@ const versions = {
1552
1565
  jest: "^30.0.0",
1553
1566
  kysely: "^0.28.2",
1554
1567
  "lucide-react": "^1.16.0",
1555
- next: "16.3.2",
1568
+ next: "16.3.3",
1556
1569
  "next-themes": "^0.4.6",
1557
1570
  oxfmt: "^0.59.0",
1558
1571
  oxlint: "^1.74.0",
@@ -2138,6 +2151,7 @@ export function AuthForm() {
2138
2151
  <Input
2139
2152
  id="name"
2140
2153
  type="text"
2154
+ autoComplete="name"
2141
2155
  value={field.state.value}
2142
2156
  onChange={(e) => field.handleChange(e.target.value)}
2143
2157
  required
@@ -2154,6 +2168,7 @@ export function AuthForm() {
2154
2168
  <Input
2155
2169
  id="email"
2156
2170
  type="email"
2171
+ autoComplete="email"
2157
2172
  value={field.state.value}
2158
2173
  onChange={(e) => field.handleChange(e.target.value)}
2159
2174
  required
@@ -2169,6 +2184,9 @@ export function AuthForm() {
2169
2184
  <Input
2170
2185
  id="password"
2171
2186
  type="password"
2187
+ autoComplete={
2188
+ tab === 'signin' ? 'current-password' : 'new-password'
2189
+ }
2172
2190
  value={field.state.value}
2173
2191
  onChange={(e) => field.handleChange(e.target.value)}
2174
2192
  required
@@ -10804,7 +10822,7 @@ const deploymentStandalone = { templates: [
10804
10822
  {
10805
10823
  when: (s) => !s.nestDiOnly,
10806
10824
  filename: "Dockerfile",
10807
- template: `FROM node:22-alpine AS base
10825
+ template: `FROM node:24-alpine AS base
10808
10826
  ENV PNPM_HOME="/pnpm"
10809
10827
  ENV PATH="$PNPM_HOME:$PATH"
10810
10828
  RUN corepack enable
@@ -10816,7 +10834,6 @@ RUN pnpm install --frozen-lockfile
10816
10834
  ARG API_HOST=localhost
10817
10835
  ENV API_HOST=$API_HOST
10818
10836
  RUN pnpm build --filter=web --filter=api --filter=@<%= projectName %>/auth
10819
- RUN pnpm deploy --filter=api --prod /deploy/api
10820
10837
 
10821
10838
  # --- web ---
10822
10839
  FROM base AS web
@@ -10829,10 +10846,9 @@ EXPOSE 3000
10829
10846
  CMD ["node", "apps/web/server.js"]
10830
10847
 
10831
10848
  # --- api ---
10832
- FROM base AS api
10849
+ FROM build AS api
10850
+ WORKDIR /app/apps/api
10833
10851
  ENV NODE_ENV=production
10834
- COPY --from=build /deploy/api /app
10835
- WORKDIR /app
10836
10852
  EXPOSE 3001
10837
10853
  CMD ["node", "dist/main"]
10838
10854
 
@@ -10942,7 +10958,7 @@ export default nextConfig;`
10942
10958
  "dependsOn": ["^build"],
10943
10959
  "inputs": ["$TURBO_DEFAULT$", ".env*"],
10944
10960
  "env": ["API_HOST", "DATABASE_URL"],
10945
- "outputs": [".next/**", "!.next/cache/**"]
10961
+ "outputs": [".next/**", "!.next/cache/**", "dist/**"]
10946
10962
  },
10947
10963
  "typecheck": {
10948
10964
  "dependsOn": ["^build"]
@@ -10956,8 +10972,7 @@ export default nextConfig;`
10956
10972
  "env": ["NODE_ENV"]
10957
10973
  },<% } %>
10958
10974
  "test": {
10959
- "dependsOn": ["^build"],
10960
- "outputs": ["coverage/**"]
10975
+ "dependsOn": ["^build"]
10961
10976
  },
10962
10977
  "dev": {
10963
10978
  "env": ["DATABASE_URL"],
@@ -11259,7 +11274,7 @@ export default nextConfig;`
11259
11274
  const deploymentStandaloneDi = { templates: [
11260
11275
  {
11261
11276
  filename: "Dockerfile",
11262
- template: `FROM node:22-alpine AS base
11277
+ template: `FROM node:24-alpine AS base
11263
11278
  ENV PNPM_HOME="/pnpm"
11264
11279
  ENV PATH="$PNPM_HOME:$PATH"
11265
11280
  RUN corepack enable
@@ -12536,27 +12551,23 @@ function validateNodeVersion(current, requirement) {
12536
12551
  error: `Node ${requirement} is required, but this is ${current}.\nUpgrade Node, or switch versions with a manager such as nvm or fnm.`
12537
12552
  };
12538
12553
  }
12554
+ function normalizeProjectName(projectName) {
12555
+ return projectName.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9\-._~]/g, "-").replace(/-+/g, "-").replace(/^[-._]+/, "").replace(/-+$/, "").slice(0, 214);
12556
+ }
12539
12557
  function validateProjectName(projectName) {
12540
12558
  if (!projectName) return {
12541
12559
  valid: false,
12542
12560
  error: "Project name is required"
12543
12561
  };
12544
- if (projectName.length < 1) return {
12562
+ const normalized = normalizeProjectName(projectName);
12563
+ if (!normalized) return {
12545
12564
  valid: false,
12546
- error: "Project name must be at least 1 character long"
12565
+ error: `"${projectName}" has nothing left after normalizing. Include a letter or a digit.`
12547
12566
  };
12548
- if (projectName.length > 214) return {
12549
- valid: false,
12550
- error: "Project name must be less than 214 characters"
12551
- };
12552
- if (/[<>:"/\\|?*]/.test(projectName)) return {
12553
- valid: false,
12554
- error: "Project name contains invalid characters"
12555
- };
12556
- const targetPath = path.resolve(process.cwd(), projectName);
12567
+ const targetPath = path.resolve(process.cwd(), normalized);
12557
12568
  if (existsSync(targetPath)) return {
12558
12569
  valid: false,
12559
- error: `Directory "${projectName}" already exists`
12570
+ error: `Directory "${normalized}" already exists`
12560
12571
  };
12561
12572
  return { valid: true };
12562
12573
  }
@@ -12632,11 +12643,7 @@ async function doInit(options) {
12632
12643
  ...!options.name && { name: () => p.text({
12633
12644
  message: "What is your project name?",
12634
12645
  placeholder: "my-newt-app",
12635
- validate: (value) => {
12636
- if (!value) return "Project name is required";
12637
- if (value.length > 214) return "Project name is too long";
12638
- if (/[<>:"/\\|?*]/.test(value)) return "Project name contains invalid characters";
12639
- }
12646
+ validate: (value) => validateProjectName(value).error
12640
12647
  }) },
12641
12648
  ...!options.nonInteractive && {
12642
12649
  shadcn: () => p.confirm({
@@ -12749,7 +12756,10 @@ async function doInit(options) {
12749
12756
  extras
12750
12757
  };
12751
12758
  const allModules = selectModules(selection);
12752
- const name = answers.name ?? options.name ?? "";
12759
+ const rawName = answers.name ?? options.name ?? "";
12760
+ const nameCheck = validateProjectName(rawName);
12761
+ if (!nameCheck.valid) throw new Error(nameCheck.error);
12762
+ const name = normalizeProjectName(rawName);
12753
12763
  const taskBuilder = new TaskBuilder();
12754
12764
  taskBuilder.add({
12755
12765
  title: "Scaffolding project",
@@ -12802,7 +12812,7 @@ async function doInit(options) {
12802
12812
  }
12803
12813
  }
12804
12814
  const program = new 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) => {
12815
+ 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: none, standalone, or 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) => {
12806
12816
  intro(`Create a ${chalk.blue("newt")} app.`);
12807
12817
  const nonInteractive = [
12808
12818
  "shadcn",