create-basalt 1.0.0 → 1.1.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Machize Contributors
3
+ Copyright (c) 2026 Basalt Contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -21,12 +21,22 @@ function packageJson(options) {
21
21
  if (options.billing) dependencies["@basaltkit/subscriptions"] = BASALT_VERSION;
22
22
  if (options.cli) {
23
23
  dependencies["@basaltkit/cli"] = BASALT_VERSION;
24
- dependencies["@basaltkit/generator"] = BASALT_VERSION;
25
24
  dependencies["@basaltkit/prisma"] = BASALT_VERSION;
26
25
  }
27
26
  for (const pkg of Object.keys(dependencies)) {
28
27
  if (pkg.startsWith("@basaltkit/")) dependencies[pkg] = versionOf(pkg);
29
28
  }
29
+ const devDependencies = {
30
+ "@basaltkit/testing": versionOf("@basaltkit/testing"),
31
+ "@types/node": "^22.15.0",
32
+ "pino-pretty": "^13.0.0",
33
+ tsx: "^4.19.0",
34
+ typescript: "^5.8.0",
35
+ vitest: "^3.1.0"
36
+ };
37
+ if (options.cli) {
38
+ devDependencies["@basaltkit/generator"] = versionOf("@basaltkit/generator");
39
+ }
30
40
  return `${JSON.stringify(
31
41
  {
32
42
  name: options.name,
@@ -41,14 +51,7 @@ function packageJson(options) {
41
51
  ...options.cli ? { basalt: "tsx bin/basalt.ts" } : {}
42
52
  },
43
53
  dependencies: Object.fromEntries(Object.entries(dependencies).sort()),
44
- devDependencies: {
45
- "@basaltkit/testing": versionOf("@basaltkit/testing"),
46
- "@types/node": "^22.15.0",
47
- "pino-pretty": "^13.0.0",
48
- tsx: "^4.19.0",
49
- typescript: "^5.8.0",
50
- vitest: "^3.1.0"
51
- }
54
+ devDependencies: Object.fromEntries(Object.entries(devDependencies).sort())
52
55
  },
53
56
  null,
54
57
  2
@@ -77,7 +80,7 @@ function tsconfigJson() {
77
80
  `;
78
81
  }
