@superbee/core 0.2.0-pre.16 → 0.2.0-pre.17
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 +107 -4
- package/dist/bundle-health/index.d.ts +14 -0
- package/dist/bundle-health/index.d.ts.map +1 -0
- package/dist/bundle-health/index.js +12 -0
- package/dist/bundle-health/index.js.map +1 -0
- package/dist/bundle-health/kind-findings.d.ts +44 -0
- package/dist/bundle-health/kind-findings.d.ts.map +1 -0
- package/dist/bundle-health/kind-findings.js +68 -0
- package/dist/bundle-health/kind-findings.js.map +1 -0
- package/dist/bundle-health/legacy-page.d.ts +39 -0
- package/dist/bundle-health/legacy-page.d.ts.map +1 -0
- package/dist/bundle-health/legacy-page.js +50 -0
- package/dist/bundle-health/legacy-page.js.map +1 -0
- package/dist/bundle-health/report.d.ts +202 -0
- package/dist/bundle-health/report.d.ts.map +1 -0
- package/dist/bundle-health/report.js +438 -0
- package/dist/bundle-health/report.js.map +1 -0
- package/dist/hosted-client/write.d.ts +10 -1
- package/dist/hosted-client/write.d.ts.map +1 -1
- package/dist/hosted-client/write.js +9 -4
- package/dist/hosted-client/write.js.map +1 -1
- package/dist/hosted-transport/answer-rows.d.ts +3 -2
- package/dist/hosted-transport/answer-rows.d.ts.map +1 -1
- package/dist/hosted-transport/answer-rows.js +1 -1
- package/dist/hosted-transport/answer-rows.js.map +1 -1
- package/dist/hosted-transport/whole-document-transport.d.ts +1 -1
- package/dist/hosted-transport/whole-document-transport.d.ts.map +1 -1
- package/dist/hosted-transport/whole-document-transport.js +20 -12
- package/dist/hosted-transport/whole-document-transport.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kinds-load.js +4 -4
- package/dist/kinds-load.js.map +1 -1
- package/dist/kinds.d.ts.map +1 -1
- package/dist/kinds.js +3 -2
- package/dist/kinds.js.map +1 -1
- package/dist/paths.d.ts +16 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +25 -0
- package/dist/paths.js.map +1 -1
- package/dist/query-filter.d.ts +9 -0
- package/dist/query-filter.d.ts.map +1 -1
- package/dist/query-filter.js +19 -3
- package/dist/query-filter.js.map +1 -1
- package/dist/record-overlay/apply.d.ts +43 -0
- package/dist/record-overlay/apply.d.ts.map +1 -0
- package/dist/record-overlay/apply.js +490 -0
- package/dist/record-overlay/apply.js.map +1 -0
- package/dist/record-overlay/canonical.d.ts +14 -0
- package/dist/record-overlay/canonical.d.ts.map +1 -0
- package/dist/record-overlay/canonical.js +31 -0
- package/dist/record-overlay/canonical.js.map +1 -0
- package/dist/record-overlay/digest.d.ts +4 -0
- package/dist/record-overlay/digest.d.ts.map +1 -0
- package/dist/record-overlay/digest.js +11 -0
- package/dist/record-overlay/digest.js.map +1 -0
- package/dist/record-overlay/errors.d.ts +40 -0
- package/dist/record-overlay/errors.d.ts.map +1 -0
- package/dist/record-overlay/errors.js +51 -0
- package/dist/record-overlay/errors.js.map +1 -0
- package/dist/record-overlay/findings.d.ts +5 -0
- package/dist/record-overlay/findings.d.ts.map +1 -0
- package/dist/record-overlay/findings.js +83 -0
- package/dist/record-overlay/findings.js.map +1 -0
- package/dist/record-overlay/index.d.ts +23 -0
- package/dist/record-overlay/index.d.ts.map +1 -0
- package/dist/record-overlay/index.js +21 -0
- package/dist/record-overlay/index.js.map +1 -0
- package/dist/record-overlay/plan.d.ts +12 -0
- package/dist/record-overlay/plan.d.ts.map +1 -0
- package/dist/record-overlay/plan.js +284 -0
- package/dist/record-overlay/plan.js.map +1 -0
- package/dist/record-overlay/policy.d.ts +60 -0
- package/dist/record-overlay/policy.d.ts.map +1 -0
- package/dist/record-overlay/policy.js +209 -0
- package/dist/record-overlay/policy.js.map +1 -0
- package/dist/record-overlay/redact.d.ts +3 -0
- package/dist/record-overlay/redact.d.ts.map +1 -0
- package/dist/record-overlay/redact.js +27 -0
- package/dist/record-overlay/redact.js.map +1 -0
- package/dist/record-overlay/signal-kind.d.ts +30 -0
- package/dist/record-overlay/signal-kind.d.ts.map +1 -0
- package/dist/record-overlay/signal-kind.js +38 -0
- package/dist/record-overlay/signal-kind.js.map +1 -0
- package/dist/record-overlay/signal-text.d.ts +45 -0
- package/dist/record-overlay/signal-text.d.ts.map +1 -0
- package/dist/record-overlay/signal-text.js +116 -0
- package/dist/record-overlay/signal-text.js.map +1 -0
- package/dist/record-overlay/source-index.d.ts +19 -0
- package/dist/record-overlay/source-index.d.ts.map +1 -0
- package/dist/record-overlay/source-index.js +102 -0
- package/dist/record-overlay/source-index.js.map +1 -0
- package/dist/record-overlay/types.d.ts +286 -0
- package/dist/record-overlay/types.d.ts.map +1 -0
- package/dist/record-overlay/types.js +2 -0
- package/dist/record-overlay/types.js.map +1 -0
- package/dist/remote-operations.js +5 -2
- package/dist/remote-operations.js.map +1 -1
- package/dist/storage.d.ts +2 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1 -1
- package/dist/storage.js.map +1 -1
- package/dist/uncertain-write.d.ts +39 -6
- package/dist/uncertain-write.d.ts.map +1 -1
- package/dist/uncertain-write.js +25 -3
- package/dist/uncertain-write.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -173,6 +173,103 @@ target this bundle's edition), `RecipeAssetConflict` (`recipe`, `key`), `RecipeE
|
|
|
173
173
|
`RecipeEvolutionInterrupted` (`reason`, `completed`, `pending`, `cause`) and
|
|
174
174
|
`RecipeEvolutionPostcondition` (`reason`, `completed`).
|
|
175
175
|
|
|
176
|
+
## Record overlay
|
|
177
|
+
|
|
178
|
+
`@superbee/core/record-overlay` is the write half of binding documents to external records. A
|
|
179
|
+
Source Feed policy names the fields a feed owns; the caller fetches and diffs its records and hands
|
|
180
|
+
the changes to the planner. It uses no Node globals or builtins, so it runs in Node, a browser or a
|
|
181
|
+
Worker over any storage backend.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { MemoryBackend } from "@superbee/core/memory-backend";
|
|
185
|
+
import { buildKindRegistry } from "@superbee/core/kinds";
|
|
186
|
+
import { applyRecordOverlay, buildSourceIndex, planRecordOverlay, readOverlayPolicy } from "@superbee/core/record-overlay";
|
|
187
|
+
|
|
188
|
+
const bundle = { root: "memory://guide", backend: new MemoryBackend() };
|
|
189
|
+
const registry = buildKindRegistry(conventionDocs);
|
|
190
|
+
const guide = { bundle, registry, okfVersion: "0.2" as const };
|
|
191
|
+
const policy = readOverlayPolicy(sourceFeedDoc, { targetKind: registry.kinds.get("Event") });
|
|
192
|
+
const overlays = await buildSourceIndex(bundle, { type: policy.target_kind });
|
|
193
|
+
const plan = await planRecordOverlay({ content: guide, ops: guide, policy, changes, observedAt, overlays });
|
|
194
|
+
const receipt = await applyRecordOverlay(plan, { content: guide, ops: guide, policy, actor: "process:calendar-sync", overlays });
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
For each owned field the plan compares the last accepted feed value, the new feed value and the
|
|
198
|
+
document's value: a document that already says the new value is left alone, one that still says
|
|
199
|
+
the old value is written, and anything else is an `OVERLAY_DOC_CONFLICT` with a Signal, so an
|
|
200
|
+
editor's override is never overwritten. Each step carries the version it was planned against.
|
|
201
|
+
`applyRecordOverlay` writes every step through `mutateDocument` with a guard core builds itself and
|
|
202
|
+
runs on the fresh read: an owned-field write reaches documents of the policy's target Kind only,
|
|
203
|
+
may change only owned and derived fields, never the body, and needs the record's `sources`
|
|
204
|
+
identity; a Signal may be created only as a new, unclaimed document of the attention Kind under its
|
|
205
|
+
path, and updated only in a fixed set of fields plus one appended observation line. Signal writes
|
|
206
|
+
are bound to the provider of the policy the caller passes, never to a field of the plan, and an id
|
|
207
|
+
held by another provider's Signal is refused. A Signal's text must be the planner's rendering of
|
|
208
|
+
its own fields and the run (its observation line, links to the plan's feed and to documents, the
|
|
209
|
+
adoption hint): every plan the planner makes passes, and other text is a held `INVALID_INPUT` row,
|
|
210
|
+
so a mismatch is visible and planned again rather than dropped. Nothing of the
|
|
211
|
+
target Kind is created and nothing is deleted. A feed never owns its target's work state: the
|
|
212
|
+
progress storage fields and the target Kind's claim fields are refused like `status`. The
|
|
213
|
+
attention Kind (default `Signal`) must declare a claim owner and state field and the fields
|
|
214
|
+
`change_kind`, `observed_at`, `provider`, `external_id` and `diff_summary`.
|
|
215
|
+
|
|
216
|
+
Site rules are hooks with safe defaults: `textGate` (identity), `interval` (none, so a disappeared
|
|
217
|
+
record is always raised), `correlate`, `sourceProperties` (an upsert of the record's `sources`
|
|
218
|
+
entry in the same write, OKF v0.2 only), `assertCandidate` (site candidate checks after the core
|
|
219
|
+
guards) and `deriveFields` (fields such as `updated_at` written in the same version). Refusals are
|
|
220
|
+
receipt rows with a `REFUSAL_CODES` code; `RETRYABLE` and `HOLD_STORE` say which leave a record to be
|
|
221
|
+
planned again. A value core's write policy refuses (an OKF v0.2 field type, for example) is a held
|
|
222
|
+
`INVALID_INPUT` row, so one bad record never stops the rest of a run. A malformed plan (an unknown
|
|
223
|
+
step, a non-canonical target, written values that are not JSON data with finite numbers, prototype
|
|
224
|
+
keys, non-scalar or identity `sources` properties), actor or bundle edition throws `OverlayRefusal`
|
|
225
|
+
before any write, and so does a plan with owned-field steps whose policy names no declared target
|
|
226
|
+
Kind or whose owned or derived list names a field a feed can never own.
|
|
227
|
+
|
|
228
|
+
`SourceIndex` holds one head read for a whole run. It is bounded to that run: an edited or deleted
|
|
229
|
+
overlay is still caught at write time, but a second document given an identity during the run is
|
|
230
|
+
only refused as ambiguous on the next run.
|
|
231
|
+
|
|
232
|
+
## Bundle health
|
|
233
|
+
|
|
234
|
+
`@superbee/core/bundle-health` computes the health report behind `superbee status` from a core
|
|
235
|
+
`Bundle` on any backend: malformed documents, Kind lint and conformance debt, registry warnings,
|
|
236
|
+
unresolved links, orphans, freshness and invalid timestamps, trust tiers, the two graph lints, the
|
|
237
|
+
View surface, cross-bundle links, the OKF v0.1 upgrade finding and legacy naming. It uses no Node
|
|
238
|
+
globals or builtins, so it runs in Node, a browser or a Worker. The caller presents the report;
|
|
239
|
+
the CLI adds row caps, help text and its home and sync blocks.
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { MemoryBackend } from "@superbee/core/memory-backend";
|
|
243
|
+
import { bundleHealth } from "@superbee/core/bundle-health";
|
|
244
|
+
|
|
245
|
+
const bundle = { root: "memory://guide", backend: new MemoryBackend() };
|
|
246
|
+
const report = await bundleHealth(bundle, { now: new Date() });
|
|
247
|
+
const gate = { malformed: report.malformed.length, kind_warnings: report.kindLint.length, unresolved_links: report.unresolvedLinks.length };
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The report reads only: one Kind registry load, one lenient query, two prefix-scoped blob listings
|
|
251
|
+
and one root-index read, with every finding derived in memory. A document whose frontmatter does
|
|
252
|
+
not parse is a `malformed` row (the root index first), never a thrown error. Top-level keys are
|
|
253
|
+
camelCase; rows keep snake_case keys (`age_ms`, `bundle_id`, `incompatible_values`) and arrive
|
|
254
|
+
whole, in report order, for the caller to cap. Sections whose presence depends on the bundle are
|
|
255
|
+
null when absent: `conformanceDebt` without any declared Kind, `trust` outside a non-empty v0.2
|
|
256
|
+
bundle, `crossBundle` without `docs/dependencies` or any `okf:` link, `okfUpgrade` outside a v0.1
|
|
257
|
+
bundle with a workflow-status collision. `crossLinkTypeViolations` is always an array, because a
|
|
258
|
+
local edge under a qualified declaration needs no dependencies. The stored values in
|
|
259
|
+
`invalidStaleAfter`, `invalidTimestamps` and `invalidLegacyTimestamps` are made JSON-safe;
|
|
260
|
+
`missingExpectedLinks[].status` is the raw stored value.
|
|
261
|
+
|
|
262
|
+
Nothing outside the bundle is read unless the caller binds it. `bindings` is a map of bound copies
|
|
263
|
+
by alias, or a hook core calls exactly once, after every read and with its own parse of
|
|
264
|
+
`docs/dependencies` (a self alias already dropped as `DEP_SELF`, using `selfBundleId` when
|
|
265
|
+
`docs/bundle` declares no id). Whatever the hook throws propagates unchanged. Each binding's
|
|
266
|
+
verdict comes from core's resolver, and `dependencies[].bound` is the binding's `label`.
|
|
267
|
+
|
|
268
|
+
`bundleKindFindings(documents, okfVersion, { actor, producer })` answers a different question:
|
|
269
|
+
which Kind problems a strict host write would refuse, preparing each document as its first edit,
|
|
270
|
+
so a timestamp or actor the write supplies is no finding. The CLI's publish preview runs it; the
|
|
271
|
+
report's `kindLint` stays advisory. Both use core's one validator, `validateAgainstKind`.
|
|
272
|
+
|
|
176
273
|
## Hosted client
|
|
177
274
|
|
|
178
275
|
`@superbee/core/hosted-client` is the headless client of a hosted Superbee's sync routes
|
|
@@ -256,14 +353,20 @@ Each write has one request identity and carries the client's binding, a digest o
|
|
|
256
353
|
client mints once (its `within` clients share it). When an answer is lost (a transport failure or
|
|
257
354
|
a deadline after sending), the client looks the identity up on the host and reports what the host
|
|
258
355
|
recorded. The host's outcome route tells a request it never received ("absent") from one still in
|
|
259
|
-
progress ("pending"),
|
|
260
|
-
|
|
356
|
+
progress ("pending"), and the shared transport keeps the two apart. On either answer `write`
|
|
357
|
+
sends the same identity once more, which the host applies at most once; after "pending", an
|
|
358
|
+
earlier delivery is known to be held. Absence counts as
|
|
261
359
|
evidence only within the retention window the host serves in its capabilities
|
|
262
360
|
(`operationsRetentionMs`, less an hour's margin); past it, the result stays `unknown` and nothing
|
|
263
361
|
is resent. The client measures an intent's age by its own clock against the host's window, so that
|
|
264
362
|
margin holds only while the client's clock is within an hour of the host's. A resend refused before
|
|
265
363
|
it reaches the host's execution (no credential, access withdrawn, a spent quota) leaves the result
|
|
266
|
-
`unknown` too, since the first delivery may still commit
|
|
364
|
+
`unknown` too, since the first delivery may still commit; after a "pending" lookup, so does any
|
|
365
|
+
refusal before execution, a gateway's `400` included. The result's `refusal` (`{ code, message }`)
|
|
366
|
+
names that refusal, so an app can say why the write is waiting (for example, access withdrawn)
|
|
367
|
+
while it stays held; only the call that met the refusal reports it. Absence alone never settles
|
|
368
|
+
such a write: a delayed first delivery is authorized when it arrives, so it can still commit once
|
|
369
|
+
access returns. When the lookups themselves fail, or the caller's `signal` aborts after sending, the
|
|
267
370
|
result is `unknown`.
|
|
268
371
|
|
|
269
372
|
An `unknown` write can be resolved later in two ways:
|
|
@@ -271,7 +374,7 @@ An `unknown` write can be resolved later in two ways:
|
|
|
271
374
|
- `lookupWrite(requestId)` makes one outcome lookup and never sends the write. When the host holds
|
|
272
375
|
no outcome yet (absent or pending), the answer stays `unknown`.
|
|
273
376
|
- `settleWrite(requestId)` looks the identity up and, when the host never recorded it within its
|
|
274
|
-
retention window, sends the same identity once more, as `write` would have.
|
|
377
|
+
retention window or holds it pending, sends the same identity once more, as `write` would have.
|
|
275
378
|
|
|
276
379
|
Both answer `{ status: "unrecorded", requestId }` when the intent store holds no write under that
|
|
277
380
|
identity: it was never recorded there, or it already settled and left the store. Both return
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@superbee/core/bundle-health`: the health report behind `superbee status`, computed from a core
|
|
3
|
+
* `Bundle` on any backend. The caller resolves what lives outside the bundle (bound copies of its
|
|
4
|
+
* dependencies, the clock, a fallback bundle id) and presents the report; the `superbee` CLI is one
|
|
5
|
+
* such caller. It also holds `bundleKindFindings`, the one rule for the Kind problems a strict host
|
|
6
|
+
* write would refuse, which publish preview and hosted bundle creation run. Storage-neutral: no Node
|
|
7
|
+
* globals or builtins.
|
|
8
|
+
*/
|
|
9
|
+
export { bundleHealth } from "./report.js";
|
|
10
|
+
export type { BindDependencies, BundleHealthOptions, BundleHealthReport, CrossBundleHealth, CrossLinkTypeViolationRow, CrossUnresolvedRow, DanglingEntryRow, DependencyProblemRow, DependencyRow, DocTypeRow, FieldValueRow, InvalidRegistrationRow, KindLintRow, LegacyNamingFindings, LinkTypeViolationRow, MalformedRow, MissingExpectedRow, OkfUpgradeFinding, StaleRow, StatusFieldRow, UnresolvedLinkRow, ValueRow, ViewSurfaceHealth, } from "./report.js";
|
|
11
|
+
export { bundleKindFindings, bundleKindRegistry, documentKindFinding, isRegistryConvention } from "./kind-findings.js";
|
|
12
|
+
export type { BundleKindFindings, KindFinding, KindWriteIdentity } from "./kind-findings.js";
|
|
13
|
+
export { LEGACY_PAGE_TYPE_NAME, isLegacyPageDoc } from "./legacy-page.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bundle-health/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,UAAU,EACV,aAAa,EACb,sBAAsB,EACtB,WAAW,EACX,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACvH,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@superbee/core/bundle-health`: the health report behind `superbee status`, computed from a core
|
|
3
|
+
* `Bundle` on any backend. The caller resolves what lives outside the bundle (bound copies of its
|
|
4
|
+
* dependencies, the clock, a fallback bundle id) and presents the report; the `superbee` CLI is one
|
|
5
|
+
* such caller. It also holds `bundleKindFindings`, the one rule for the Kind problems a strict host
|
|
6
|
+
* write would refuse, which publish preview and hosted bundle creation run. Storage-neutral: no Node
|
|
7
|
+
* globals or builtins.
|
|
8
|
+
*/
|
|
9
|
+
export { bundleHealth } from "./report.js";
|
|
10
|
+
export { bundleKindFindings, bundleKindRegistry, documentKindFinding, isRegistryConvention } from "./kind-findings.js";
|
|
11
|
+
export { LEGACY_PAGE_TYPE_NAME, isLegacyPageDoc } from "./legacy-page.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bundle-health/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0B3C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEvH,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type KindRegistry } from "../kinds.js";
|
|
2
|
+
import type { OkfDocument } from "../types.js";
|
|
3
|
+
import type { ValidationWarning } from "../validation.js";
|
|
4
|
+
/**
|
|
5
|
+
* Who the checked first edit is attributed to. `producer` defaults to `actor`, as a write's does.
|
|
6
|
+
* On OKF v0.2 a `person:` actor cannot be a producer, so a v0.2 call with a `person:` actor must
|
|
7
|
+
* pass a `process:` (or `<producer>/<version>`) producer, or the check throws `OkfActorError`.
|
|
8
|
+
*/
|
|
9
|
+
export interface KindWriteIdentity {
|
|
10
|
+
actor: string;
|
|
11
|
+
producer?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface KindFinding {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly governs: string;
|
|
16
|
+
readonly violations: readonly ValidationWarning[];
|
|
17
|
+
/** Core's own sentence: `'<id>' does not satisfy the '<Kind>' kind: …`. */
|
|
18
|
+
readonly message: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BundleKindFindings {
|
|
21
|
+
/** Registry warnings: every strict write to the bundle refuses while any is present. */
|
|
22
|
+
readonly conventions: readonly ValidationWarning[];
|
|
23
|
+
/** Documents whose first strict edit would refuse for their Kind. */
|
|
24
|
+
readonly documents: readonly KindFinding[];
|
|
25
|
+
}
|
|
26
|
+
/** Whether `loadKinds` builds the Kind registry from this document: a `Convention` under `conventions/`. */
|
|
27
|
+
export declare function isRegistryConvention(doc: OkfDocument): boolean;
|
|
28
|
+
/** The Kind registry a bundle holding `documents` loads, built with `loadKinds`' own filter and builder. */
|
|
29
|
+
export declare function bundleKindRegistry(documents: readonly OkfDocument[], okfVersion: "0.1" | "0.2"): KindRegistry;
|
|
30
|
+
/**
|
|
31
|
+
* The Kind problem a strict write would refuse the first edit of one stored document over, or
|
|
32
|
+
* null. The document is prepared as its first edit: the stored document as the existing one and a
|
|
33
|
+
* body one line longer as the candidate, so unchanged values keep the leniency an edit gives them.
|
|
34
|
+
* An edit refused for another reason (a malformed standard field it changes) is not a Kind problem.
|
|
35
|
+
*/
|
|
36
|
+
export declare function documentKindFinding(doc: OkfDocument, registry: KindRegistry, okfVersion: "0.1" | "0.2", write: KindWriteIdentity): KindFinding | null;
|
|
37
|
+
/**
|
|
38
|
+
* The Kind problems in `documents` (as stored) that strict writes would refuse over: the warnings
|
|
39
|
+
* of the registry their conventions build, and each document's own finding against it, in input
|
|
40
|
+
* order. Each document is checked on its own, so a bundle checked in parts against the same
|
|
41
|
+
* registry finds exactly this.
|
|
42
|
+
*/
|
|
43
|
+
export declare function bundleKindFindings(documents: readonly OkfDocument[], okfVersion: "0.1" | "0.2", write: KindWriteIdentity): BundleKindFindings;
|
|
44
|
+
//# sourceMappingURL=kind-findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind-findings.d.ts","sourceRoot":"","sources":["../../src/bundle-health/kind-findings.ts"],"names":[],"mappings":"AAaA,OAAO,EAA0D,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAExG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAClD,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,SAAS,WAAW,EAAE,CAAC;CAC5C;AAED,4GAA4G;AAC5G,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,WAAW,EAAE,EAAE,UAAU,EAAE,KAAK,GAAG,KAAK,GAAG,YAAY,CAE7G;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,KAAK,GAAG,KAAK,EACzB,KAAK,EAAE,iBAAiB,GACvB,WAAW,GAAG,IAAI,CAuBpB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,UAAU,EAAE,KAAK,GAAG,KAAK,EACzB,KAAK,EAAE,iBAAiB,GACvB,kBAAkB,CAQpB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Kind problems a strict host write would refuse a bundle over, before the bundle exists. A
|
|
3
|
+
* strict write refuses while the Kind registry has any warning, and it prepares and validates its
|
|
4
|
+
* candidate with `prepareDocumentMutationCandidate`, which supplies the timestamp, actor and v0.2
|
|
5
|
+
* metadata a write adds. This is the one rule for "what would the host refuse": the CLI's publish
|
|
6
|
+
* preview runs it, and a host's bundle creation runs it with its own producer.
|
|
7
|
+
*
|
|
8
|
+
* It asks a different question from the health report's Kind lint (`kindLint`,
|
|
9
|
+
* `conformanceDebt`), which reports what is wrong with each stored document as advice. Both run
|
|
10
|
+
* core's one validator, `validateAgainstKind`.
|
|
11
|
+
*/
|
|
12
|
+
import { KindConformanceError, prepareDocumentMutationCandidate } from "../document-mutation.js";
|
|
13
|
+
import { InvalidInputError, OkfActorError } from "../errors.js";
|
|
14
|
+
import { buildKindRegistry, CONVENTION_TYPE, CONVENTIONS_PREFIX } from "../kinds.js";
|
|
15
|
+
import { matchesFilter } from "../query-filter.js";
|
|
16
|
+
/** Whether `loadKinds` builds the Kind registry from this document: a `Convention` under `conventions/`. */
|
|
17
|
+
export function isRegistryConvention(doc) {
|
|
18
|
+
return matchesFilter(doc, { prefix: CONVENTIONS_PREFIX, type: CONVENTION_TYPE });
|
|
19
|
+
}
|
|
20
|
+
/** The Kind registry a bundle holding `documents` loads, built with `loadKinds`' own filter and builder. */
|
|
21
|
+
export function bundleKindRegistry(documents, okfVersion) {
|
|
22
|
+
return buildKindRegistry(documents.filter(isRegistryConvention), [], { okfVersion });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The Kind problem a strict write would refuse the first edit of one stored document over, or
|
|
26
|
+
* null. The document is prepared as its first edit: the stored document as the existing one and a
|
|
27
|
+
* body one line longer as the candidate, so unchanged values keep the leniency an edit gives them.
|
|
28
|
+
* An edit refused for another reason (a malformed standard field it changes) is not a Kind problem.
|
|
29
|
+
*/
|
|
30
|
+
export function documentKindFinding(doc, registry, okfVersion, write) {
|
|
31
|
+
try {
|
|
32
|
+
prepareDocumentMutationCandidate(doc, { frontmatter: doc.frontmatter, body: `${doc.body ?? ""}\n` }, {
|
|
33
|
+
strict: true,
|
|
34
|
+
persistActor: true,
|
|
35
|
+
...(write.producer === undefined ? {} : { producer: write.producer }),
|
|
36
|
+
id: doc.id,
|
|
37
|
+
registry,
|
|
38
|
+
okfVersion,
|
|
39
|
+
actor: write.actor,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof KindConformanceError) {
|
|
44
|
+
return { id: doc.id, governs: error.governs, violations: error.violations, message: error.message };
|
|
45
|
+
}
|
|
46
|
+
if (error instanceof InvalidInputError && !(error instanceof OkfActorError))
|
|
47
|
+
return null;
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The Kind problems in `documents` (as stored) that strict writes would refuse over: the warnings
|
|
54
|
+
* of the registry their conventions build, and each document's own finding against it, in input
|
|
55
|
+
* order. Each document is checked on its own, so a bundle checked in parts against the same
|
|
56
|
+
* registry finds exactly this.
|
|
57
|
+
*/
|
|
58
|
+
export function bundleKindFindings(documents, okfVersion, write) {
|
|
59
|
+
const registry = bundleKindRegistry(documents, okfVersion);
|
|
60
|
+
const found = [];
|
|
61
|
+
for (const doc of documents) {
|
|
62
|
+
const finding = documentKindFinding(doc, registry, okfVersion, write);
|
|
63
|
+
if (finding)
|
|
64
|
+
found.push(finding);
|
|
65
|
+
}
|
|
66
|
+
return { conventions: registry.warnings, documents: found };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=kind-findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind-findings.js","sourceRoot":"","sources":["../../src/bundle-health/kind-findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,oBAAoB,EAAE,gCAAgC,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAqB,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA6BnD,4GAA4G;AAC5G,MAAM,UAAU,oBAAoB,CAAC,GAAgB;IACnD,OAAO,aAAa,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,kBAAkB,CAAC,SAAiC,EAAE,UAAyB;IAC7F,OAAO,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;AACvF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAgB,EAChB,QAAsB,EACtB,UAAyB,EACzB,KAAwB;IAExB,IAAI,CAAC;QACH,gCAAgC,CAC9B,GAAG,EACH,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,EAC7D;YACE,MAAM,EAAE,IAAI;YACZ,YAAY,EAAE,IAAI;YAClB,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YACrE,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,QAAQ;YACR,UAAU;YACV,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,oBAAoB,EAAE,CAAC;YAC1C,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QACtG,CAAC;QACD,IAAI,KAAK,YAAY,iBAAiB,IAAI,CAAC,CAAC,KAAK,YAAY,aAAa,CAAC;YAAE,OAAO,IAAI,CAAC;QACzF,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAiC,EACjC,UAAyB,EACzB,KAAwB;IAExB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACtE,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The retired `Page` kind name and `bridge` access-field spelling, for the `legacyNaming` section of
|
|
3
|
+
* the bundle health report. The runtime no longer recognizes either name: Page-typed documents do
|
|
4
|
+
* not register, and a bridge-only document resolves to `access: none`. Legacy folder locations
|
|
5
|
+
* remain valid.
|
|
6
|
+
*
|
|
7
|
+
* These literals cannot come from the live grammar in `page.ts`: diagnostics must recognize stock
|
|
8
|
+
* the runtime deliberately rejects, and a retired name must never track a live export. This module
|
|
9
|
+
* imports nothing; `legacy-constants-tripwire.test.ts` in the CLI pins its literals equal to
|
|
10
|
+
* core's legacy prefixes and to the recipe lifecycle's retired name by assertion.
|
|
11
|
+
*/
|
|
12
|
+
/** The retired legacy kind name, frozen as a historical fact. */
|
|
13
|
+
export declare const LEGACY_PAGE_TYPE_NAME = "Page";
|
|
14
|
+
/**
|
|
15
|
+
* True when this frontmatter declares the legacy kind name: `type` exactly `"Page"`, the same exact
|
|
16
|
+
* match core's grammar applies (`isPageTypeName`). No trimming: a value that reaches a consumer with
|
|
17
|
+
* surrounding whitespace was deliberately quoted and was never a registration.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isLegacyPageDoc(frontmatter: Record<string, unknown>): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* True when a View-kind document (current `View` or legacy `Page` spelling) carries its own legacy
|
|
22
|
+
* `bridge` field. `bridge` is only the View kind's legacy capability spelling, so a document of any
|
|
23
|
+
* other type carrying it is ordinary data and is never flagged.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasLegacyBridgeField(frontmatter: Record<string, unknown>): boolean;
|
|
26
|
+
/** True when this frontmatter is a Convention governing exactly the retired `Page` name. */
|
|
27
|
+
export declare function isLegacyPageConvention(frontmatter: Record<string, unknown>): boolean;
|
|
28
|
+
/** The legacy id prefixes, frozen as historical facts (they mirror the legacy locations core still accepts). */
|
|
29
|
+
export declare const LEGACY_PAGE_REGISTRY_PREFIX = "pages-registry/";
|
|
30
|
+
export declare const LEGACY_PAGE_BLOB_PREFIX = "pages/";
|
|
31
|
+
/**
|
|
32
|
+
* Store-aware classifiers: a registry document is legacy only under `pages-registry/` in the
|
|
33
|
+
* document store, an entry only under `pages/` in the blob store. A concept document at `pages/x`
|
|
34
|
+
* is not a legacy item. A `true` here is reported as information, never acted on.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isLegacyRegistryDocId(id: string): boolean;
|
|
37
|
+
/** See {@link isLegacyRegistryDocId}: the blob-store half. */
|
|
38
|
+
export declare function isLegacyEntryBlobKey(key: string): boolean;
|
|
39
|
+
//# sourceMappingURL=legacy-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-page.d.ts","sourceRoot":"","sources":["../../src/bundle-health/legacy-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iEAAiE;AACjE,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAGlF;AAED,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEpF;AAED,gHAAgH;AAChH,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAC7D,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEzD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The retired `Page` kind name and `bridge` access-field spelling, for the `legacyNaming` section of
|
|
3
|
+
* the bundle health report. The runtime no longer recognizes either name: Page-typed documents do
|
|
4
|
+
* not register, and a bridge-only document resolves to `access: none`. Legacy folder locations
|
|
5
|
+
* remain valid.
|
|
6
|
+
*
|
|
7
|
+
* These literals cannot come from the live grammar in `page.ts`: diagnostics must recognize stock
|
|
8
|
+
* the runtime deliberately rejects, and a retired name must never track a live export. This module
|
|
9
|
+
* imports nothing; `legacy-constants-tripwire.test.ts` in the CLI pins its literals equal to
|
|
10
|
+
* core's legacy prefixes and to the recipe lifecycle's retired name by assertion.
|
|
11
|
+
*/
|
|
12
|
+
/** The retired legacy kind name, frozen as a historical fact. */
|
|
13
|
+
export const LEGACY_PAGE_TYPE_NAME = "Page";
|
|
14
|
+
/**
|
|
15
|
+
* True when this frontmatter declares the legacy kind name: `type` exactly `"Page"`, the same exact
|
|
16
|
+
* match core's grammar applies (`isPageTypeName`). No trimming: a value that reaches a consumer with
|
|
17
|
+
* surrounding whitespace was deliberately quoted and was never a registration.
|
|
18
|
+
*/
|
|
19
|
+
export function isLegacyPageDoc(frontmatter) {
|
|
20
|
+
return frontmatter["type"] === LEGACY_PAGE_TYPE_NAME;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* True when a View-kind document (current `View` or legacy `Page` spelling) carries its own legacy
|
|
24
|
+
* `bridge` field. `bridge` is only the View kind's legacy capability spelling, so a document of any
|
|
25
|
+
* other type carrying it is ordinary data and is never flagged.
|
|
26
|
+
*/
|
|
27
|
+
export function hasLegacyBridgeField(frontmatter) {
|
|
28
|
+
const viewKind = frontmatter["type"] === LEGACY_PAGE_TYPE_NAME || frontmatter["type"] === "View";
|
|
29
|
+
return viewKind && Object.hasOwn(frontmatter, "bridge");
|
|
30
|
+
}
|
|
31
|
+
/** True when this frontmatter is a Convention governing exactly the retired `Page` name. */
|
|
32
|
+
export function isLegacyPageConvention(frontmatter) {
|
|
33
|
+
return frontmatter["type"] === "Convention" && frontmatter["governs"] === LEGACY_PAGE_TYPE_NAME;
|
|
34
|
+
}
|
|
35
|
+
/** The legacy id prefixes, frozen as historical facts (they mirror the legacy locations core still accepts). */
|
|
36
|
+
export const LEGACY_PAGE_REGISTRY_PREFIX = "pages-registry/";
|
|
37
|
+
export const LEGACY_PAGE_BLOB_PREFIX = "pages/";
|
|
38
|
+
/**
|
|
39
|
+
* Store-aware classifiers: a registry document is legacy only under `pages-registry/` in the
|
|
40
|
+
* document store, an entry only under `pages/` in the blob store. A concept document at `pages/x`
|
|
41
|
+
* is not a legacy item. A `true` here is reported as information, never acted on.
|
|
42
|
+
*/
|
|
43
|
+
export function isLegacyRegistryDocId(id) {
|
|
44
|
+
return id.startsWith(LEGACY_PAGE_REGISTRY_PREFIX);
|
|
45
|
+
}
|
|
46
|
+
/** See {@link isLegacyRegistryDocId}: the blob-store half. */
|
|
47
|
+
export function isLegacyEntryBlobKey(key) {
|
|
48
|
+
return key.startsWith(LEGACY_PAGE_BLOB_PREFIX);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=legacy-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-page.js","sourceRoot":"","sources":["../../src/bundle-health/legacy-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,WAAoC;IAClE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,qBAAqB,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAoC;IACvE,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,qBAAqB,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC;IACjG,OAAO,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAC1D,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,sBAAsB,CAAC,WAAoC;IACzE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,YAAY,IAAI,WAAW,CAAC,SAAS,CAAC,KAAK,qBAAqB,CAAC;AAClG,CAAC;AAED,gHAAgH;AAChH,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAC7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,OAAO,EAAE,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;AACpD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,GAAG,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { type BundleBinding, type UnresolvedReason } from "../cross-bundle.js";
|
|
2
|
+
import { type ParsedDependencies } from "../dependencies.js";
|
|
3
|
+
import type { Bundle } from "../types.js";
|
|
4
|
+
import type { ValidationWarning } from "../validation.js";
|
|
5
|
+
import { type TrustTierCounts } from "../verification.js";
|
|
6
|
+
/**
|
|
7
|
+
* Binds declared dependencies: called once, after every read has completed and `docs/dependencies`
|
|
8
|
+
* has been parsed, with that parse. Returns the bound copies by alias.
|
|
9
|
+
*/
|
|
10
|
+
export type BindDependencies = (declared: ParsedDependencies) => Promise<ReadonlyMap<string, BundleBinding>>;
|
|
11
|
+
export interface BundleHealthOptions {
|
|
12
|
+
/** The instant freshness is judged at. Default: the current time, taken after the reads. */
|
|
13
|
+
now?: Date;
|
|
14
|
+
/**
|
|
15
|
+
* Bound copies of declared dependencies, by alias: a map, or a hook called exactly once, after
|
|
16
|
+
* every read has completed and `docs/dependencies` has been parsed, with that parse. Default: none,
|
|
17
|
+
* so nothing outside the bundle is read. Whatever the hook throws propagates unchanged.
|
|
18
|
+
*/
|
|
19
|
+
bindings?: ReadonlyMap<string, BundleBinding> | BindDependencies;
|
|
20
|
+
/** This bundle's id when `docs/bundle` declares none. */
|
|
21
|
+
selfBundleId?: string;
|
|
22
|
+
}
|
|
23
|
+
/** A document whose frontmatter does not parse; the root index comes first when it is one. */
|
|
24
|
+
export interface MalformedRow {
|
|
25
|
+
id: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}
|
|
28
|
+
/** One Kind violation of one document. */
|
|
29
|
+
export interface KindLintRow {
|
|
30
|
+
id: string;
|
|
31
|
+
field: string;
|
|
32
|
+
code: string;
|
|
33
|
+
}
|
|
34
|
+
/** A document and its `type` ("" when absent or not a string). */
|
|
35
|
+
export interface DocTypeRow {
|
|
36
|
+
id: string;
|
|
37
|
+
type: string;
|
|
38
|
+
}
|
|
39
|
+
export interface UnresolvedLinkRow {
|
|
40
|
+
from: string;
|
|
41
|
+
href: string;
|
|
42
|
+
}
|
|
43
|
+
/** A resolved local edge whose text is a declared link type its source or target does not conform to. */
|
|
44
|
+
export interface LinkTypeViolationRow {
|
|
45
|
+
from: string;
|
|
46
|
+
to: string;
|
|
47
|
+
text: string;
|
|
48
|
+
expected: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A qualified link whose text is a declared type it does not conform to, or a local link under a
|
|
52
|
+
* qualified declaration (`links: {pours: "beers:Beer"}`).
|
|
53
|
+
*/
|
|
54
|
+
export interface CrossLinkTypeViolationRow {
|
|
55
|
+
from: string;
|
|
56
|
+
href: string;
|
|
57
|
+
text: string;
|
|
58
|
+
expected: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A Kind instance lacking a declared inbound expectation. `status` is present when the Kind declares
|
|
62
|
+
* a `status` field, and is the raw stored value (any YAML value, or undefined when unset).
|
|
63
|
+
*/
|
|
64
|
+
export interface MissingExpectedRow {
|
|
65
|
+
id: string;
|
|
66
|
+
status?: unknown;
|
|
67
|
+
missing: string[];
|
|
68
|
+
}
|
|
69
|
+
/** A stale document: past its `stale_after` instant (a string by construction), or older than its Kind's horizon. */
|
|
70
|
+
export interface StaleRow {
|
|
71
|
+
id: string;
|
|
72
|
+
age_ms?: number;
|
|
73
|
+
horizon_ms?: number;
|
|
74
|
+
stale_after?: string;
|
|
75
|
+
}
|
|
76
|
+
/** An unreadable `stale_after`; `value` is the stored value made JSON-safe. */
|
|
77
|
+
export interface ValueRow {
|
|
78
|
+
id: string;
|
|
79
|
+
type: string;
|
|
80
|
+
value: unknown;
|
|
81
|
+
}
|
|
82
|
+
/** An invalid timestamp field occurrence; `value` is the stored value made JSON-safe. */
|
|
83
|
+
export interface FieldValueRow {
|
|
84
|
+
id: string;
|
|
85
|
+
type: string;
|
|
86
|
+
field: string;
|
|
87
|
+
value: unknown;
|
|
88
|
+
}
|
|
89
|
+
export interface DanglingEntryRow {
|
|
90
|
+
id: string;
|
|
91
|
+
entry: string;
|
|
92
|
+
}
|
|
93
|
+
/** A View-typed document failing the registration grammar; `problem` names the failing legs, joined by `+`. */
|
|
94
|
+
export interface InvalidRegistrationRow {
|
|
95
|
+
id: string;
|
|
96
|
+
problem: string;
|
|
97
|
+
}
|
|
98
|
+
export interface ViewSurfaceHealth {
|
|
99
|
+
/** View-typed documents (legacy locations included). */
|
|
100
|
+
typed: number;
|
|
101
|
+
danglingEntries: DanglingEntryRow[];
|
|
102
|
+
invalidRegistrations: InvalidRegistrationRow[];
|
|
103
|
+
}
|
|
104
|
+
export interface CrossUnresolvedRow {
|
|
105
|
+
from: string;
|
|
106
|
+
href: string;
|
|
107
|
+
reason: UnresolvedReason;
|
|
108
|
+
detail: string;
|
|
109
|
+
}
|
|
110
|
+
export interface DependencyRow {
|
|
111
|
+
alias: string;
|
|
112
|
+
bundle_id: string;
|
|
113
|
+
/** `unbound` without a binding; otherwise the bound copy's verdict from core's resolver. */
|
|
114
|
+
state: "unbound" | "ok" | UnresolvedReason;
|
|
115
|
+
/** The binding's label, or null when the alias is unbound. */
|
|
116
|
+
bound: string | null;
|
|
117
|
+
pin: string | null;
|
|
118
|
+
}
|
|
119
|
+
/** A `docs/dependencies` defect (a `DEP_*` code). */
|
|
120
|
+
export interface DependencyProblemRow {
|
|
121
|
+
code: string;
|
|
122
|
+
alias: string | null;
|
|
123
|
+
detail: string;
|
|
124
|
+
}
|
|
125
|
+
export interface CrossBundleHealth {
|
|
126
|
+
/** Every qualified (`okf:`) link, malformed ones included. */
|
|
127
|
+
links: number;
|
|
128
|
+
/** Qualified links whose declared alias has no binding. */
|
|
129
|
+
unchecked: number;
|
|
130
|
+
unresolved: CrossUnresolvedRow[];
|
|
131
|
+
dependencies: DependencyRow[];
|
|
132
|
+
problems: DependencyProblemRow[];
|
|
133
|
+
}
|
|
134
|
+
/** One Kind declaring a workflow `status` that collides with the OKF v0.2 lifecycle vocabulary. */
|
|
135
|
+
export interface StatusFieldRow {
|
|
136
|
+
kind: string;
|
|
137
|
+
convention: string;
|
|
138
|
+
declaration: "unbounded" | "enumerated";
|
|
139
|
+
incompatible_values: string[];
|
|
140
|
+
observed_incompatible_values: string[];
|
|
141
|
+
affected_documents: number;
|
|
142
|
+
}
|
|
143
|
+
export interface OkfUpgradeFinding {
|
|
144
|
+
statusFieldRows: StatusFieldRow[];
|
|
145
|
+
affectedDocuments: number;
|
|
146
|
+
}
|
|
147
|
+
export interface LegacyNamingFindings {
|
|
148
|
+
pageTyped: {
|
|
149
|
+
id: string;
|
|
150
|
+
}[];
|
|
151
|
+
bridgeField: {
|
|
152
|
+
id: string;
|
|
153
|
+
}[];
|
|
154
|
+
pageConvention: {
|
|
155
|
+
id: string;
|
|
156
|
+
}[];
|
|
157
|
+
legacyPrefix: {
|
|
158
|
+
id: string;
|
|
159
|
+
store: "doc" | "blob";
|
|
160
|
+
}[];
|
|
161
|
+
}
|
|
162
|
+
export interface BundleHealthReport {
|
|
163
|
+
/** The root index's declared edition; undefined when absent or unreadable. */
|
|
164
|
+
okfVersion: string | undefined;
|
|
165
|
+
docs: number;
|
|
166
|
+
kinds: number;
|
|
167
|
+
malformed: MalformedRow[];
|
|
168
|
+
kindLint: KindLintRow[];
|
|
169
|
+
/** One row per governed document with a frontmatter-level violation; null when the bundle declares no Kind. */
|
|
170
|
+
conformanceDebt: DocTypeRow[] | null;
|
|
171
|
+
registryWarnings: ValidationWarning[];
|
|
172
|
+
unresolvedLinks: UnresolvedLinkRow[];
|
|
173
|
+
orphans: DocTypeRow[];
|
|
174
|
+
linkTypeViolations: LinkTypeViolationRow[];
|
|
175
|
+
/** Independent of `crossBundle`: a local edge under a qualified declaration needs no dependencies. */
|
|
176
|
+
crossLinkTypeViolations: CrossLinkTypeViolationRow[];
|
|
177
|
+
/** In triage order. */
|
|
178
|
+
missingExpectedLinks: MissingExpectedRow[];
|
|
179
|
+
/** Terminal instances skipped before the inbound-expectation lint evaluated them. */
|
|
180
|
+
terminalSkipped: number;
|
|
181
|
+
stale: StaleRow[];
|
|
182
|
+
noTimestamp: DocTypeRow[];
|
|
183
|
+
invalidStaleAfter: ValueRow[];
|
|
184
|
+
invalidTimestamps: FieldValueRow[];
|
|
185
|
+
invalidLegacyTimestamps: FieldValueRow[];
|
|
186
|
+
/** Null on v0.1, an undeclared edition, or an empty bundle. */
|
|
187
|
+
trust: TrustTierCounts | null;
|
|
188
|
+
views: ViewSurfaceHealth;
|
|
189
|
+
/** Null without `docs/dependencies` and without any `okf:` link. */
|
|
190
|
+
crossBundle: CrossBundleHealth | null;
|
|
191
|
+
/** Present only on a v0.1 bundle with a workflow-status collision. */
|
|
192
|
+
okfUpgrade: OkfUpgradeFinding | null;
|
|
193
|
+
legacyNaming: LegacyNamingFindings;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Compute the health report for `bundle`. Read-only: it reads through the bundle's backend and
|
|
197
|
+
* never writes. It throws only what it propagates: `InvalidInputError` for a backend-less bundle in
|
|
198
|
+
* a runtime with no default, backend errors other than `MalformedDocumentError` (a finding), and
|
|
199
|
+
* whatever the `bindings` hook throws.
|
|
200
|
+
*/
|
|
201
|
+
export declare function bundleHealth(bundle: Bundle, options?: BundleHealthOptions): Promise<BundleHealthReport>;
|
|
202
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/bundle-health/report.ts"],"names":[],"mappings":"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"}
|