create-basalt 1.12.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/README.md +6 -2
- package/dist/index.js +2 -1
- package/dist/latest-versions.d.ts +2 -0
- package/dist/latest-versions.js +13 -2
- package/dist/project/add.js +5 -1
- package/dist/project/update.d.ts +11 -0
- package/dist/project/update.js +51 -1
- package/dist/templates.d.ts +14 -2
- package/dist/templates.js +75 -2
- package/dist/versions.js +20 -17
- package/package.json +17 -16
package/README.md
CHANGED
|
@@ -273,7 +273,11 @@ newest release **on the app's current major** (a newer major is listed as
|
|
|
273
273
|
`minimumReleaseAge`, read from the project's `pnpm-workspace.yaml` when set) is
|
|
274
274
|
left for later so the install cannot refuse it. When a framework release
|
|
275
275
|
declares a peer range the app would not meet (say `zod ^5` while zod is held on
|
|
276
|
-
4), the plan warns before anything is written.
|
|
276
|
+
4), the plan warns before anything is written. When a framework release
|
|
277
|
+
requires an `@basaltkit/*` peer the app does not list (`@basaltkit/testing` 3
|
|
278
|
+
takes `@basaltkit/mailer`), the plan adds it at its latest version (in
|
|
279
|
+
`dependencies` when a runtime dependency needs it, else `devDependencies`), or
|
|
280
|
+
warns when it cannot; optional peers are never added.
|
|
277
281
|
|
|
278
282
|
Both `package.json` and `web/package.json` are updated, **in place**: only the
|
|
279
283
|
version strings change — order, indentation and range style (`^`, `~`, exact)
|
|
@@ -466,7 +470,7 @@ Detects the manager that invoked the command from `npm_config_user_agent` (or th
|
|
|
466
470
|
| --- | --- |
|
|
467
471
|
| `runProjectCommand(argv, deps)` | Runs `update`/`add`/`doctor`/`info` and returns the exit code; every side effect (output, prompts, package-manager runs, registry fetch, codemods) is injected through `deps` |
|
|
468
472
|
| `loadProject(dir, pm?)` | Reads an app: package.json (+ `web/`), manifest, detected features and package manager. Throws `NotABasaltAppError` |
|
|
469
|
-
| `planUpdate(ctx, { major?, only?, tooling?, registry? })` | The update plan — entries, the full before/after of every file, tooling, warnings, framework majors. Writes nothing |
|
|
473
|
+
| `planUpdate(ctx, { major?, only?, tooling?, registry? })` | The update plan — entries, the full before/after of every file, tooling, warnings, framework majors, required peers it adds (`addedPeers`). Writes nothing |
|
|
470
474
|
| `planAdd(ctx, feature, { force?, resolveLatest?, registry? })` | The add plan — created/merged/skipped files and manual steps. Writes nothing |
|
|
471
475
|
| `runDoctor(ctx, options)` | Doctor findings (`{ level: 'ok' \| 'info' \| 'warn' \| 'error', area, message }`) |
|
|
472
476
|
| `MANIFEST_PATH`, `readManifest(dir)`, `hashContent(text)` | The scaffold manifest |
|
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(),
|
|
@@ -114,6 +114,8 @@ export interface LatestInfo {
|
|
|
114
114
|
latest?: string;
|
|
115
115
|
/** `peerDependencies` declared by that latest version. */
|
|
116
116
|
peers: Record<string, string>;
|
|
117
|
+
/** The peers its `peerDependenciesMeta` marks optional (absent: none). */
|
|
118
|
+
optionalPeers?: string[];
|
|
117
119
|
/**
|
|
118
120
|
* Release age of `latest` against the window: `mature` (provably older, or
|
|
119
121
|
* not probed), `recent` (inside the window) or `unknown` (could not prove it).
|
package/dist/latest-versions.js
CHANGED
|
@@ -153,6 +153,15 @@ function peersOf(body) {
|
|
|
153
153
|
}
|
|
154
154
|
return peers;
|
|
155
155
|
}
|
|
156
|
+
/** The peers `peerDependenciesMeta` marks `optional: true`. */
|
|
157
|
+
function optionalPeersOf(body) {
|
|
158
|
+
const raw = body?.peerDependenciesMeta;
|
|
159
|
+
if (!raw || typeof raw !== 'object')
|
|
160
|
+
return [];
|
|
161
|
+
return Object.entries(raw)
|
|
162
|
+
.filter(([, meta]) => typeof meta === 'object' && meta !== null && meta.optional === true)
|
|
163
|
+
.map(([name]) => name);
|
|
164
|
+
}
|
|
156
165
|
async function lookupLatest(fetchImpl, registry, name, signal) {
|
|
157
166
|
try {
|
|
158
167
|
const response = await fetchImpl(latestUrl(registry, name), {
|
|
@@ -165,7 +174,9 @@ async function lookupLatest(fetchImpl, registry, name, signal) {
|
|
|
165
174
|
return 'miss';
|
|
166
175
|
const body = (await response.json());
|
|
167
176
|
const version = body?.version;
|
|
168
|
-
return typeof version === 'string' && STABLE_SEMVER.test(version)
|
|
177
|
+
return typeof version === 'string' && STABLE_SEMVER.test(version)
|
|
178
|
+
? { version, peers: peersOf(body), optionalPeers: optionalPeersOf(body) }
|
|
179
|
+
: 'miss';
|
|
169
180
|
}
|
|
170
181
|
catch {
|
|
171
182
|
// Network error, per-request timeout, or malformed JSON.
|
|
@@ -223,7 +234,7 @@ export async function lookupLatestVersions(names, shouldProbe, options = {}) {
|
|
|
223
234
|
const age = windowMs === 0 || !shouldProbe(name, found.version)
|
|
224
235
|
? 'mature'
|
|
225
236
|
: await probeAge(fetchImpl, registry, name, windowMs, now, AbortSignal.any([AbortSignal.timeout(timeoutMs), overall.signal]));
|
|
226
|
-
results.set(name, { latest: found.version, peers: found.peers, age });
|
|
237
|
+
results.set(name, { latest: found.version, peers: found.peers, optionalPeers: found.optionalPeers, age });
|
|
227
238
|
}
|
|
228
239
|
};
|
|
229
240
|
const pool = Math.max(1, Math.min(options.concurrency ?? CONCURRENCY, names.length));
|
package/dist/project/add.js
CHANGED
|
@@ -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') {
|
package/dist/project/update.d.ts
CHANGED
|
@@ -76,6 +76,17 @@ export interface UpdatePlan {
|
|
|
76
76
|
to: string;
|
|
77
77
|
changelog: string;
|
|
78
78
|
}[];
|
|
79
|
+
/**
|
|
80
|
+
* Required `@basaltkit/*` peers of the framework releases the app ends up on
|
|
81
|
+
* that its package.json did not list (testing 3 takes mailer): added at their
|
|
82
|
+
* latest version, in `dependencies` when a runtime dependency needs them.
|
|
83
|
+
*/
|
|
84
|
+
addedPeers: {
|
|
85
|
+
name: string;
|
|
86
|
+
range: string;
|
|
87
|
+
section: 'dependencies' | 'devDependencies';
|
|
88
|
+
requiredBy: string[];
|
|
89
|
+
}[];
|
|
79
90
|
registry: string;
|
|
80
91
|
}
|
|
81
92
|
export interface UpdateOptions {
|
package/dist/project/update.js
CHANGED
|
@@ -277,6 +277,50 @@ export async function planUpdate(ctx, options = {}) {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
|
+
// A required @basaltkit peer the app never declared: pnpm and npm may
|
|
281
|
+
// auto-install it, but yarn PnP, `auto-install-peers=false` or
|
|
282
|
+
// `--legacy-peer-deps` do not, and `doctor` checks installed versions, not
|
|
283
|
+
// the manifest. Add it at its latest version; when that is impossible
|
|
284
|
+
// (registry, release-age window, out of range), say so.
|
|
285
|
+
const declared = new Set(entries.filter((entry) => entry.file === 'package.json').map((entry) => entry.name));
|
|
286
|
+
const missing = new Map();
|
|
287
|
+
for (const entry of entries) {
|
|
288
|
+
if (!entry.framework || (entry.status !== 'update' && entry.status !== 'current') || entry.file !== 'package.json')
|
|
289
|
+
continue;
|
|
290
|
+
const info = results.get(entry.name);
|
|
291
|
+
for (const [peer, wanted] of Object.entries(info?.peers ?? {})) {
|
|
292
|
+
if (!isFramework(peer) || declared.has(peer) || info?.optionalPeers?.includes(peer))
|
|
293
|
+
continue;
|
|
294
|
+
const prior = missing.get(peer);
|
|
295
|
+
const section = entry.section === 'dependencies' || prior?.section === 'dependencies' ? 'dependencies' : 'devDependencies';
|
|
296
|
+
const requiredBy = [...(prior?.requiredBy ?? []), `${entry.name}@${info?.latest}`];
|
|
297
|
+
missing.set(peer, { wanted: prior?.wanted ?? wanted, requiredBy: [...new Set(requiredBy)], section });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const addedPeers = [];
|
|
301
|
+
if (missing.size > 0) {
|
|
302
|
+
const peerLookup = await lookupLatestVersions([...missing.keys()].sort(), (name) => !exempt(name), {
|
|
303
|
+
...options.registry,
|
|
304
|
+
minimumReleaseAge: window,
|
|
305
|
+
});
|
|
306
|
+
const additions = { dependencies: {}, devDependencies: {} };
|
|
307
|
+
for (const [peer, need] of missing) {
|
|
308
|
+
const found = peerLookup.results.get(peer);
|
|
309
|
+
if (found?.latest !== undefined && found.age === 'mature' && satisfies(found.latest, need.wanted) === true) {
|
|
310
|
+
const range = `^${found.latest}`;
|
|
311
|
+
additions[need.section][peer] = range;
|
|
312
|
+
addedPeers.push({ name: peer, range, section: need.section, requiredBy: need.requiredBy });
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
warnings.push(`${need.requiredBy.join(', ')} requires ${peer} ${need.wanted}, which package.json does not list — add it (${ctx.pm} add ${need.section === 'devDependencies' ? '-D ' : ''}${peer})`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (addedPeers.length > 0) {
|
|
319
|
+
const merged = mergePackageJson(files['package.json']?.after ?? ctx.packageJsonText, additions);
|
|
320
|
+
if (merged.changes.length > 0)
|
|
321
|
+
files['package.json'] = { before: ctx.packageJsonText, after: merged.text };
|
|
322
|
+
}
|
|
323
|
+
}
|
|
280
324
|
const failed = entries.filter((entry) => entry.status === 'failed').map((entry) => entry.name);
|
|
281
325
|
if (failed.length > 0)
|
|
282
326
|
warnings.push(`The registry did not answer for ${[...new Set(failed)].join(', ')} — left unchanged.`);
|
|
@@ -289,7 +333,7 @@ export async function planUpdate(ctx, options = {}) {
|
|
|
289
333
|
changelog: changelogUrl(entry.name),
|
|
290
334
|
}))
|
|
291
335
|
.filter((major, i, all) => all.findIndex((other) => other.name === major.name) === i);
|
|
292
|
-
return { entries, updates, files, tooling: toolingNotes, manual, warnings, majors, registry };
|
|
336
|
+
return { entries, updates, files, tooling: toolingNotes, manual, warnings, majors, addedPeers, registry };
|
|
293
337
|
}
|
|
294
338
|
/** The plan as terminal lines: the update table, then notes, tooling, warnings and majors. */
|
|
295
339
|
export function renderUpdatePlan(plan, colors) {
|
|
@@ -328,6 +372,12 @@ export function renderUpdatePlan(plan, colors) {
|
|
|
328
372
|
lines.push(` ${major.name} ${major.from} → ${major.to}: ${major.changelog}`);
|
|
329
373
|
lines.push(` Upgrade notes: ${DOCS_UPGRADING_URL}`);
|
|
330
374
|
}
|
|
375
|
+
if (plan.addedPeers.length > 0) {
|
|
376
|
+
lines.push('', colors.bold('Required peers the app did not list (added):'));
|
|
377
|
+
for (const peer of plan.addedPeers) {
|
|
378
|
+
lines.push(` ${colors.cyan(peer.name)} ${peer.range} (${peer.section}) — required by ${peer.requiredBy.join(', ')}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
331
381
|
if (plan.tooling.length > 0) {
|
|
332
382
|
lines.push('', colors.bold('Project tooling:'));
|
|
333
383
|
for (const note of plan.tooling)
|
package/dist/templates.d.ts
CHANGED
|
@@ -20,8 +20,8 @@ export { basaltBin } from './bin-template.js';
|
|
|
20
20
|
export { SCAFFOLD_VERSIONS } from './versions.js';
|
|
21
21
|
export { THIRD_PARTY_VERSIONS } from './latest-versions.js';
|
|
22
22
|
/**
|
|
23
|
-
* The dependency range for a @basaltkit/* package:
|
|
24
|
-
* (`^<major>.<minor
|
|
23
|
+
* The dependency range for a @basaltkit/* package: its workspace version as
|
|
24
|
+
* the floor (`^<major>.<minor>.<patch>`), from the generated
|
|
25
25
|
* {@link SCAFFOLD_VERSIONS} map. Throws for an unknown package rather than
|
|
26
26
|
* guessing a range — a stale guess once pinned new apps to frozen 1.x lines.
|
|
27
27
|
*/
|
|
@@ -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
|
@@ -5,8 +5,8 @@ export { basaltBin } from './bin-template.js';
|
|
|
5
5
|
export { SCAFFOLD_VERSIONS } from './versions.js';
|
|
6
6
|
export { THIRD_PARTY_VERSIONS } from './latest-versions.js';
|
|
7
7
|
/**
|
|
8
|
-
* The dependency range for a @basaltkit/* package:
|
|
9
|
-
* (`^<major>.<minor
|
|
8
|
+
* The dependency range for a @basaltkit/* package: its workspace version as
|
|
9
|
+
* the floor (`^<major>.<minor>.<patch>`), from the generated
|
|
10
10
|
* {@link SCAFFOLD_VERSIONS} map. Throws for an unknown package rather than
|
|
11
11
|
* guessing a range — a stale guess once pinned new apps to frozen 1.x lines.
|
|
12
12
|
*/
|
|
@@ -104,9 +104,16 @@ export function packageJson(options) {
|
|
|
104
104
|
}
|
|
105
105
|
const devDependencies = {
|
|
106
106
|
'@basaltkit/testing': versionOf('@basaltkit/testing'),
|
|
107
|
+
// @basaltkit/testing's peer: fakeMailer() binds the app's own MAILER token,
|
|
108
|
+
// so the copy must be the app's (a package manager that skips peers would
|
|
109
|
+
// otherwise leave `@basaltkit/testing` unable to load).
|
|
110
|
+
'@basaltkit/mailer': versionOf('@basaltkit/mailer'),
|
|
107
111
|
// The project commands (\`pnpm basalt update | add | doctor | info\`) — dev
|
|
108
112
|
// tooling with no dependencies of its own, never imported by the app.
|
|
109
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'),
|
|
110
117
|
};
|
|
111
118
|
for (const pkg of ['@types/node', 'pino-pretty', 'tsx', 'typescript', 'vitest']) {
|
|
112
119
|
devDependencies[pkg] = thirdPartyVersionOf(pkg);
|
|
@@ -725,9 +732,17 @@ model AuthApiKey {
|
|
|
725
732
|
expiresAt DateTime?
|
|
726
733
|
lastUsedAt DateTime?
|
|
727
734
|
revokedAt DateTime?
|
|
735
|
+
// 3.0: API key lifecycle (migration \`add_api_key_lifecycle\`).
|
|
736
|
+
serviceId String?
|
|
737
|
+
previousHash String? @unique
|
|
738
|
+
previousHashExpiresAt DateTime?
|
|
739
|
+
rotatedAt DateTime?
|
|
740
|
+
allowedIps String[] @default([])
|
|
741
|
+
meta Json?
|
|
728
742
|
|
|
729
743
|
@@index([tenantId])
|
|
730
744
|
@@index([userId])
|
|
745
|
+
@@index([serviceId])
|
|
731
746
|
@@map("auth_api_keys")
|
|
732
747
|
}
|
|
733
748
|
|
|
@@ -1274,6 +1289,64 @@ export function mcpJson(_options) {
|
|
|
1274
1289
|
export function dockerignore() {
|
|
1275
1290
|
return DOCKERIGNORE;
|
|
1276
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
|
+
}
|
|
1277
1350
|
export function gitignore(options) {
|
|
1278
1351
|
return `node_modules/
|
|
1279
1352
|
dist/
|
package/dist/versions.js
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
// GENERATED by scripts/sync-versions.mjs (runs before every build) — do not edit.
|
|
2
2
|
// The dependency range a new app gets for each @basaltkit/* package: the
|
|
3
|
-
//
|
|
3
|
+
// workspace version as the floor (^<major>.<minor>.<patch>), so a new app never
|
|
4
|
+
// resolves an older patch of the same line.
|
|
4
5
|
export const SCAFFOLD_VERSIONS = {
|
|
5
6
|
'@basaltkit/admin': '^2.0.0',
|
|
6
|
-
'@basaltkit/admin-shadcn': '^1.1.
|
|
7
|
+
'@basaltkit/admin-shadcn': '^1.1.1',
|
|
7
8
|
'@basaltkit/ai-mcp': '^0.4.0',
|
|
8
|
-
'@basaltkit/auth': '^
|
|
9
|
-
'@basaltkit/auth-prisma': '^
|
|
10
|
-
'@basaltkit/cli': '^1.4.
|
|
11
|
-
'@basaltkit/config': '^1.1.
|
|
9
|
+
'@basaltkit/auth': '^5.0.0',
|
|
10
|
+
'@basaltkit/auth-prisma': '^3.0.0',
|
|
11
|
+
'@basaltkit/cli': '^1.4.1',
|
|
12
|
+
'@basaltkit/config': '^1.1.2',
|
|
12
13
|
'@basaltkit/core': '^1.6.0',
|
|
13
|
-
'@basaltkit/
|
|
14
|
+
'@basaltkit/deploy': '^0.3.0',
|
|
15
|
+
'@basaltkit/env': '^3.1.1',
|
|
14
16
|
'@basaltkit/events': '^1.3.0',
|
|
15
|
-
'@basaltkit/fastify': '^
|
|
17
|
+
'@basaltkit/fastify': '^3.0.0',
|
|
16
18
|
'@basaltkit/generator': '^1.6.0',
|
|
17
19
|
'@basaltkit/logger': '^1.3.0',
|
|
18
|
-
'@basaltkit/
|
|
19
|
-
'@basaltkit/
|
|
20
|
+
'@basaltkit/mailer': '^2.1.0',
|
|
21
|
+
'@basaltkit/mcp': '^6.0.0',
|
|
22
|
+
'@basaltkit/prisma': '^4.0.0',
|
|
20
23
|
'@basaltkit/sdk': '^2.1.0',
|
|
21
|
-
'@basaltkit/subscriptions': '^
|
|
22
|
-
'@basaltkit/subscriptions-prisma': '^
|
|
23
|
-
'@basaltkit/teams': '^4.1.
|
|
24
|
+
'@basaltkit/subscriptions': '^6.0.0',
|
|
25
|
+
'@basaltkit/subscriptions-prisma': '^4.0.0',
|
|
26
|
+
'@basaltkit/teams': '^4.1.1',
|
|
24
27
|
'@basaltkit/teams-prisma': '^1.1.0',
|
|
25
|
-
'@basaltkit/tenancy': '^
|
|
26
|
-
'@basaltkit/tenancy-prisma': '^
|
|
27
|
-
'@basaltkit/testing': '^
|
|
28
|
-
'create-basalt': '^1.
|
|
28
|
+
'@basaltkit/tenancy': '^4.0.0',
|
|
29
|
+
'@basaltkit/tenancy-prisma': '^3.0.0',
|
|
30
|
+
'@basaltkit/testing': '^3.0.0',
|
|
31
|
+
'create-basalt': '^1.14.0',
|
|
29
32
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-basalt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22.5.0"
|
|
6
6
|
},
|
|
@@ -32,26 +32,27 @@
|
|
|
32
32
|
"typescript": "^7.0.2",
|
|
33
33
|
"vitest": "^5.0.1",
|
|
34
34
|
"zod": "^4.6.5",
|
|
35
|
-
"@basaltkit/auth": "^
|
|
36
|
-
"@basaltkit/auth-prisma": "^
|
|
37
|
-
"@basaltkit/cli": "^1.4.
|
|
35
|
+
"@basaltkit/auth": "^5.0.0",
|
|
36
|
+
"@basaltkit/auth-prisma": "^3.0.0",
|
|
37
|
+
"@basaltkit/cli": "^1.4.1",
|
|
38
|
+
"@basaltkit/config": "^1.1.2",
|
|
38
39
|
"@basaltkit/core": "^1.6.0",
|
|
40
|
+
"@basaltkit/env": "^3.1.1",
|
|
39
41
|
"@basaltkit/events": "^1.3.0",
|
|
40
|
-
"@basaltkit/fastify": "^
|
|
41
|
-
"@basaltkit/config": "^1.1.2",
|
|
42
|
+
"@basaltkit/fastify": "^3.0.0",
|
|
42
43
|
"@basaltkit/generator": "^1.6.0",
|
|
43
44
|
"@basaltkit/logger": "^1.3.0",
|
|
44
|
-
"@basaltkit/
|
|
45
|
-
"@basaltkit/
|
|
46
|
-
"@basaltkit/
|
|
47
|
-
"@basaltkit/
|
|
48
|
-
"@basaltkit/
|
|
49
|
-
"@basaltkit/
|
|
50
|
-
"@basaltkit/tenancy": "^3.
|
|
45
|
+
"@basaltkit/prisma": "^4.0.0",
|
|
46
|
+
"@basaltkit/subscriptions": "^6.0.0",
|
|
47
|
+
"@basaltkit/deploy": "^0.3.0",
|
|
48
|
+
"@basaltkit/mcp": "^6.0.0",
|
|
49
|
+
"@basaltkit/teams": "^4.1.1",
|
|
50
|
+
"@basaltkit/subscriptions-prisma": "^4.0.0",
|
|
51
|
+
"@basaltkit/tenancy-prisma": "^3.0.0",
|
|
51
52
|
"@basaltkit/teams-prisma": "^1.1.0",
|
|
52
|
-
"@basaltkit/
|
|
53
|
-
"@basaltkit/
|
|
54
|
-
"@basaltkit/
|
|
53
|
+
"@basaltkit/testing": "^3.0.0",
|
|
54
|
+
"@basaltkit/tenancy": "^4.0.0",
|
|
55
|
+
"@basaltkit/tsconfig": "^0.24.0"
|
|
55
56
|
},
|
|
56
57
|
"publishConfig": {
|
|
57
58
|
"access": "public"
|