create-basalt 1.10.0 → 1.12.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.
@@ -1,8 +1,11 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { binStatus, MANUAL_BIN_SNIPPET, patchBasaltBin } from '../bin-template.js';
3
+ import { binStatus, hasProjectCommands, manualBinSnippet, patchBasaltBin } from '../bin-template.js';
4
+ import { devEntryStatus, MANUAL_DEV_SNIPPET, patchDevEntry, patchEnvExample } from '../dev-entry.js';
4
5
  import { alwaysLatest, lookupLatestVersions, minimumReleaseAgeMinutes, } from '../latest-versions.js';
5
6
  import { BASALT_PROJECT_SCRIPT } from '../templates.js';
7
+ import { planProductionPath } from './production.js';
8
+ import { legacySeedScriptFix } from './seed-script.js';
6
9
  import { extendManifest, MANIFEST_PATH, serializeManifest } from './manifest.js';
7
10
  import { DEPENDENCY_SECTIONS, mergePackageJson, setDependencyRange, } from './package-json.js';
8
11
  import { table } from './term.js';
@@ -194,22 +197,61 @@ export async function planUpdate(ctx, options = {}) {
194
197
  }
195
198
  }
196
199
  }
197
- // bin/basalt.ts from an earlier template: make it delegate the project commands.
200
+ // Template files from an earlier release: bring them to the current
201
+ // templates when untouched (known hash or the manifest's), else print the
202
+ // snippet. Patched files get their manifest hash refreshed.
203
+ const patched = {};
198
204
  const bin = await readOptional(join(ctx.dir, 'bin', 'basalt.ts'));
199
205
  const status = binStatus(bin, ctx.manifest?.files['bin/basalt.ts']);
200
206
  if (status === 'patchable' && bin !== undefined) {
201
207
  const after = patchBasaltBin(bin);
202
208
  files['bin/basalt.ts'] = { before: bin, after };
203
- toolingNotes.push('bin/basalt.ts: unmodified template from an earlier release — gains update/add/doctor/info');
204
- if (ctx.manifest) {
205
- files[MANIFEST_PATH] = {
206
- before: serializeManifest(ctx.manifest),
207
- after: serializeManifest(extendManifest(ctx.manifest, ctx.options, { 'bin/basalt.ts': after })),
208
- };
209
- }
209
+ patched['bin/basalt.ts'] = after;
210
+ toolingNotes.push(`bin/basalt.ts: unmodified template from an earlier release — ${hasProjectCommands(bin) ? '' : 'gains update/add/doctor/info; '}loads .env for development, runs \`upgrade\` without booting the app, explains env errors`);
211
+ }
212
+ else if (status === 'modified' && bin !== undefined) {
213
+ manual.push(`bin/basalt.ts was customised, so it was not patched. To bring it up to date:\n${manualBinSnippet(bin)}`);
214
+ }
215
+ const dev = await readOptional(join(ctx.dir, 'src', 'dev.ts'));
216
+ const devStatus = devEntryStatus(dev, ctx.manifest?.files['src/dev.ts']);
217
+ if (devStatus === 'patchable' && dev !== undefined) {
218
+ const after = patchDevEntry();
219
+ files['src/dev.ts'] = { before: dev, after };
220
+ patched['src/dev.ts'] = after;
221
+ toolingNotes.push('src/dev.ts: unmodified template from an earlier release — `dev` loads .env (exported variables still win)');
222
+ }
223
+ else if (devStatus === 'modified') {
224
+ manual.push(`src/dev.ts was customised, so it was not patched. To load .env in development:\n${MANUAL_DEV_SNIPPET}`);
225
+ }
226
+ const example = await readOptional(join(ctx.dir, '.env.example'));
227
+ const exampleAfter = example === undefined ? undefined : patchEnvExample(example);
228
+ if (example !== undefined && exampleAfter !== undefined) {
229
+ files['.env.example'] = { before: example, after: exampleAfter };
230
+ patched['.env.example'] = exampleAfter;
231
+ toolingNotes.push('.env.example: header now says dev/CLI load .env automatically and `start` does not');
232
+ }
233
+ // The production path (BK-026): tsconfig.build.json, a `build` script, the
234
+ // Dockerfile — offered when missing, never overwriting what the app has.
235
+ const production = await planProductionPath(ctx.dir, files['package.json']?.after ?? ctx.packageJsonText, ctx.pm);
236
+ if (production.packageJsonText !== (files['package.json']?.after ?? ctx.packageJsonText)) {
237
+ files['package.json'] = { before: ctx.packageJsonText, after: production.packageJsonText };
238
+ }
239
+ for (const [path, content] of Object.entries(production.files)) {
240
+ files[path] = { before: undefined, after: content };
241
+ patched[path] = content;
210
242
  }
