create-basalt 1.14.1 → 1.14.2

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.
@@ -2,6 +2,8 @@
2
2
  export declare const PROJECT_COMMANDS_MARKER = "['update', 'add', 'doctor', 'info'].includes(process.argv[2]";
3
3
  /** Marker proving a bin/basalt.ts already has the dev prelude (.env loading, `upgrade`, env errors). */
4
4
  export declare const DEV_PRELUDE_MARKER = "process.loadEnvFile(envFile)";
5
+ /** Marker proving a bin/basalt.ts already runs the generators without booting the app. */
6
+ export declare const GENERATORS_PRELUDE_MARKER = "process.argv[2]?.startsWith('make:')";
5
7
  export declare function basaltBin(): string;
6
8
  /**
7
9
  * Hashes of every bin/basalt.ts an earlier create-basalt release generated
@@ -11,13 +13,16 @@ export declare function basaltBin(): string;
11
13
  export declare const LEGACY_BIN_HASHES: ReadonlySet<string>;
12
14
  export declare const hasProjectCommands: (content: string) => boolean;
13
15
  export declare const hasDevPrelude: (content: string) => boolean;
16
+ export declare const hasGeneratorsPrelude: (content: string) => boolean;
14
17
  /**
15
18
  * Upgrades a template-generated bin/basalt.ts to the current template, step by
16
19
  * step: (1) without the project commands, inserts their prelude after the
17
20
  * shebang and turns the remaining static imports into dynamic ones (so they no
18
21
  * longer run before it); (2) without the dev prelude, inserts it right after
19
- * the project commands and routes the app import through `explainBootFailure`.
20
- * Deterministic for the known templates — for the latest ones (1.9, 1.10) the
22
+ * the project commands and routes the app import through `explainBootFailure`;
23
+ * (3) without the generators prelude, inserts it right before the dev tools
24
+ * are imported for the booted CLI.
25
+ * Deterministic for the known templates — for the latest ones (1.9 to 1.14) the
21
26
  * result is exactly {@link basaltBin}.
22
27
  */
23
28
  export declare function patchBasaltBin(content: string): string;
@@ -174,10 +174,35 @@ async function databaseInUse(): Promise<{ name: string; target: string }> {
174
174
  }
175
175
  }
176
176
  `;
177
+ /**
178
+ * The GENERATORS PRELUDE, after the dev prelude and still before anything of
179
+ * the app is imported: `make:*` only writes source files, so — like `upgrade` —
180
+ * it runs without booting the app. Booting it would run every boot check, and
181
+ * a generator would refuse to work until the database is up and migrated (or
182
+ * every environment variable is set), which is often exactly when the
183
+ * resource is being written. Any other command, and a `make:*` the generator
184
+ * does not know, falls through to the booted CLI below.
185
+ */
186
+ const GENERATORS_PRELUDE = `// The generators (make:*) only write source files: like \`upgrade\`, they run
187
+ // without booting the app, so they work before the database is up or migrated.
188
+ if (process.argv[2]?.startsWith('make:')) {
189
+ const { consoleIo, parseArgv } = await import('@basaltkit/cli')
190
+ const { generatorCommands } = await import('@basaltkit/generator')
191
+ const { command, args, flags } = parseArgv(process.argv.slice(2))
192
+ const make = generatorCommands().find((candidate) => candidate.name === command)
193
+ if (make) {
194
+ // The generators read only io/args/flags — there is no app to hand them.
195
+ const context = { io: consoleIo(), args, flags } as unknown as Parameters<typeof make.handle>[0]
196
+ process.exit((await make.handle(context)) ?? 0)
197
+ }
198
+ }
199
+ `;
177
200
  /** Marker proving a bin/basalt.ts already delegates the project commands. */
178
201
  export const PROJECT_COMMANDS_MARKER = "['update', 'add', 'doctor', 'info'].includes(process.argv[2]";
179
202
  /** Marker proving a bin/basalt.ts already has the dev prelude (.env loading, `upgrade`, env errors). */
180
203
  export const DEV_PRELUDE_MARKER = 'process.loadEnvFile(envFile)';
204
+ /** Marker proving a bin/basalt.ts already runs the generators without booting the app. */
205
+ export const GENERATORS_PRELUDE_MARKER = "process.argv[2]?.startsWith('make:')";
181
206
  const APP_IMPORT = "await import('../src/app.js')";
182
207
  const APP_IMPORT_EXPLAINED = `${APP_IMPORT}.catch(explainBootFailure)`;
183
208
  const RUN_CLI = 'process.exit(await runCli({ app })';
@@ -185,6 +210,7 @@ export function basaltBin() {
185
210
  return `#!/usr/bin/env node
