create-basalt 1.13.0 → 1.14.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.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { randomBytes } from 'node:crypto';
2
2
  import { mkdir, readdir, writeFile } from 'node:fs/promises';
3
3
  import { dirname, join, resolve } from 'node:path';
4
- import { appTest, appTs, dbTs, devEnvFile, devTs, dockerfile, dockerignore, envExample, envTs, gitignore, mcpJson, basaltBin, packageJson, pnpmWorkspaceYaml, prismaConfigTs, prismaSchema, prismaSeedTs, readme, routesTs, serverTs, tsconfigBuildJson, tsconfigJson, } from './templates.js';
4
+ import { appTest, appTs, dbTs, devEnvFile, devTs, dockerfile, dockerignore, envExample, envTs, deployConfigTs, gitignore, mcpJson, basaltBin, packageJson, pnpmWorkspaceYaml, prismaConfigTs, prismaSchema, prismaSeedTs, readme, routesTs, serverTs, tsconfigBuildJson, tsconfigJson, } from './templates.js';
5
5
  import { uiFiles } from './templates-ui.js';
6
6
  import { INSECURE_SECRET } from './project/doctor.js';
7
7
  import { createManifest, MANIFEST_PATH, serializeManifest } from './project/manifest.js';
@@ -51,6 +51,7 @@ export function scaffoldFiles(options) {
51
51
  'README.md': readme(options),
52
52
  'pnpm-workspace.yaml': pnpmWorkspaceYaml(options),
53
53
  'src/env.ts': envTs(options),
54
+ 'deploy.config.ts': deployConfigTs(options),
54
55
  'src/app.ts': appTs(options),
55
56
  'src/routes.ts': routesTs(options),
56
57
  'src/server.ts': serverTs(),
@@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { basaltBin } from '../bin-template.js';
4
4
  import { collectDependencies, resolveFileVersions, resolveLatestVersions, } from '../latest-versions.js';
5
- import { appTs, BASALT_PROJECT_SCRIPT, gitignore, mcpJson, pnpmWorkspaceYaml, readme, readmeCliSection, readmeMcpSection, readmeUiSection, routesTs, versionOf, webDevScript, } from '../templates.js';
5
+ import { appTs, BASALT_PROJECT_SCRIPT, gitignore, mcpJson, pnpmWorkspaceYaml, readme, deployConfigTs, readmeCliSection, readmeMcpSection, readmeUiSection, routesTs, versionOf, webDevScript, } from '../templates.js';
6
6
  import { uiFiles } from '../templates-ui.js';
7
7
  import { createManifest, extendManifest, isPristine, MANIFEST_PATH, serializeManifest } from './manifest.js';
8
8
  import { mergePackageJson } from './package-json.js';
@@ -255,6 +255,10 @@ export async function planAdd(ctx, feature, options = {}) {
255
255
  const ignore = await readOptional(ctx.dir, '.gitignore');
256
256
  plannedEdit(b, '.gitignore', ignore, ignore === undefined ? gitignore(next) : ensureGitignore(ignore, ['node_modules/', 'dist/']), 'ignore web/ build output');
257
257
  await plannedReadme(b, regenOptions, '## Web UI', readmeUiSection(next));
258
+ // The deploy builds web/ too (served as web/dist by the proxy).
259
+ if ((await readOptional(ctx.dir, 'deploy.config.ts')) !== undefined) {
260
+ await plannedSource(b, 'deploy.config.ts', regenOptions ? () => deployConfigTs(regenOptions) : undefined, (source) => (/\bweb:/.test(source) ? source : /build: \{ ([^}\n]*) \}/.test(source) ? source.replace(/build: \{ ([^}\n]*) \}/, "build: { $1, web: 'web' }") : undefined), "add web: 'web' to build in deploy.config.ts, so the deploy builds the frontend.");
261
+ }
258
262
  b.notes.push('No CORS change needed: the Vite dev server proxies /api to the API on :3000.');
259
263
  }