211
- else if (status === 'modified') {
212
- manual.push(`bin/basalt.ts was customised, so it was not patched. To give it the project commands:\n${MANUAL_BIN_SNIPPET}`);
243
+ toolingNotes.push(...production.notes);
244
+ manual.push(...production.manual);
245
+ // db:seed from create-basalt 1.8–1.11 does not load .env: printed, never
246
+ // rewritten — package.json scripts are the app's.
247
+ const seedFix = legacySeedScriptFix(ctx.packageJson, await readOptional(join(ctx.dir, 'prisma.config.ts')));
248
+ if (seedFix !== undefined)
249
+ manual.push(seedFix);
250
+ if (ctx.manifest && Object.keys(patched).length > 0) {
251
+ files[MANIFEST_PATH] = {
252
+ before: serializeManifest(ctx.manifest),
253
+ after: serializeManifest(extendManifest(ctx.manifest, ctx.options, patched)),
254
+ };
213
255
  }
214
256
  }
215
257
  // Peer ranges of the framework versions we end up on vs the app's resulting ranges.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The production stubs `basalt publish` copies into an app — the SINGLE source
3
+ * of truth. create-basalt ships the same files in every new scaffold and offers
4
+ * them from `create-basalt update`: its build copies this file verbatim to
5
+ * `packages/create-app/src/stubs.ts` (scripts/sync-stubs.mjs), and a test there
6
+ * fails if the copy drifts. Keep this module free of imports for that reason.
7
+ *
8
+ * The layout these stubs assume is the create-basalt scaffold's (BK-026):
9
+ * `pnpm build` runs `tsc -p tsconfig.build.json` (rootDir `.`, outDir `dist`),
10
+ * so `src/server.ts` compiles to {@link PRODUCTION_ENTRY}; `pnpm start` runs it
11
+ * with plain `node` — no tsx, no TypeScript at runtime. A Prisma client, when
12
+ * there is one, is generated OUTSIDE `src/` (`generated/prisma`) and imported
13
+ * through the package.json `imports` alias `#db/*`, so it resolves the same
14
+ * from `src/` (tsx) and from `dist/src/` (node).
15
+ */
16
+ /** The compiled server entry the Dockerfile runs and the scaffold's `start` script points at. */
17
+ export declare const PRODUCTION_ENTRY = "dist/src/server.js";
18
+ /** Multi-stage production image: build with the dev toolchain, run on plain node as a non-root user. */
19
+ export declare const DOCKERFILE = "# syntax=docker/dockerfile:1\n# Production image for a Basalt app (the create-basalt layout): `pnpm build`\n# compiles src/ to dist/ and the image runs dist/src/server.js on plain\n# node \u2014 no tsx, no TypeScript at runtime.\n#\n# docker build -t my-app .\n# docker run -p 3000:3000 -e APP_SECRET=\u2026 -e DATABASE_URL=\u2026 my-app\n#\n# Configuration comes from the environment (nothing loads .env here, and\n# .dockerignore keeps it out of the image). Database migrations are NOT run\n# by the image: apply them before rolling out (`pnpm db:deploy` in CI).\n#\n# Installs with pnpm from pnpm-lock.yaml. An app on npm/yarn/bun replaces the\n# pnpm install / exec / run / prune lines with its own package manager's.\nARG NODE_VERSION=22\nARG PNPM_VERSION=11\n\nFROM node:${NODE_VERSION}-slim AS build\nARG PNPM_VERSION\n# Non-interactive pnpm: without it `pnpm prune` in a workspace (a --ui app's\n# web/) aborts with ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY.\nENV CI=true\nWORKDIR /app\nRUN npm install -g pnpm@${PNPM_VERSION}\nCOPY . .\n# Full install: the build needs the devDependencies (typescript, prisma).\nRUN pnpm install --frozen-lockfile\n# The Prisma client (when the app has a schema) is generated into ./generated.\nRUN if [ -f prisma/schema.prisma ]; then pnpm exec prisma generate; fi && mkdir -p generated\nRUN pnpm run build\n# Drop the devDependencies (tsx, typescript, prisma CLI, generators, the AI\n# bridge): none of them may ship. --ignore-scripts keeps the app's postinstall\n# (`prisma generate`, a dev tool) from running again.\nRUN pnpm prune --prod --ignore-scripts\n\nFROM node:${NODE_VERSION}-slim AS run\nENV NODE_ENV=production\nENV PORT=3000\n# Path the HEALTHCHECK probes: the scaffold's /health route by default; set\n# /readyz when the app registers healthPlugin().\nENV HEALTHCHECK_PATH=/health\nWORKDIR /app\nCOPY --from=build --chown=node:node /app/package.json ./package.json\nCOPY --from=build --chown=node:node /app/node_modules ./node_modules\nCOPY --from=build --chown=node:node /app/generated ./generated\nCOPY --from=build --chown=node:node /app/dist ./dist\nUSER node\nEXPOSE 3000\nHEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \\\n CMD node -e \"fetch('http://127.0.0.1:' + (process.env.PORT || 3000) + process.env.HEALTHCHECK_PATH).then((r) => process.exit(r.ok ? 0 : 1), () => process.exit(1))\"\nCMD [\"node\", \"--enable-source-maps\", \"dist/src/server.js\"]\n";
20
+ /**
21
+ * Published with the Dockerfile: its \`COPY . .\` would otherwise bake \`.env\`,
22
+ * private keys and VCS metadata into an image layer. Every secret rule is
23
+ * \`**\/\`-prefixed: .dockerignore patterns are anchored at the context root, so
24
+ * a bare \`.env\` or \`*.pem\` would still let \`prisma/.env\` or
25
+ * \`certs/server.key\` through. \`dist\` is rebuilt inside the image.
26
+ */
27
+ export declare const DOCKERIGNORE = "**/.env\n**/.env.*\n!**/.env.example\n**/.npmrc\n**/.git\n**/node_modules\n**/coverage\n**/*.log\n**/*.pem\n**/*.key\n**/*.p12\n**/*.pfx\n**/.DS_Store\ndist\n";
28
+ /** GitHub Actions CI: install, typecheck, build (the production path), test. */
29
+ export declare const CI_WORKFLOW = "name: ci\non:\n push: { branches: [main] }\n pull_request:\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n # Drop `with: version` if package.json declares a packageManager.\n - uses: pnpm/action-setup@v4\n with: { version: 11 }\n - uses: actions/setup-node@v4\n with: { node-version: 22, cache: pnpm }\n - run: pnpm install --frozen-lockfile\n - run: pnpm run typecheck\n - run: pnpm run build\n - run: pnpm run test\n";
30
+ export declare const EDITORCONFIG = "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ntrim_trailing_whitespace = true\n";
package/dist/stubs.js ADDED
@@ -0,0 +1,123 @@
1
+ // GENERATED by scripts/sync-stubs.mjs from packages/cli/src/stubs.ts (runs before every build) — do not edit.
2
+ /**
3
+ * The production stubs `basalt publish` copies into an app — the SINGLE source
4
+ * of truth. create-basalt ships the same files in every new scaffold and offers
5
+ * them from `create-basalt update`: its build copies this file verbatim to
6
+ * `packages/create-app/src/stubs.ts` (scripts/sync-stubs.mjs), and a test there
7
+ * fails if the copy drifts. Keep this module free of imports for that reason.
8
+ *
9
+ * The layout these stubs assume is the create-basalt scaffold's (BK-026):
10
+ * `pnpm build` runs `tsc -p tsconfig.build.json` (rootDir `.`, outDir `dist`),
11
+ * so `src/server.ts` compiles to {@link PRODUCTION_ENTRY}; `pnpm start` runs it
12
+ * with plain `node` — no tsx, no TypeScript at runtime. A Prisma client, when
13
+ * there is one, is generated OUTSIDE `src/` (`generated/prisma`) and imported
14
+ * through the package.json `imports` alias `#db/*`, so it resolves the same
15
+ * from `src/` (tsx) and from `dist/src/` (node).
16
+ */
17
+ /** The compiled server entry the Dockerfile runs and the scaffold's `start` script points at. */
18
+ export const PRODUCTION_ENTRY = 'dist/src/server.js';
19
+ /** Multi-stage production image: build with the dev toolchain, run on plain node as a non-root user. */
20
+ export const DOCKERFILE = `# syntax=docker/dockerfile:1
21
+ # Production image for a Basalt app (the create-basalt layout): \`pnpm build\`
22
+ # compiles src/ to dist/ and the image runs ${PRODUCTION_ENTRY} on plain
23
+ # node — no tsx, no TypeScript at runtime.
24
+ #
25
+ # docker build -t my-app .
26
+ # docker run -p 3000:3000 -e APP_SECRET=… -e DATABASE_URL=… my-app
27
+ #
28
+ # Configuration comes from the environment (nothing loads .env here, and
29
+ # .dockerignore keeps it out of the image). Database migrations are NOT run
30
+ # by the image: apply them before rolling out (\`pnpm db:deploy\` in CI).
31
+ #
32
+ # Installs with pnpm from pnpm-lock.yaml. An app on npm/yarn/bun replaces the
33
+ # pnpm install / exec / run / prune lines with its own package manager's.
34
+ ARG NODE_VERSION=22
35
+ ARG PNPM_VERSION=11
36
+
37
+ FROM node:\${NODE_VERSION}-slim AS build
38
+ ARG PNPM_VERSION
39
+ # Non-interactive pnpm: without it \`pnpm prune\` in a workspace (a --ui app's
40
+ # web/) aborts with ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY.
41
+ ENV CI=true
42
+ WORKDIR /app
43
+ RUN npm install -g pnpm@\${PNPM_VERSION}
44
+ COPY . .
45
+ # Full install: the build needs the devDependencies (typescript, prisma).
46
+ RUN pnpm install --frozen-lockfile
47
+ # The Prisma client (when the app has a schema) is generated into ./generated.
48
+ RUN if [ -f prisma/schema.prisma ]; then pnpm exec prisma generate; fi && mkdir -p generated
49
+ RUN pnpm run build
50
+ # Drop the devDependencies (tsx, typescript, prisma CLI, generators, the AI
51
+ # bridge): none of them may ship. --ignore-scripts keeps the app's postinstall
52
+ # (\`prisma generate\`, a dev tool) from running again.
53
+ RUN pnpm prune --prod --ignore-scripts
54
+
55
+ FROM node:\${NODE_VERSION}-slim AS run
56
+ ENV NODE_ENV=production
57
+ ENV PORT=3000
58
+ # Path the HEALTHCHECK probes: the scaffold's /health route by default; set
59
+ # /readyz when the app registers healthPlugin().
60
+ ENV HEALTHCHECK_PATH=/health
61
+ WORKDIR /app
62
+ COPY --from=build --chown=node:node /app/package.json ./package.json
63
+ COPY --from=build --chown=node:node /app/node_modules ./node_modules
64
+ COPY --from=build --chown=node:node /app/generated ./generated
65
+ COPY --from=build --chown=node:node /app/dist ./dist
66
+ USER node
67
+ EXPOSE 3000
68
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \\
69
+ CMD node -e "fetch('http://127.0.0.1:' + (process.env.PORT || 3000) + process.env.HEALTHCHECK_PATH).then((r) => process.exit(r.ok ? 0 : 1), () => process.exit(1))"
70
+ CMD ["node", "--enable-source-maps", "${PRODUCTION_ENTRY}"]
71
+ `;
72
+ /**
73
+ * Published with the Dockerfile: its \`COPY . .\` would otherwise bake \`.env\`,
74
+ * private keys and VCS metadata into an image layer. Every secret rule is
75
+ * \`**\/\`-prefixed: .dockerignore patterns are anchored at the context root, so
76
+ * a bare \`.env\` or \`*.pem\` would still let \`prisma/.env\` or
77
+ * \`certs/server.key\` through. \`dist\` is rebuilt inside the image.
78
+ */
79
+ export const DOCKERIGNORE = `**/.env
80
+ **/.env.*
81
+ !**/.env.example
82
+ **/.npmrc
83
+ **/.git
84
+ **/node_modules
85
+ **/coverage
86
+ **/*.log
87
+ **/*.pem
88
+ **/*.key
89
+ **/*.p12
90
+ **/*.pfx
91
+ **/.DS_Store
92
+ dist
93
+ `;
94
+ /** GitHub Actions CI: install, typecheck, build (the production path), test. */
95
+ export const CI_WORKFLOW = `name: ci
96
+ on:
97
+ push: { branches: [main] }
98
+ pull_request:
99
+ jobs:
100
+ build:
101
+ runs-on: ubuntu-latest
102
+ steps:
103
+ - uses: actions/checkout@v4
104
+ # Drop \`with: version\` if package.json declares a packageManager.
105
+ - uses: pnpm/action-setup@v4
106
+ with: { version: 11 }
107
+ - uses: actions/setup-node@v4
108
+ with: { node-version: 22, cache: pnpm }
109
+ - run: pnpm install --frozen-lockfile
110
+ - run: pnpm run typecheck
111
+ - run: pnpm run build
112
+ - run: pnpm run test
113
+ `;
114
+ export const EDITORCONFIG = `root = true
115
+
116
+ [*]
117
+ charset = utf-8
118
+ end_of_line = lf
119
+ insert_final_newline = true
120
+ indent_style = space
121
+ indent_size = 2
122
+ trim_trailing_whitespace = true
123
+ `;
@@ -33,6 +33,24 @@ export declare const versionOf: (pkg: string) => string;
33
33
  * unknown package so every emitted range lives in that single table.