186
211
  ${PRELUDE}
187
212
  ${DEV_PRELUDE}
213
+ ${GENERATORS_PRELUDE}
188
214
  // The dev tools are imported dynamically, after the project commands above.
189
215
  const { runCli } = await import('@basaltkit/cli')
190
216
  const { generatorCommands } = await import('@basaltkit/generator')
@@ -228,16 +254,24 @@ export const LEGACY_BIN_HASHES = new Set([
228
254
  // 2026-10-01 (create-basalt 1.10): project commands (update/add/doctor/info)
229
255
  // delegated before boot — but no .env loading and `upgrade` booted the app.
230
256
  'sha256-9091e137a5de39929d0e70b2fd973386b9cc1c2f996e130989a22c795b9d0893',
257
+ // 2026-10-01 (create-basalt 1.11): the dev prelude — but make:* booted the
258
+ // app, so a generator needed a migrated database.
259
+ 'sha256-bd0b6c9c40089a18c2c2f1a70953044d6a74a329d38a72903b494b1f2265a114',
260
+ // 2026-10-08: database diagnoses in explainBootFailure — make:* still booted.
261
+ 'sha256-abea8cbfdb41a302cabad7929617f7fc2fe822345aa8db6ff777e923eb0fc96b',
231
262
  ]);
232
263
  export const hasProjectCommands = (content) => content.includes(PROJECT_COMMANDS_MARKER);
233
264
  export const hasDevPrelude = (content) => content.includes(DEV_PRELUDE_MARKER);
265
+ export const hasGeneratorsPrelude = (content) => content.includes(GENERATORS_PRELUDE_MARKER);
234
266
  /**
235
267
  * Upgrades a template-generated bin/basalt.ts to the current template, step by
236
268
  * step: (1) without the project commands, inserts their prelude after the
237
269
  * shebang and turns the remaining static imports into dynamic ones (so they no
238
270
  * longer run before it); (2) without the dev prelude, inserts it right after
239
- * the project commands and routes the app import through `explainBootFailure`.
240
- * Deterministic for the known templates — for the latest ones (1.9, 1.10) the
271
+ * the project commands and routes the app import through `explainBootFailure`;
272
+ * (3) without the generators prelude, inserts it right before the dev tools
273
+ * are imported for the booted CLI.
274
+ * Deterministic for the known templates — for the latest ones (1.9 to 1.14) the
241
275
  * result is exactly {@link basaltBin}.
242
276
  */
243
277
  export function patchBasaltBin(content) {
@@ -246,6 +280,8 @@ export function patchBasaltBin(content) {
246
280
  text = addProjectCommands(text);
247
281
  if (!hasDevPrelude(text))
248
282
  text = addDevPrelude(text);
283
+ if (!hasGeneratorsPrelude(text))
284
+ text = addGeneratorsPrelude(text);
249
285
  return text;
250
286
  }
251
287
  function addProjectCommands(content) {
@@ -273,11 +309,19 @@ function addDevPrelude(content) {
273
309
  .replace(`${RUN_CLI})\n`, `${RUN_CLI}.catch(explainBootFailure))\n`);
274
310
  return `${content.slice(0, end)}${DEV_PRELUDE}\n${rest}`;
275
311
  }
312
+ /** Inserts the generators prelude right before the dev tools are imported for the booted CLI. */
313
+ function addGeneratorsPrelude(content) {
314
+ const anchor = /^(?:\/\/ The dev tools are imported dynamically[^\n]*\n)?const \{ runCli \} = await import\('@basaltkit\/cli'\)$/m.exec(content);
315
+ // Without the template's dynamic CLI import, the file is not ours to rearrange.
316
+ if (!anchor || !hasDevPrelude(content))
317
+ return content;
318
+ return `${content.slice(0, anchor.index)}${GENERATORS_PRELUDE}\n${content.slice(anchor.index)}`;
319
+ }
276
320
  /** Where a bin/basalt.ts stands: already current, an untouched old template, or user code. */
277
321
  export function binStatus(content, manifestHash) {
278
322
  if (content === undefined)
279
323
  return 'absent';
280
- if (hasProjectCommands(content) && hasDevPrelude(content))
324
+ if (hasProjectCommands(content) && hasDevPrelude(content) && hasGeneratorsPrelude(content))
281
325
  return 'current';
282
326
  const hash = hashContent(content);
283
327
  return LEGACY_BIN_HASHES.has(hash) || hash === manifestHash ? 'patchable' : 'modified';
@@ -300,6 +344,13 @@ and explains env errors — and change the app import to
300
344
  \`const { buildApp } = ${APP_IMPORT_EXPLAINED}\`:
301
345
 
302
346
  ${DEV_PRELUDE}`);
347
+ }
348
+ if (!hasGeneratorsPrelude(content)) {
349
+ steps.push(`${steps.length > 0 ? 'Then paste' : 'Paste'} this after the dev prelude (before the dev tools are imported for the
350
+ booted CLI) — it runs the make:* generators without booting the app, so they
351
+ work before the database is up or migrated:
352
+
353
+ ${GENERATORS_PRELUDE}`);
303
354
  }
304
355
  return steps.join('\n');
305
356
  }