260
264
  if (feature === 'cli') {
@@ -155,6 +155,18 @@ export declare function mcpJson(_options: ProjectOptions): string;
155
155
  * `certs/server.key` through.
156
156
  */
157
157
  export declare function dockerignore(): string;
158
+ /**
159
+ * The C4 owner label `@basaltkit/deploy` names everything with
160
+ * (`[a-z][a-z0-9-]{1,30}`), from the package name.
161
+ */
162
+ export declare function deployAppName(name: string): string;
163
+ /**
164
+ * `deploy.config.ts` (RFC 0007 §3): what `basalt-deploy init` writes for this
165
+ * scaffold — PM2 behind Apache, a dedicated Postgres when the app has one, the
166
+ * compiled build, the app's own secret generated on the server. Typed by
167
+ * src/env.ts. The domain is the one thing to change.
168
+ */
169
+ export declare function deployConfigTs(options: ProjectOptions): string;
158
170
  export declare function gitignore(options: ProjectOptions): string;
159
171
  /**
160
172
  * pnpm settings: esbuild's build script is required by tsx; with --prisma,
package/dist/templates.js CHANGED
@@ -111,6 +111,9 @@ export function packageJson(options) {
111
111
  // The project commands (\`pnpm basalt update | add | doctor | info\`) — dev
112
112
  // tooling with no dependencies of its own, never imported by the app.
113
113
  'create-basalt': versionOf('create-basalt'),
114
+ // Production deploy (deploy.config.ts): dev tooling, run on the server as
115
+ // `node node_modules/@basaltkit/deploy/dist/bin.js run`, never imported by the app.
116
+ '@basaltkit/deploy': versionOf('@basaltkit/deploy'),
114
117
  };
115
118
  for (const pkg of ['@types/node', 'pino-pretty', 'tsx', 'typescript', 'vitest']) {
116
119
  devDependencies[pkg] = thirdPartyVersionOf(pkg);
@@ -1286,6 +1289,64 @@ export function mcpJson(_options) {
1286
1289
  export function dockerignore() {
1287
1290
  return DOCKERIGNORE;
1288
1291
  }
1292
+ /**
1293
+ * The C4 owner label `@basaltkit/deploy` names everything with
1294
+ * (`[a-z][a-z0-9-]{1,30}`), from the package name.
1295
+ */
1296
+ export function deployAppName(name) {
1297
+ // Trimmed in linear time: an anchored `-+$` regex backtracks on long runs of '-'.
1298
+ const base = name.replace(/^@[^/]+\//, '').toLowerCase().replace(/[^a-z0-9]+/g, '-');
1299
+ let start = 0;
1300
+ while (start < base.length && !(base[start] >= 'a' && base[start] <= 'z'))
1301
+ start++;
1302
+ let end = Math.min(base.length, start + 31);
1303
+ while (end > start && base[end - 1] === '-')
1304
+ end--;
1305
+ const slug = base.slice(start, end);
1306
+ return /^[a-z][a-z0-9-]{1,30}$/.test(slug) ? slug : 'app';
1307
+ }
1308
+ /**
1309
+ * `deploy.config.ts` (RFC 0007 §3): what `basalt-deploy init` writes for this
1310
+ * scaffold — PM2 behind Apache, a dedicated Postgres when the app has one, the
1311
+ * compiled build, the app's own secret generated on the server. Typed by
1312
+ * src/env.ts. The domain is the one thing to change.
1313
+ */
1314
+ export function deployConfigTs(options) {
1315
+ const app = deployAppName(options.name);
1316
+ const helpers = ['apache', 'defineDeploy', ...(options.prisma ? ['dockerInfra'] : []), 'pm2', ...(options.auth ? ['secret'] : [])];
1317
+ const build = [...(options.prisma ? [`prisma: ['prisma.config.ts']`] : []), `script: 'build'`, ...(options.ui ? [`web: 'web'`] : [])];
1318
+ return `/**
1319
+ * Production deploy with @basaltkit/deploy, on one Linux server. Holds no secrets.
1320
+ *
1321
+ * node node_modules/@basaltkit/deploy/dist/bin.js check # this file, without a server (CI)
1322
+ * node node_modules/@basaltkit/deploy/dist/bin.js plan # on the server: what run would do
1323
+ * node node_modules/@basaltkit/deploy/dist/bin.js run
1324
+ *
1325
+ * Rewrite it from the project at any time:
1326
+ * node node_modules/@basaltkit/deploy/dist/bin.js init --force --domain=<host>
1327
+ */
1328
+ import type { env } from './src/env.js'
1329
+ import { ${helpers.join(', ')} } from '@basaltkit/deploy'
1330
+
1331
+ export default defineDeploy<typeof env>({
1332
+ app: '${app}',
1333
+ domain: '${app}.example.com', // the domain the app answers on
1334
+
1335
+ env: {
1336
+ schema: 'src/env.ts',
1337
+ fixed: { NODE_ENV: 'production', HOST: '127.0.0.1' },${options.auth ? `
1338
+ generate: { APP_SECRET: secret(32) },` : ''}
1339
+ },${options.prisma ? `
1340
+ infra: dockerInfra('${app}', { redis: false }),` : ''}
1341
+ build: { ${build.join(', ')} },${options.prisma ? `
1342
+ migrate: { central: true },` : ''}
1343
+
1344
+ runtime: pm2(),
1345
+ proxy: apache(),
1346
+ health: { path: '/health' },
1347
+ })
1348
+ `;
1349
+ }
1289
1350
  export function gitignore(options) {
1290
1351
  return `node_modules/
1291
1352
  dist/
package/dist/versions.js CHANGED
@@ -11,6 +11,7 @@ export const SCAFFOLD_VERSIONS = {
11
11
  '@basaltkit/cli': '^1.4.1',
12
12
  '@basaltkit/config': '^1.1.2',
13
13
  '@basaltkit/core': '^1.6.0',
14
+ '@basaltkit/deploy': '^0.3.0',
14
15
  '@basaltkit/env': '^3.1.1',
15
16
  '@basaltkit/events': '^1.3.0',
16
17
  '@basaltkit/fastify': '^3.0.0',
@@ -27,5 +28,5 @@ export const SCAFFOLD_VERSIONS = {
27
28
  '@basaltkit/tenancy': '^4.0.0',
28
29
  '@basaltkit/tenancy-prisma': '^3.0.0',
29
30
  '@basaltkit/testing': '^3.0.0',
30
- 'create-basalt': '^1.13.0',
31
+ 'create-basalt': '^1.14.0',
31
32
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-basalt",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "engines": {
5
5
  "node": ">=22.5.0"
6
6
  },
@@ -32,25 +32,26 @@
32
32
  "typescript": "^7.0.2",
33
33
  "vitest": "^5.0.1",
34
34
  "zod": "^4.6.5",
35
+ "@basaltkit/auth": "^5.0.0",
35
36
  "@basaltkit/auth-prisma": "^3.0.0",
36
37
  "@basaltkit/cli": "^1.4.1",
37
38
  "@basaltkit/config": "^1.1.2",
38
39
  "@basaltkit/core": "^1.6.0",
39
- "@basaltkit/auth": "^5.0.0",
40
- "@basaltkit/events": "^1.3.0",
41
40
  "@basaltkit/env": "^3.1.1",
41
+ "@basaltkit/events": "^1.3.0",
42
42
  "@basaltkit/fastify": "^3.0.0",
43
- "@basaltkit/mcp": "^6.0.0",
44
- "@basaltkit/prisma": "^4.0.0",
45
43
  "@basaltkit/generator": "^1.6.0",
46
44
  "@basaltkit/logger": "^1.3.0",
45
+ "@basaltkit/prisma": "^4.0.0",
47
46
  "@basaltkit/subscriptions": "^6.0.0",
48
- "@basaltkit/subscriptions-prisma": "^4.0.0",
47
+ "@basaltkit/deploy": "^0.3.0",
48
+ "@basaltkit/mcp": "^6.0.0",
49
49
  "@basaltkit/teams": "^4.1.1",
50
- "@basaltkit/teams-prisma": "^1.1.0",
51
- "@basaltkit/tenancy": "^4.0.0",
50
+ "@basaltkit/subscriptions-prisma": "^4.0.0",
52
51
  "@basaltkit/tenancy-prisma": "^3.0.0",
52
+ "@basaltkit/teams-prisma": "^1.1.0",
53
53
  "@basaltkit/testing": "^3.0.0",
54
+ "@basaltkit/tenancy": "^4.0.0",
54
55
  "@basaltkit/tsconfig": "^0.24.0"
55
56
  },
56
57
  "publishConfig": {