34
34
  */
35
35
  export declare const thirdPartyVersionOf: (pkg: string) => string;
36
+ /**
37
+ * The production path (BK-026): `build` compiles src/ with tsconfig.build.json
38
+ * (rootDir `.`, outDir `dist`) and `start` runs the result on plain node — the
39
+ * same entry the Dockerfile's CMD runs. `start:dev` keeps the old tsx start.
40
+ */
41
+ export declare const BUILD_SCRIPT = "tsc -p tsconfig.build.json";
42
+ /** The `db:seed` script of a `--prisma` scaffold with tenancy (prisma.config.ts loads .env, then runs `migrations.seed`). */
43
+ export declare const DB_SEED_SCRIPT = "prisma db seed";
44
+ export declare const START_SCRIPT = "node --enable-source-maps dist/src/server.js";
45
+ export declare const START_DEV_SCRIPT = "tsx src/server.ts";
46
+ /** The `start` script every create-basalt release before the production path wrote. */
47
+ export declare const LEGACY_START_SCRIPT = "tsx src/server.ts";
48
+ /**
49
+ * package.json `imports` alias for the generated Prisma client. It lives in
50
+ * ./generated/prisma — outside src/, so tsc never has to copy its .js files —
51
+ * and `#db/*` resolves to it from src/ (tsx, vitest) and dist/src/ (node) alike.
52
+ */
53
+ export declare const PRISMA_IMPORTS: Readonly<Record<string, string>>;
36
54
  /** The root `basalt` script of an app without `--cli`: create-basalt's project commands. */