@@ -382,10 +382,10 @@ export async function runDoctor(ctx, options = {}) {
382
382
  const bin = await readText(join(dir, 'bin', 'basalt.ts'));
383
383
  const status = binStatus(bin, ctx.manifest?.files['bin/basalt.ts']);
384
384
  if (status === 'patchable') {
385
- push('warn', 'tooling', 'bin/basalt.ts is an older template (no .env loading / pre-boot project commands) — `npx create-basalt@latest update` patches it.');
385
+ push('warn', 'tooling', 'bin/basalt.ts is an older template (it lacks some of: .env loading, pre-boot project commands, make:* without booting the app) — `npx create-basalt@latest update` patches it.');
386
386
  }
387
387
  if (status === 'modified') {
388
- push('info', 'tooling', 'bin/basalt.ts is customised and lacks the current preludes (project commands, .env loading, pre-boot `upgrade`) — see `create-basalt update` for the snippet.');
388
+ push('info', 'tooling', 'bin/basalt.ts is customised and lacks the current preludes (project commands, .env loading, pre-boot `upgrade` and make:*) — see `create-basalt update` for the snippet.');
389
389
  }
390
390
  const dev = await readText(join(dir, 'src', 'dev.ts'));
391
391
  const devStatus = devEntryStatus(dev, ctx.manifest?.files['src/dev.ts']);
@@ -1,6 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { binStatus, hasProjectCommands, manualBinSnippet, patchBasaltBin } from '../bin-template.js';
3
+ import { binStatus, hasDevPrelude, hasProjectCommands, manualBinSnippet, patchBasaltBin } from '../bin-template.js';
4
4
  import { devEntryStatus, MANUAL_DEV_SNIPPET, patchDevEntry, patchEnvExample } from '../dev-entry.js';
5
5
  import { alwaysLatest, lookupLatestVersions, minimumReleaseAgeMinutes, } from '../latest-versions.js';
6
6
  import { BASALT_PROJECT_SCRIPT } from '../templates.js';
@@ -207,7 +207,7 @@ export async function planUpdate(ctx, options = {}) {
207
207
  const after = patchBasaltBin(bin);
208
208
  files['bin/basalt.ts'] = { before: bin, after };
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`);
210
+ toolingNotes.push(`bin/basalt.ts: unmodified template from an earlier release — ${hasProjectCommands(bin) ? '' : 'gains update/add/doctor/info; '}${hasDevPrelude(bin) ? '' : 'loads .env for development, runs \`upgrade\` without booting the app, explains env errors; '}runs make:* without booting the app (no database needed to generate code)`);
211
211
  }
212
212
  else if (status === 'modified' && bin !== undefined) {
213
213
  manual.push(`bin/basalt.ts was customised, so it was not patched. To bring it up to date:\n${manualBinSnippet(bin)}`);
package/dist/templates.js CHANGED
@@ -367,9 +367,13 @@ export function appTs(options) {
367
367
  if (options.prisma) {
368
368
  imports.push(`import { prismaPlugin } from '@basaltkit/prisma'`);
369
369
  imports.push(`import { db, prisma } from './db.js'`);
370
- plugins.push(`prismaPlugin({
370
+ plugins.push(`prismaPlugin({${options.tenancy
371
+ ? `
371
372
  // \`db\` is the tenant-scoped client (src/db.ts): db<PrismaClient>() in a
372
- // handler returns it, already filtered by the request's tenant.
373
+ // handler returns it, already filtered by the request's tenant.`
374
+ : `
375
+ // \`db\` is the application client (src/db.ts): db<PrismaClient>() in a
376
+ // handler returns it. No tenancy, so queries are not filtered by tenant.`}
373
377
  client: db,
374
378
  // Fail the BOOT when this database is not the migrated one — a shell that
375
379
  // exported another project's DATABASE_URL, a typo in the database name.
package/dist/versions.js CHANGED
@@ -11,11 +11,11 @@ export const SCAFFOLD_VERSIONS = {
11
11
  '@basaltkit/cli': '^1.4.2',
12
12
  '@basaltkit/config': '^1.1.2',
13
13
  '@basaltkit/core': '^1.6.0',
14
- '@basaltkit/deploy': '^0.5.0',
14
+ '@basaltkit/deploy': '^0.8.0',
15
15
  '@basaltkit/env': '^3.1.1',
16
16
  '@basaltkit/events': '^1.3.0',
17
17
  '@basaltkit/fastify': '^3.0.0',
18
- '@basaltkit/generator': '^1.6.0',
18
+ '@basaltkit/generator': '^1.7.0',
19
19
  '@basaltkit/logger': '^1.3.0',
20
20
  '@basaltkit/mailer': '^2.1.0',
21
21
  '@basaltkit/mcp': '^6.0.0',
@@ -28,5 +28,5 @@ export const SCAFFOLD_VERSIONS = {
28
28
  '@basaltkit/tenancy': '^4.0.0',
29
29
  '@basaltkit/tenancy-prisma': '^3.0.0',
30
30
  '@basaltkit/testing': '^3.0.0',
31
- 'create-basalt': '^1.14.1',
31
+ 'create-basalt': '^1.14.2',
32
32
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-basalt",
3
- "version": "1.14.1",
3
+ "version": "1.14.2",
4
4
  "engines": {
5
5
  "node": ">=22.5.0"
6
6
  },
@@ -24,23 +24,23 @@
24
24
  "@prisma/adapter-pg": "^7.10.0",
25
25
  "@prisma/client": "^7.10.0",
26
26
  "@prisma/client-runtime-utils": "^7.10.0",
27
- "@types/node": "^26.6.1",
27
+ "@types/node": "^26.6.5",
28
28
  "@types/pg": "^8.23.1",
29
- "pg": "^8.23.0",
29
+ "pg": "^8.23.1",
30
30
  "prisma": "^7.10.0",
31
- "tsx": "^4.23.13",
31
+ "tsx": "^4.23.15",
32
32
  "typescript": "^7.0.2",
33
- "vitest": "^5.0.1",
34
- "zod": "^4.6.5",
35
- "@basaltkit/auth": "^5.0.0",
36
- "@basaltkit/auth-prisma": "^3.0.0",
37
- "@basaltkit/config": "^1.1.2",
33
+ "vitest": "^5.0.3",
34
+ "zod": "^4.6.6",
38
35
  "@basaltkit/cli": "^1.4.2",
36
+ "@basaltkit/config": "^1.1.2",
39
37
  "@basaltkit/core": "^1.6.0",
40
- "@basaltkit/deploy": "^0.5.0",
38
+ "@basaltkit/auth-prisma": "^3.0.0",
39
+ "@basaltkit/deploy": "^0.8.0",
40
+ "@basaltkit/env": "^3.1.1",
41
41
  "@basaltkit/events": "^1.3.0",
42
42
  "@basaltkit/fastify": "^3.0.0",
43
- "@basaltkit/generator": "^1.6.0",
43
+ "@basaltkit/generator": "^1.7.0",
44
44
  "@basaltkit/logger": "^1.3.0",
45
45
  "@basaltkit/mcp": "^6.0.0",
46
46
  "@basaltkit/prisma": "^4.0.0",
@@ -50,9 +50,9 @@
50
50
  "@basaltkit/teams-prisma": "^1.1.0",
51
51
  "@basaltkit/tenancy": "^4.0.0",
52
52
  "@basaltkit/tenancy-prisma": "^3.0.0",
53
- "@basaltkit/env": "^3.1.1",
53
+ "@basaltkit/testing": "^3.0.0",
54
54
  "@basaltkit/tsconfig": "^0.24.0",
55
- "@basaltkit/testing": "^3.0.0"
55
+ "@basaltkit/auth": "^5.0.0"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"