create-basalt 1.12.0 → 1.13.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/latest-versions.d.ts +2 -0
- package/dist/latest-versions.js +13 -2
- package/dist/project/update.d.ts +11 -0
- package/dist/project/update.js +51 -1
- package/dist/templates.d.ts +2 -2
- package/dist/templates.js +14 -2
- package/dist/versions.js +19 -17
- package/package.json +16 -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 |
|
|
@@ -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/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
|
*/
|
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,6 +104,10 @@ 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'),
|
|
@@ -725,9 +729,17 @@ model AuthApiKey {
|
|
|
725
729
|
expiresAt DateTime?
|
|
726
730
|
lastUsedAt DateTime?
|
|
727
731
|
revokedAt DateTime?
|
|
732
|
+
// 3.0: API key lifecycle (migration \`add_api_key_lifecycle\`).
|
|
733
|
+
serviceId String?
|
|
734
|
+
previousHash String? @unique
|
|
735
|
+
previousHashExpiresAt DateTime?
|
|
736
|
+
rotatedAt DateTime?
|
|
737
|
+
allowedIps String[] @default([])
|
|
738
|
+
meta Json?
|
|
728
739
|
|
|
729
740
|
@@index([tenantId])
|
|
730
741
|
@@index([userId])
|
|
742
|
+
@@index([serviceId])
|
|
731
743
|
@@map("auth_api_keys")
|
|
732
744
|
}
|
|
733
745
|
|
package/dist/versions.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
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/env': '^3.1.
|
|
14
|
+
'@basaltkit/env': '^3.1.1',
|
|
14
15
|
'@basaltkit/events': '^1.3.0',
|
|
15
|
-
'@basaltkit/fastify': '^
|
|
16
|
+
'@basaltkit/fastify': '^3.0.0',
|
|
16
17
|
'@basaltkit/generator': '^1.6.0',
|
|
17
18
|
'@basaltkit/logger': '^1.3.0',
|
|
18
|
-
'@basaltkit/
|
|
19
|
-
'@basaltkit/
|
|
19
|
+
'@basaltkit/mailer': '^2.1.0',
|
|
20
|
+
'@basaltkit/mcp': '^6.0.0',
|
|
21
|
+
'@basaltkit/prisma': '^4.0.0',
|
|
20
22
|
'@basaltkit/sdk': '^2.1.0',
|
|
21
|
-
'@basaltkit/subscriptions': '^
|
|
22
|
-
'@basaltkit/subscriptions-prisma': '^
|
|
23
|
-
'@basaltkit/teams': '^4.1.
|
|
23
|
+
'@basaltkit/subscriptions': '^6.0.0',
|
|
24
|
+
'@basaltkit/subscriptions-prisma': '^4.0.0',
|
|
25
|
+
'@basaltkit/teams': '^4.1.1',
|
|
24
26
|
'@basaltkit/teams-prisma': '^1.1.0',
|
|
25
|
-
'@basaltkit/tenancy': '^
|
|
26
|
-
'@basaltkit/tenancy-prisma': '^
|
|
27
|
-
'@basaltkit/testing': '^
|
|
28
|
-
'create-basalt': '^1.
|
|
27
|
+
'@basaltkit/tenancy': '^4.0.0',
|
|
28
|
+
'@basaltkit/tenancy-prisma': '^3.0.0',
|
|
29
|
+
'@basaltkit/testing': '^3.0.0',
|
|
30
|
+
'create-basalt': '^1.13.0',
|
|
29
31
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-basalt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22.5.0"
|
|
6
6
|
},
|
|
@@ -32,26 +32,26 @@
|
|
|
32
32
|
"typescript": "^7.0.2",
|
|
33
33
|
"vitest": "^5.0.1",
|
|
34
34
|
"zod": "^4.6.5",
|
|
35
|
-
"@basaltkit/auth": "^
|
|
36
|
-
"@basaltkit/
|
|
37
|
-
"@basaltkit/
|
|
35
|
+
"@basaltkit/auth-prisma": "^3.0.0",
|
|
36
|
+
"@basaltkit/cli": "^1.4.1",
|
|
37
|
+
"@basaltkit/config": "^1.1.2",
|
|
38
38
|
"@basaltkit/core": "^1.6.0",
|
|
39
|
+
"@basaltkit/auth": "^5.0.0",
|
|
39
40
|
"@basaltkit/events": "^1.3.0",
|
|
40
|
-
"@basaltkit/
|
|
41
|
-
"@basaltkit/
|
|
41
|
+
"@basaltkit/env": "^3.1.1",
|
|
42
|
+
"@basaltkit/fastify": "^3.0.0",
|
|
43
|
+
"@basaltkit/mcp": "^6.0.0",
|
|
44
|
+
"@basaltkit/prisma": "^4.0.0",
|
|
42
45
|
"@basaltkit/generator": "^1.6.0",
|
|
43
46
|
"@basaltkit/logger": "^1.3.0",
|
|
44
|
-
"@basaltkit/
|
|
45
|
-
"@basaltkit/
|
|
46
|
-
"@basaltkit/
|
|
47
|
-
"@basaltkit/subscriptions": "^5.0.0",
|
|
48
|
-
"@basaltkit/subscriptions-prisma": "^3.0.0",
|
|
49
|
-
"@basaltkit/teams": "^4.1.0",
|
|
50
|
-
"@basaltkit/tenancy": "^3.2.0",
|
|
47
|
+
"@basaltkit/subscriptions": "^6.0.0",
|
|
48
|
+
"@basaltkit/subscriptions-prisma": "^4.0.0",
|
|
49
|
+
"@basaltkit/teams": "^4.1.1",
|
|
51
50
|
"@basaltkit/teams-prisma": "^1.1.0",
|
|
52
|
-
"@basaltkit/tenancy
|
|
53
|
-
"@basaltkit/
|
|
54
|
-
"@basaltkit/testing": "^
|
|
51
|
+
"@basaltkit/tenancy": "^4.0.0",
|
|
52
|
+
"@basaltkit/tenancy-prisma": "^3.0.0",
|
|
53
|
+
"@basaltkit/testing": "^3.0.0",
|
|
54
|
+
"@basaltkit/tsconfig": "^0.24.0"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|