37
55
  export declare const BASALT_PROJECT_SCRIPT = "create-basalt --project";
38
56
  /** The root `dev:web` script of a `--ui` app (web/ is a pnpm workspace member). */
@@ -41,6 +59,15 @@ export declare const webDevScript: (options: Pick<ProjectOptions, 'name'>) => st
41
59
  export declare const enforcesMembership: (options: ProjectOptions) => boolean;
42
60
  export declare function packageJson(options: ProjectOptions): string;
43
61
  export declare function tsconfigJson(options: ProjectOptions): string;
62
+ /**
63
+ * `tsconfig.build.json` — what `pnpm build` compiles: src/ only (tests and
64
+ * bin/ stay dev-only), emitted to dist/ with rootDir `.`, so src/server.ts
65
+ * becomes dist/src/server.js. Extends tsconfig.json, so the compiler options
66
+ * (and `pnpm typecheck`) never diverge.
67
+ */
68
+ export declare function tsconfigBuildJson(): string;
69
+ /** The production Dockerfile — the same file `basalt publish dockerfile` writes. */
70
+ export declare function dockerfile(): string;
44
71
  export declare function envTs(options: ProjectOptions): string;
45
72
  /**
46
73
  * An app-specific env-var prefix derived from the project name
@@ -48,17 +75,33 @@ export declare function envTs(options: ProjectOptions): string;
48
75
  * (`DATABASE_URL`, …) other projects export too.
49
76
  */
