@elytracms/cli 0.0.87 → 0.0.88
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/package.json +2 -2
- package/src/cli.js +3 -1
- package/src/doctor.js +74 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elytracms/cli",
|
|
3
3
|
"author": "finaldream <hi@finaldream.de>",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.88",
|
|
5
5
|
"description": "The Elytra CLI — run a consuming repo's studio, frontend, and Convex backend under one command.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"node": ">=22.18.0"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@elytracms/core": "^0.0.
|
|
20
|
+
"@elytracms/core": "^0.0.88"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"vitest": "^4.1.10"
|
package/src/cli.js
CHANGED
|
@@ -117,7 +117,9 @@ and are checked in the studio), and reports the generated-previews artifacts
|
|
|
117
117
|
(manifest/files present; hash staleness lives in \`elytra previews --check\`).
|
|
118
118
|
With studio/ deps installed, config validity is checked for real: doctor
|
|
119
119
|
executes elytra.config.ts through your studio's own Vite (takes a few
|
|
120
|
-
seconds); without deps it stays an honest "unknown" with the reason.
|
|
120
|
+
seconds); without deps it stays an honest "unknown" with the reason. With
|
|
121
|
+
the config resolved, it also reads the public delivery snapshot and warns
|
|
122
|
+
about published documents whose collection the config does not declare.
|
|
121
123
|
Exit non-zero if any check fails. Read-only.
|
|
122
124
|
|
|
123
125
|
Options:
|
package/src/doctor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs'
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import { dirname, join } from 'node:path'
|
|
4
|
+
import { orphanedCollections } from '@elytracms/core/cms-core'
|
|
4
5
|
import {
|
|
5
6
|
REVALIDATE_ENV_ENDPOINT,
|
|
6
7
|
REVALIDATE_ENV_SECRET,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
checkDeploymentReady,
|
|
9
10
|
expectedDeploymentEnv,
|
|
10
11
|
probeAuthSigningKeys,
|
|
12
|
+
probeDeliverySnapshot,
|
|
11
13
|
probeDeployedFunctionsVersion,
|
|
12
14
|
probeRevalidateEndpoint,
|
|
13
15
|
} from '@elytracms/core/export-sync/deployment-ready'
|
|
@@ -201,7 +203,7 @@ export function configFactsFromOutcome(outcome) {
|
|
|
201
203
|
issueCount: issues.length,
|
|
202
204
|
...(firstIssue ? { firstIssue: formatConfigIssue(firstIssue) } : {}),
|
|
203
205
|
}
|
|
204
|
-
const project =
|
|
206
|
+
const project = resolvedProjectOf(outcome)
|
|
205
207
|
const collections = project?.collections
|
|
206
208
|
// EC-524: the `componentIds` fact was gathered here for EC-508's presentation
|
|
207
209
|
// check, which resolved a collection's declared `presentation.wrapper` against
|
|
@@ -216,6 +218,60 @@ export function configFactsFromOutcome(outcome) {
|
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
|
|
221
|
+
/**
|
|
222
|
+
* The project a resolved config outcome describes — the first one, the same choice
|
|
223
|
+
* {@link configFactsFromOutcome} makes for `collections` — or `undefined` when the
|
|
224
|
+
* config did not resolve validly (or was never evaluated). Pure.
|
|
225
|
+
*/
|
|
226
|
+
export function resolvedProjectOf(outcome) {
|
|
227
|
+
if (!outcome || outcome.kind !== 'resolved' || outcome.result?.ok !== true) return undefined
|
|
228
|
+
return outcome.result.projects?.[0]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// --- Published orphans (EC-606) -----------------------------------------------------
|
|
232
|
+
//
|
|
233
|
+
// A published document whose collection the config does not declare is still on the
|
|
234
|
+
// public delivery snapshot, but no route or query addresses it and the studio hides it.
|
|
235
|
+
// The doctor reads the snapshot (public, published-only — what every visitor receives)
|
|
236
|
+
// and runs core's ONE counter (`orphanedCollections`, the same one the studio's session
|
|
237
|
+
// hydration runs) against the resolved config's collection ids.
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Gather the `publishedOrphans` fact for a convex target, or `undefined` for any other
|
|
241
|
+
* target (no deployment, no snapshot). Without a declared set — the config did not
|
|
242
|
+
* resolve here — the fact is an honest `unknown` carrying why, and no request is made.
|
|
243
|
+
* `project` is {@link resolvedProjectOf}'s answer; `configFacts` is what
|
|
244
|
+
* {@link configFactsFromOutcome} returned (for the reason text).
|
|
245
|
+
*/
|
|
246
|
+
export async function gatherPublishedOrphans({
|
|
247
|
+
target,
|
|
248
|
+
project,
|
|
249
|
+
configFacts = {},
|
|
250
|
+
fetchImpl = fetch,
|
|
251
|
+
probe = probeDeliverySnapshot,
|
|
252
|
+
} = {}) {
|
|
253
|
+
if (target?.kind !== 'convex') return undefined
|
|
254
|
+
if (!project || !Array.isArray(project.collections)) {
|
|
255
|
+
const reason =
|
|
256
|
+
configFacts.config !== undefined && !configFacts.config.valid
|
|
257
|
+
? 'fix the workspace config issues first (see config-valid).'
|
|
258
|
+
: (configFacts.configUnavailableDetail ?? 'elytra.config.ts was not evaluated here.')
|
|
259
|
+
return {
|
|
260
|
+
status: 'unknown',
|
|
261
|
+
detail: `Published documents were not checked against the declared collections — ${reason}`,
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const snapshot = await probe(target.url, project.slug, fetchImpl)
|
|
265
|
+
if (snapshot.status !== 'answered') return { status: 'unknown', detail: snapshot.detail }
|
|
266
|
+
return {
|
|
267
|
+
status: 'counted',
|
|
268
|
+
orphans: orphanedCollections(
|
|
269
|
+
snapshot.collections.map((collection) => ({ collection, published: true })),
|
|
270
|
+
project.collections.map((collection) => collection.id),
|
|
271
|
+
),
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
219
275
|
// --- Deployment env-var presence (EC-399) --------------------------------------
|
|
220
276
|
//
|
|
221
277
|
// The Convex deployment's own env (`npx convex env set …`) lives in NO file a
|
|
@@ -441,6 +497,11 @@ export function formatReport(report) {
|
|
|
441
497
|
* version and the `functions-version` check gets a real answer; otherwise the fact is
|
|
442
498
|
* omitted → an honest `unknown`. Resolution stays at the entry point so this function
|
|
443
499
|
* remains pure/injected like every other gatherer here.
|
|
500
|
+
*
|
|
501
|
+
* EC-606: against a convex target the `app` bucket also reports PUBLISHED ORPHANS —
|
|
502
|
+
* published documents whose collection the resolved config does not declare — read
|
|
503
|
+
* from the public delivery snapshot ({@link gatherPublishedOrphans}). A `warn` at most,
|
|
504
|
+
* so the exit code never changes; without a resolved config it is an honest `unknown`.
|
|
444
505
|
*/
|
|
445
506
|
export async function runDoctor({
|
|
446
507
|
env = {},
|
|
@@ -491,12 +552,23 @@ export async function runDoctor({
|
|
|
491
552
|
// (announced by the harness itself — the boot costs seconds). Merged BEFORE the
|
|
492
553
|
// contract composes the report so `config-valid`/`asset-collection` are real checks.
|
|
493
554
|
let configFacts = {}
|
|
555
|
+
let outcome
|
|
494
556
|
if (configOutcome !== undefined || root !== undefined) {
|
|
495
|
-
|
|
557
|
+
outcome = configOutcome ?? (await executeWorkspaceConfig({ root, studioDir, log }))
|
|
496
558
|
configFacts = configFactsFromOutcome(outcome)
|
|
497
559
|
Object.assign(facts, configFacts)
|
|
498
560
|
}
|
|
499
561
|
|
|
562
|
+
// EC-606: published documents of undeclared collections — one more request on the
|
|
563
|
+
// same public query API, made only when the config resolved (it needs the declared set).
|
|
564
|
+
const publishedOrphans = await gatherPublishedOrphans({
|
|
565
|
+
target,
|
|
566
|
+
project: resolvedProjectOf(outcome),
|
|
567
|
+
configFacts,
|
|
568
|
+
fetchImpl,
|
|
569
|
+
})
|
|
570
|
+
if (publishedOrphans) facts.publishedOrphans = publishedOrphans
|
|
571
|
+
|
|
500
572
|
const report = checkDeploymentReady(facts)
|
|
501
573
|
|
|
502
574
|
// EC-440: the previews bucket (repo artifacts, backend-independent). Appended to
|