79
82
  function envTs(options) {
80
- return `import { defineEnv } from '@basaltkit/env'
83
+ return `import { defineEnv${options.auth ? ", secret" : ""} } from '@basaltkit/env'
81
84
  import { z } from 'zod'
82
85
 
83
86
  export const env = defineEnv({
@@ -85,7 +88,9 @@ export const env = defineEnv({
85
88
  HOST: z.string().default('0.0.0.0'),
86
89
  LOG_LEVEL: z.string().default('info'),
87
90
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),${options.auth ? `
88
- APP_SECRET: z.string().min(16).default('change-me-in-production--'),` : ""}
91
+ // Signs JWTs and sessions. secret() is fail-closed: required in production
92
+ // (no fallback), rejected if it looks like a placeholder. Dev uses devDefault.
93
+ APP_SECRET: secret({ minLength: 32, devDefault: 'dev-only-insecure-secret-please-change-me' }),` : ""}
89
94
  })
90
95
  `;
91
96
  }
@@ -94,20 +99,26 @@ function envExample(options) {
94
99
  HOST=0.0.0.0
95
100
  LOG_LEVEL=info
96
101
  NODE_ENV=development
97
- ${options.auth ? "APP_SECRET=change-me-in-production--\n" : ""}`;
102
+ ${options.auth ? "# Required in production (the app refuses to boot without it).\n# Generate a strong one: openssl rand -base64 48\n# APP_SECRET=\n" : ""}`;
98
103
  }
99
104
  function appTs(options) {
100
105
  const imports = [
101
106
  `import { createApp } from '@basaltkit/core'`,
102
107
  `import { configPlugin } from '@basaltkit/config'`,
103
108
  `import { eventsPlugin } from '@basaltkit/events'`,
104
- `import { fastifyPlugin } from '@basaltkit/fastify'`,
109
+ `import { fastifyPlugin, securityPlugin } from '@basaltkit/fastify'`,
105
110
  `import { loggerPlugin } from '@basaltkit/logger'`
106
111
  ];
107
112
  const plugins = [
108
113
  `configPlugin({ app: { name: '${options.name}' } })`,
109
114
  `loggerPlugin({ level: options.logLevel ?? 'info', ...(options.pretty ? { pretty: true } : {}) })`,
110
- `eventsPlugin()`
115
+ `eventsPlugin()`,
116
+ `securityPlugin({
117
+ // Secure response headers (HSTS, X-Frame-Options, nosniff, \u2026) are on by
118
+ // default. Turn on rate limiting and a CORS allow-list for production:
119
+ // rateLimit: { limit: 120, windowMs: 60_000 },
120
+ // cors: { origin: ['https://app.example.com'], credentials: true },
121
+ })`
111
122
  ];
112
123
  let routesExpression = "appRoutes";
113
124
  if (options.tenancy) {
@@ -143,18 +154,19 @@ function appTs(options) {
143
154
  })`);
144
155
  }
145
156
  if (options.cli) {
146
- imports.push(`import { commandsPlugin } from '@basaltkit/cli'`);
147
- imports.push(`import { generatorCommands } from '@basaltkit/generator'`);
148
- imports.push(`import { prismaSyncCommand } from '@basaltkit/prisma'`);
149
- plugins.push(`commandsPlugin([...generatorCommands(), prismaSyncCommand()])`);
157
+ imports.push(`import { commandsPlugin, type CommandDefinition } from '@basaltkit/cli'`);
158
+ plugins.push(`...(options.commands && options.commands.length > 0 ? [commandsPlugin(options.commands)] : [])`);
150
159
  }
151
160
  plugins.push(`fastifyPlugin({ routes: ${routesExpression} })`);
161
+ const commandsField = options.cli ? `
162
+ /** Dev/CLI commands (make:*, ai:*, prisma:sync) \u2014 passed ONLY by bin/basalt.ts. */
163
+ commands?: CommandDefinition[]` : "";
152
164
  return `${imports.join("\n")}
153
165
  import { appRoutes } from './routes.js'
154
166
 
155
167
  export interface BuildAppOptions {
156
168
  logLevel?: string
157
- pretty?: boolean
169
+ pretty?: boolean${commandsField}
158
170
  }
159
171
 
160
172
  export function buildApp(options: BuildAppOptions = {}) {
@@ -229,14 +241,22 @@ for (const signal of ['SIGINT', 'SIGTERM'] as const) {
229
241
  function basaltBin() {
230
242
  return `#!/usr/bin/env node
231
243
  import { runCli } from '@basaltkit/cli'
244
+ import { generatorCommands } from '@basaltkit/generator'
245
+ import { prismaSyncCommand } from '@basaltkit/prisma'
232
246
  import { buildApp } from '../src/app.js'
233
247
 
234
- // The 'basalt' CLI: boots the app, runs one command, shuts down.
248
+ // The 'basalt' CLI: boots the app WITH the dev/CLI commands, runs one, shuts down.
249
+ // The dev tools (@basaltkit/generator; add @basaltkit/ai for ai:*) are imported
250
+ // ONLY here \u2014 the runtime server (src/server.ts) never loads them, so the SaaS
251
+ // runs without the codegen/AI layer.
235
252
  // pnpm basalt list \u2014 show available commands
236
253
  // pnpm basalt routes \u2014 list registered HTTP routes
237
254
  // pnpm basalt make:resource Project \u2014 generate a full resource vertical
238
255
  // pnpm basalt make:service Project \u2014 generate a single artifact (schema/service/\u2026)
239
- const app = buildApp({ logLevel: 'silent' })
256
+ const app = buildApp({
257
+ logLevel: 'silent',
258
+ commands: [...generatorCommands(), prismaSyncCommand()],
259
+ })
240
260
  process.exit(await runCli({ app }))
241
261
  `;
242
262
  }
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  TargetNotEmptyError,
4
4
  createProject,
5
5
  detectPackageManager
6
- } from "./chunk-RFS7HGZ6.js";
6
+ } from "./chunk-TYOPE3RU.js";
7
7
 
8
8
  // src/cli.ts
9
9
  import { spawn } from "child_process";
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  TargetNotEmptyError,
3
3
  createProject,
4
4
  detectPackageManager
5
- } from "./chunk-RFS7HGZ6.js";
5
+ } from "./chunk-TYOPE3RU.js";
6
6
  export {
7
7
  TargetNotEmptyError,
8
8
  createProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-basalt",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Scaffold a production-shaped Basalt SaaS app: npm create basalt my-saas [--billing] [--ui] [--cli] [--install] [--git]",
5
5
  "license": "MIT",
6
6
  "type": "module",