50
77
  export declare function envPrefix(name: string): string;
78
+ /**
79
+ * The opening lines of `.env.example`. Up to create-basalt 1.10 they read
80
+ * {@link LEGACY_ENV_EXAMPLE_LEAD} ("nothing loads this file"); `update`
81
+ * swaps that for this one in existing apps.
82
+ */
83
+ export declare const ENV_EXAMPLE_LEAD = "# Development: copy this file to .env \u2014 `pnpm dev` and `pnpm basalt` load it\n# automatically (a new app already has one). `pnpm start` (production) does\n# NOT: there the variables come from the environment (or `node --env-file`).";
84
+ export declare const LEGACY_ENV_EXAMPLE_LEAD = "# Nothing loads this file for you: copy it to .env and start with\n# `node --env-file=.env` / `tsx --env-file=.env`, or export the variables.";
51
85
  export declare function envExample(options: ProjectOptions): string;
86
+ /**
87
+ * The `.env` a new app starts with (git-ignored, never in the manifest): the
88
+ * values of `.env.example` for local development plus — with auth — a freshly
89
+ * generated APP_SECRET, so `pnpm dev` works without a copy step.
90
+ */
91
+ export declare function devEnvFile(options: ProjectOptions, appSecret: string): string;
52
92
  /** A PostgreSQL-safe database name derived from the project name. */
53
93
  export declare function databaseName(name: string): string;
54
94
  export declare function appTs(options: ProjectOptions): string;
55
95
  export declare function routesTs(options: ProjectOptions): string;
56
96
  export declare function serverTs(): string;
57
97
  /**
58
- * `pnpm dev` entrypoint. Opts into NODE_ENV=development (dev secret defaults,
59
- * pretty logs) unless NODE_ENV is already set, then starts the server. Kept out
60
- * of server.ts on purpose: `pnpm start` runs server.ts directly, where an unset
61
- * NODE_ENV counts as production and secrets are required (fail-closed).
98
+ * `pnpm dev` entrypoint. Loads `.env` (when present) with `node --env-file`
99
+ * semantics — an exported variable wins, the file only fills in what is
100
+ * missing — and opts into NODE_ENV=development (dev secret defaults, pretty
101
+ * logs) unless NODE_ENV is already set, then starts the server. Kept out of
102
+ * server.ts on purpose: `pnpm start` runs server.ts directly, where nothing
103
+ * loads `.env` (production configuration comes from the real environment) and
104
+ * an unset NODE_ENV counts as production, so secrets are required (fail-closed).
62
105
  */
63
106
  export declare function devTs(): string;
64
107
  /**
@@ -85,8 +128,9 @@ export declare function prismaConfigTs(options: ProjectOptions): string;
85
128
  export declare function dbTs(options: ProjectOptions): string;
86
129
  /**
87
130
  * `prisma/seed.ts` — creates the `demo` tenant the scaffolded resolvers expect
88
- * (`x-tenant-id: demo`, `demo.localhost`). Runs from `pnpm db:seed` and after
89
- * `prisma migrate dev` (prisma.config.ts declares it).
131
+ * (`x-tenant-id: demo`, `demo.localhost`). Runs from `pnpm db:seed`
132
+ * (`prisma db seed`, the command prisma.config.ts declares) — Prisma 7's
133
+ * `migrate dev` does not run it.
90
134
  */
91
135
  export declare function prismaSeedTs(options: ProjectOptions): string;
92
136
  export declare function appTest(options: ProjectOptions): string;
@@ -113,7 +157,9 @@ export declare function mcpJson(_options: ProjectOptions): string;
113
157
  export declare function dockerignore(): string;
114
158
  export declare function gitignore(options: ProjectOptions): string;
115
159
  /**
116
- * pnpm settings: esbuild's build script is required by tsx;
160
+ * pnpm settings: esbuild's build script is required by tsx; with --prisma,
161
+ * the Prisma CLI's build scripts (prisma, @prisma/engines) are approved too — pnpm 11 fails
162
+ * the install on an unapproved build;
117
163
  * msgpackr-extract (optional native accelerator via BullMQ) is declined —
118
164
  * msgpackr falls back to pure JS. With --ui, `web` is a workspace member so
119
165
  * its own dependencies resolve.