@intentius/chant-lexicon-helm 0.46.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/archive-render.d.ts +94 -0
- package/dist/archive-render.d.ts.map +1 -0
- package/dist/commands.d.ts +54 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/config.d.ts +135 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/deep-observe-hooks.d.ts +2 -0
- package/dist/deep-observe-hooks.d.ts.map +1 -0
- package/dist/deep-observe.d.ts +54 -0
- package/dist/deep-observe.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +17 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +5 -3
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/whm503.d.ts +34 -0
- package/dist/lint/post-synth/whm503.d.ts.map +1 -0
- package/dist/lint/post-synth/whm504.d.ts +20 -0
- package/dist/lint/post-synth/whm504.d.ts.map +1 -0
- package/dist/manifest.json +25 -13
- package/dist/okf/index.md +2 -0
- package/dist/okf/rules/WHM503.md +15 -0
- package/dist/okf/rules/WHM504.md +11 -0
- package/dist/okf/types/Values.md +1 -0
- package/dist/op/activities/cluster-probe.d.ts +44 -0
- package/dist/op/activities/cluster-probe.d.ts.map +1 -0
- package/dist/op/activities/helm.d.ts +179 -5
- package/dist/op/activities/helm.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +4 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/builders.d.ts +47 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/dist/pinnability/actions.d.ts +76 -0
- package/dist/pinnability/actions.d.ts.map +1 -0
- package/dist/pinnability/classify.d.ts +129 -0
- package/dist/pinnability/classify.d.ts.map +1 -0
- package/dist/pinnability/conditions.d.ts +109 -0
- package/dist/pinnability/conditions.d.ts.map +1 -0
- package/dist/pinnability/index.d.ts +17 -0
- package/dist/pinnability/index.d.ts.map +1 -0
- package/dist/pinnability/localize.d.ts +124 -0
- package/dist/pinnability/localize.d.ts.map +1 -0
- package/dist/pinnability/render-stream.d.ts +27 -0
- package/dist/pinnability/render-stream.d.ts.map +1 -0
- package/dist/pinnability/values.d.ts +69 -0
- package/dist/pinnability/values.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/release-observe.d.ts +109 -0
- package/dist/release-observe.d.ts.map +1 -0
- package/dist/render-diff.d.ts +192 -0
- package/dist/render-diff.d.ts.map +1 -0
- package/dist/render-digest.d.ts +135 -0
- package/dist/render-digest.d.ts.map +1 -0
- package/dist/render-store.d.ts +310 -0
- package/dist/render-store.d.ts.map +1 -0
- package/dist/render-wrapper.d.ts +140 -0
- package/dist/render-wrapper.d.ts.map +1 -0
- package/dist/render.d.ts +81 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/rules/whm503.ts +101 -0
- package/dist/rules/whm504.ts +52 -0
- package/dist/skills/chant-helm.md +7 -0
- package/dist/values-probe.d.ts +177 -0
- package/dist/values-probe.d.ts.map +1 -0
- package/dist/wrapper-chart.d.ts +61 -0
- package/dist/wrapper-chart.d.ts.map +1 -0
- package/package.json +10 -4
- package/src/archive-render.test.ts +201 -0
- package/src/archive-render.ts +119 -0
- package/src/commands.test.ts +487 -0
- package/src/commands.ts +445 -0
- package/src/config.test.ts +130 -0
- package/src/config.ts +220 -0
- package/src/deep-observe-hooks.ts +20 -0
- package/src/deep-observe.test.ts +165 -0
- package/src/deep-observe.ts +121 -0
- package/src/describe-resources.test.ts +255 -0
- package/src/describe-resources.ts +198 -0
- package/src/index.ts +106 -2
- package/src/lifecycle-integration.test.ts +289 -0
- package/src/lint/audit-catalog.ts +2 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/whm503.test.ts +134 -0
- package/src/lint/post-synth/whm503.ts +101 -0
- package/src/lint/post-synth/whm504.test.ts +105 -0
- package/src/lint/post-synth/whm504.ts +52 -0
- package/src/op/activities/cluster-probe.test.ts +66 -0
- package/src/op/activities/cluster-probe.ts +148 -0
- package/src/op/activities/helm.test.ts +824 -0
- package/src/op/activities/helm.ts +628 -5
- package/src/op/activities/index.ts +17 -2
- package/src/op/builders.test.ts +70 -0
- package/src/op/builders.ts +66 -0
- package/src/pinnability/actions.ts +263 -0
- package/src/pinnability/classify.ts +579 -0
- package/src/pinnability/conditions.ts +0 -0
- package/src/pinnability/index.ts +77 -0
- package/src/pinnability/localize.test.ts +234 -0
- package/src/pinnability/localize.ts +644 -0
- package/src/pinnability/pinnability.test.ts +560 -0
- package/src/pinnability/render-stream.ts +59 -0
- package/src/pinnability/values.ts +205 -0
- package/src/plugin.test.ts +3 -1
- package/src/plugin.ts +97 -12
- package/src/release-observe.ts +392 -0
- package/src/render-diff.test.ts +366 -0
- package/src/render-diff.ts +407 -0
- package/src/render-digest.test.ts +186 -0
- package/src/render-digest.ts +207 -0
- package/src/render-store.test.ts +412 -0
- package/src/render-store.ts +621 -0
- package/src/render-wrapper.test.ts +259 -0
- package/src/render-wrapper.ts +274 -0
- package/src/render.test.ts +383 -4
- package/src/render.ts +319 -8
- package/src/skills/chant-helm.md +7 -0
- package/src/values-probe.test.ts +400 -0
- package/src/values-probe.ts +627 -0
- package/src/wrapper-chart.test.ts +110 -0
- package/src/wrapper-chart.ts +124 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render diffing (#1249 offline, #1250 live — epic #1228 Phase 6), the two
|
|
3
|
+
* halves of `chant helm diff` (./commands.ts).
|
|
4
|
+
*
|
|
5
|
+
* `diffRenders` (#1249) is the offline half: given two content digests
|
|
6
|
+
* already in the render store (render-store.ts), report what changed
|
|
7
|
+
* between them — no cluster, no credentials, no live read. This is the
|
|
8
|
+
* pre-flight question a pin, a chart bump, or a values change all raise:
|
|
9
|
+
* "what will this touch?"
|
|
10
|
+
*
|
|
11
|
+
* Pairing is document-level, keyed on `(kind, namespace, name)` — the same
|
|
12
|
+
* identity `RenderManifest.documents` already indexes (render-store.ts).
|
|
13
|
+
* That index exists precisely so two renders can be matched without
|
|
14
|
+
* reparsing a whole stream: a document present on both sides with the same
|
|
15
|
+
* per-document digest is unchanged and costs nothing further; one whose
|
|
16
|
+
* digest differs is parsed on both sides and diffed field by field.
|
|
17
|
+
*
|
|
18
|
+
* Field-level diffing reuses core's `flattenDeepProperties` /
|
|
19
|
+
* `deepValueEqual` (packages/core/src/deep-observation.ts) — the same
|
|
20
|
+
* path-flattening core's own live-drift diff (lifecycle/deep-diff.ts) is
|
|
21
|
+
* built on. This module does not reuse `diffDeep` itself for the offline
|
|
22
|
+
* path: that function's shape is declared/live/baseline/fieldOwners,
|
|
23
|
+
* tailored to a source tree vs a cluster read. A stored render has neither
|
|
24
|
+
* a baseline nor a field owner, and both sides here are equally "declared"
|
|
25
|
+
* — reusing the flatten/compare primitives without the three-way apparatus
|
|
26
|
+
* is the right cut for render-to-render.
|
|
27
|
+
*
|
|
28
|
+
* Duplicate documents (an aliased dependency emitting the same CRD twice,
|
|
29
|
+
* render-digest.ts's canonicalization note) are matched positionally within
|
|
30
|
+
* their `(kind, namespace, name)` group: first occurrence to first, second
|
|
31
|
+
* to second. A group with more entries on one side reports the surplus as
|
|
32
|
+
* added or removed rather than guessing which duplicate corresponds to
|
|
33
|
+
* which.
|
|
34
|
+
*
|
|
35
|
+
* A document neither side's manifest could index (unparseable, or missing
|
|
36
|
+
* `kind`/`metadata.name` — render-store.ts's `indexRenderDocuments`) cannot
|
|
37
|
+
* be paired by identity. It is never silently dropped: `unindexed` counts
|
|
38
|
+
* it on whichever side(s) it appears, so a diff over two renders that both
|
|
39
|
+
* carry unindexable documents does not quietly under-report.
|
|
40
|
+
*
|
|
41
|
+
* `diffRenderLive` (#1250) is the online complement: given a single
|
|
42
|
+
* `contentDigest` resolved from the render store, read the live property
|
|
43
|
+
* tree for every document the render recorded — by identity
|
|
44
|
+
* (kind/namespace/name), not by helm release — and diff each one against
|
|
45
|
+
* the render's own stored bytes with `lifecycle/deep-diff.ts`. This *does*
|
|
46
|
+
* reuse `diffDeep`'s three-way apparatus (via `diffDeepObservation`): the
|
|
47
|
+
* declared side is the render's stored documents, the live side is a
|
|
48
|
+
* cluster read, which is exactly that function's shape.
|
|
49
|
+
*
|
|
50
|
+
* The declared side for the live path is the render's stored documents,
|
|
51
|
+
* never a fresh `helm template` run and never a chant TS build. A digest
|
|
52
|
+
* not in the store — an unpinned render was never persisted
|
|
53
|
+
* (`render-store.ts`'s `persistHelmRender` refuses that) — has nothing to
|
|
54
|
+
* diff against and comes back `found: false`, never a false "no drift" over
|
|
55
|
+
* documents nobody has (epic AC: unpinned releases handled without false
|
|
56
|
+
* drift).
|
|
57
|
+
*
|
|
58
|
+
* The live side reuses the exact seam `observeResourcesDeepHelm` (#1247)
|
|
59
|
+
* uses — the k8s lexicon's typed client and normalization hooks — so a
|
|
60
|
+
* document this reads and one a release's `describeResources` reads compare
|
|
61
|
+
* under the same rules (secret masking, managed-fields ownership, pruning).
|
|
62
|
+
* Hook resources need no special handling here the way the release-scoped
|
|
63
|
+
* read needs a second `helm get hooks` channel: `helm template` (what
|
|
64
|
+
* produced the stored render) already includes hook manifests as ordinary
|
|
65
|
+
* documents, so they are simply rows in `manifest.documents` like any other.
|
|
66
|
+
*/
|
|
67
|
+
import type { DeepDiffResult } from "@intentius/chant/lifecycle/deep-diff";
|
|
68
|
+
import type { K8sConnector } from "@intentius/chant-lexicon-k8s/api/connect";
|
|
69
|
+
import { type RenderManifest } from "./render-store.js";
|
|
70
|
+
/** How one field within a changed document differs between the two renders. */
|
|
71
|
+
export interface RenderFieldChange {
|
|
72
|
+
/** Path within the document's property tree (`spec.replicas`, `data.zeta`). */
|
|
73
|
+
path: string;
|
|
74
|
+
/**
|
|
75
|
+
* `changed` — both renders have the path, with different values.
|
|
76
|
+
* `added` — only the right-hand (`to`) render has it.
|
|
77
|
+
* `removed` — only the left-hand (`from`) render has it.
|
|
78
|
+
*/
|
|
79
|
+
kind: "changed" | "added" | "removed";
|
|
80
|
+
/** Value on the `from` side. Absent for `added`. */
|
|
81
|
+
before?: unknown;
|
|
82
|
+
/** Value on the `to` side. Absent for `removed`. */
|
|
83
|
+
after?: unknown;
|
|
84
|
+
}
|
|
85
|
+
/** Identity of one document, for reporting — the same triple documents are paired on. */
|
|
86
|
+
export interface RenderDiffDocumentRef {
|
|
87
|
+
kind: string;
|
|
88
|
+
namespace: string | null;
|
|
89
|
+
name: string;
|
|
90
|
+
/** The `# Source:` origin path, when the document carried one. */
|
|
91
|
+
source: string | null;
|
|
92
|
+
}
|
|
93
|
+
/** A document present on only one side. */
|
|
94
|
+
export interface AddedOrRemovedDocument extends RenderDiffDocumentRef {
|
|
95
|
+
digest: string;
|
|
96
|
+
}
|
|
97
|
+
/** A document present on both sides with different content. */
|
|
98
|
+
export interface ChangedDocument extends RenderDiffDocumentRef {
|
|
99
|
+
/** Per-document digest on the `from` side. */
|
|
100
|
+
beforeDigest: string;
|
|
101
|
+
/** Per-document digest on the `to` side. */
|
|
102
|
+
afterDigest: string;
|
|
103
|
+
/** Field-level differences, sorted by path. Empty only if a document parses but yields no leaves. */
|
|
104
|
+
changes: RenderFieldChange[];
|
|
105
|
+
}
|
|
106
|
+
export interface RenderDiffResult {
|
|
107
|
+
from: {
|
|
108
|
+
contentDigest: string;
|
|
109
|
+
chart: string;
|
|
110
|
+
releaseName: string;
|
|
111
|
+
};
|
|
112
|
+
to: {
|
|
113
|
+
contentDigest: string;
|
|
114
|
+
chart: string;
|
|
115
|
+
releaseName: string;
|
|
116
|
+
};
|
|
117
|
+
/** Present only on `to`. Sorted by kind/namespace/name. */
|
|
118
|
+
added: AddedOrRemovedDocument[];
|
|
119
|
+
/** Present only on `from`. Sorted by kind/namespace/name. */
|
|
120
|
+
removed: AddedOrRemovedDocument[];
|
|
121
|
+
/** Present on both, different bytes. Sorted by kind/namespace/name. */
|
|
122
|
+
changed: ChangedDocument[];
|
|
123
|
+
/** Present on both with equal per-document digest — reported as identities only, no field pass run. */
|
|
124
|
+
unchanged: RenderDiffDocumentRef[];
|
|
125
|
+
/**
|
|
126
|
+
* Documents each manifest's index could not identify — present in the
|
|
127
|
+
* stream (`docCount`) but absent from `documents` (unparseable, or no
|
|
128
|
+
* `kind` + `metadata.name`). Never matched, never silently dropped.
|
|
129
|
+
*/
|
|
130
|
+
unindexed: {
|
|
131
|
+
from: number;
|
|
132
|
+
to: number;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export interface DiffRendersOptions {
|
|
136
|
+
/** Render store root override; defaults to `renderStoreRoot()`. */
|
|
137
|
+
root?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Diff two renders already in the store, by content digest. Offline: every
|
|
141
|
+
* byte compared comes from the archive (render-store.ts), never a cluster.
|
|
142
|
+
*
|
|
143
|
+
* Throws when either digest has no manifest — a diff over a render nobody
|
|
144
|
+
* persisted is a usage error, not an empty report.
|
|
145
|
+
*/
|
|
146
|
+
export declare function diffRenders(from: string, to: string, options?: DiffRendersOptions): RenderDiffResult;
|
|
147
|
+
/** True when the diff found no added, removed, or changed documents. */
|
|
148
|
+
export declare function renderDiffIsEmpty(result: RenderDiffResult): boolean;
|
|
149
|
+
export interface RenderLiveDiffOptions {
|
|
150
|
+
/** The stored render to diff against the cluster — a `contentDigest` from `chant helm renders`. */
|
|
151
|
+
contentDigest: string;
|
|
152
|
+
/** The chant environment the live read targets — resolves the k8s cluster binding (`k8s.profiles.<environment>.context`), same as any other live read. */
|
|
153
|
+
environment: string;
|
|
154
|
+
/** Render store root override (tests); defaults to `renderStoreRoot()`. */
|
|
155
|
+
root?: string;
|
|
156
|
+
owned?: boolean;
|
|
157
|
+
}
|
|
158
|
+
export interface RenderLiveDiffDeps {
|
|
159
|
+
/** Forwarded to the k8s reader — a test passes a fake cluster's connector. */
|
|
160
|
+
connect?: K8sConnector;
|
|
161
|
+
}
|
|
162
|
+
export type RenderLiveDiffOutcome = {
|
|
163
|
+
found: true;
|
|
164
|
+
manifest: RenderManifest;
|
|
165
|
+
diff: DeepDiffResult;
|
|
166
|
+
}
|
|
167
|
+
/** No such render in the store — refuse the diff rather than report a false clean result. */
|
|
168
|
+
| {
|
|
169
|
+
found: false;
|
|
170
|
+
contentDigest: string;
|
|
171
|
+
};
|
|
172
|
+
/** Row key convention shared with the release-scoped reads (#1246/#1247): `<Kind>/<namespace>/<name>`, `cluster:<Kind>/<name>`. */
|
|
173
|
+
export declare function documentKey(kind: string, namespace: string | undefined, name: string): string;
|
|
174
|
+
/**
|
|
175
|
+
* A namespace-silent document defaults to the render's target namespace —
|
|
176
|
+
* the same rule a deployed release applies to its manifest (`helm apply
|
|
177
|
+
* -n <ns>` targets whatever a namespace-silent object's `.Release.Namespace`
|
|
178
|
+
* would have filled in) — unless the kind is cluster-scoped, in which case a
|
|
179
|
+
* missing namespace is never defaulted.
|
|
180
|
+
*/
|
|
181
|
+
export declare function resolveDocumentNamespace(kind: string, declared: string | null, renderNamespace: string | null): string | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* Diff one stored render's documents against the live cluster.
|
|
184
|
+
*
|
|
185
|
+
* `found: false` when `contentDigest` is not in the store — never fabricates
|
|
186
|
+
* a document, and never reports "no drift" over a render this has no bytes
|
|
187
|
+
* for. On a found render, every document indexed in its manifest becomes a
|
|
188
|
+
* synthetic declared entity (keyed like a release's rows), read live through
|
|
189
|
+
* the k8s lexicon's deep observer, and diffed property-by-property.
|
|
190
|
+
*/
|
|
191
|
+
export declare function diffRenderLive(options: RenderLiveDiffOptions, deps?: RenderLiveDiffDeps): Promise<RenderLiveDiffOutcome>;
|
|
192
|
+
//# sourceMappingURL=render-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-diff.d.ts","sourceRoot":"","sources":["../src/render-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render canonicalization and the contentDigest/inputDigest split
|
|
3
|
+
* (#1237, epic #1228 Phase 2).
|
|
4
|
+
*
|
|
5
|
+
* A pinned render's output is normalized to a canonical byte form before
|
|
6
|
+
* digesting, and two digests are recorded with different jobs:
|
|
7
|
+
*
|
|
8
|
+
* - `inputDigest` answers "same inputs?" cheaply — a `sha256:` over the
|
|
9
|
+
* canonical JSON of { chart reference, chart version, resolved values,
|
|
10
|
+
* capability profile }. It is the same digest `helmInstall` records in the
|
|
11
|
+
* release ledger (#1243), computed by the same helper, so a render and a
|
|
12
|
+
* deploy of the same inputs share an identity.
|
|
13
|
+
* - `contentDigest` answers "same bytes on the cluster?" — a `sha256:` over
|
|
14
|
+
* the canonical rendered bytes. It is the artifact identity.
|
|
15
|
+
*
|
|
16
|
+
* The two diverge exactly when rendering is unpinned or the chart is
|
|
17
|
+
* unstable: two renders with the same inputDigest but different
|
|
18
|
+
* contentDigests mean the render function is not a function of its declared
|
|
19
|
+
* inputs. That divergence is itself a signal — `renderStability` names it.
|
|
20
|
+
*
|
|
21
|
+
* Canonicalization scope (what the epic measured, not more):
|
|
22
|
+
* - Mapping key order is normalized (sorted) — YAML mappings are unordered
|
|
23
|
+
* in Kubernetes semantics, so key order is render noise. Sequence order is
|
|
24
|
+
* never touched; list order is meaningful to Kubernetes.
|
|
25
|
+
* - Document order is preserved, not sorted. The epic verified document
|
|
26
|
+
* ordering is already stable across renders (three renders, again with
|
|
27
|
+
* subcharts), so reordering would only destroy information.
|
|
28
|
+
* - Duplicate documents are preserved. An aliased dependency emits the same
|
|
29
|
+
* CRD twice (epic finding 11); helm dedupes on install, the artifact keeps
|
|
30
|
+
* both, and the digest stays stable because canonicalization is
|
|
31
|
+
* per-document and order-preserving.
|
|
32
|
+
* - The helm-inserted `# Source:` header is kept (it is the origin-routing
|
|
33
|
+
* key the archive wrapper builds on) and normalized to a single leading
|
|
34
|
+
* line. All other comments, trailing whitespace, CRLF line endings, and
|
|
35
|
+
* document-separator styling are render noise and are dropped or
|
|
36
|
+
* normalized.
|
|
37
|
+
*/
|
|
38
|
+
import type { HelmRenderRecord } from "./render.js";
|
|
39
|
+
/**
|
|
40
|
+
* The declared inputs of a helm render or deploy, in the exact shape #1243
|
|
41
|
+
* digests for the release ledger. `helmInstallInputDigest`
|
|
42
|
+
* (op/activities/helm.ts) and `HelmRender`'s recorded `inputDigest` both
|
|
43
|
+
* delegate here, so the two cannot drift: the same chart reference, version,
|
|
44
|
+
* resolved values, and capability facts produce the same digest whether they
|
|
45
|
+
* reach helm through a render or a deploy.
|
|
46
|
+
*/
|
|
47
|
+
export interface HelmInputDigestSource {
|
|
48
|
+
/** Chart reference — a local path, or `<repo-url>/<chart>` for repo-fetched charts. */
|
|
49
|
+
chart: string;
|
|
50
|
+
/** Pinned chart version. Digested as `null` when absent. */
|
|
51
|
+
chartVersion?: string;
|
|
52
|
+
/** Resolved values (file merged with overrides). Digested as `{}` when absent. */
|
|
53
|
+
values?: Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Capability facts the render is pinned against. Only the facts join the
|
|
56
|
+
* digest — the profile's *name* is a label, not an input, so two profiles
|
|
57
|
+
* declaring the same cluster digest identically. `apiVersions` is sorted:
|
|
58
|
+
* it declares a set, not an order.
|
|
59
|
+
*/
|
|
60
|
+
capabilityProfile?: {
|
|
61
|
+
kubeVersion?: string;
|
|
62
|
+
apiVersions?: string[];
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The input-side identity of a helm render or deploy: `sha256:` over the
|
|
67
|
+
* canonical JSON (core's `canonicalJson`, RFC 8785 shape) of the declared
|
|
68
|
+
* inputs. Shared with #1243's release-ledger digest — see
|
|
69
|
+
* `HelmInputDigestSource`. Deliberately excludes the release name and
|
|
70
|
+
* namespace: those are baked into the rendered bytes but the ledger uses
|
|
71
|
+
* this digest as a cross-environment join key, and two environments
|
|
72
|
+
* deploying the same chart, version, and values must share it.
|
|
73
|
+
*/
|
|
74
|
+
export declare function helmInputDigest(source: HelmInputDigestSource): string;
|
|
75
|
+
/**
|
|
76
|
+
* Normalize a `helm template` stream to its canonical byte form.
|
|
77
|
+
*
|
|
78
|
+
* Per document: the `# Source:` header (if any) becomes the single leading
|
|
79
|
+
* comment line, the YAML body is re-serialized with sorted mapping keys
|
|
80
|
+
* (sequences untouched), no line-width folding, and a trailing newline.
|
|
81
|
+
* Documents are emitted in render order, each introduced by a `---` line.
|
|
82
|
+
* CRLF endings, trailing whitespace, non-Source comments, and empty or
|
|
83
|
+
* comment-only documents are render noise and do not survive.
|
|
84
|
+
*
|
|
85
|
+
* A document that fails to parse as YAML is kept verbatim (trimmed) rather
|
|
86
|
+
* than dropped — the canonical form must never silently lose content, and a
|
|
87
|
+
* verbatim document still digests deterministically.
|
|
88
|
+
*/
|
|
89
|
+
export declare function canonicalizeRender(rendered: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* The content-side identity of a render: `sha256:` over the canonical bytes
|
|
92
|
+
* of the rendered stream (see `canonicalizeRender`). Unlike `inputDigest`,
|
|
93
|
+
* this changes whenever the bytes that would reach the cluster change — a
|
|
94
|
+
* chart upgrade with identical values, a helm version that renders
|
|
95
|
+
* differently, an unstable template.
|
|
96
|
+
*/
|
|
97
|
+
export declare function helmContentDigest(rendered: string): string;
|
|
98
|
+
/** One inputDigest's renders and the distinct content identities they produced. */
|
|
99
|
+
export interface RenderStabilityGroup {
|
|
100
|
+
inputDigest: string;
|
|
101
|
+
/** Render names in this group, in record order. */
|
|
102
|
+
names: string[];
|
|
103
|
+
/** Distinct content digests observed, in first-seen order. */
|
|
104
|
+
contentDigests: string[];
|
|
105
|
+
}
|
|
106
|
+
export interface RenderStabilityReport {
|
|
107
|
+
/** Groups whose every render produced the same bytes. */
|
|
108
|
+
stable: RenderStabilityGroup[];
|
|
109
|
+
/**
|
|
110
|
+
* Groups where the same inputs produced different bytes: the render is
|
|
111
|
+
* not pinned down by its declared inputs — an unstable chart, or an input
|
|
112
|
+
* that escaped declaration. Every group here is a defect signal.
|
|
113
|
+
*/
|
|
114
|
+
unstable: RenderStabilityGroup[];
|
|
115
|
+
/** Names of records carrying no digests (unpinned renders) — unassessable. */
|
|
116
|
+
unassessed: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Group recorded renders by input identity and report whether the same
|
|
120
|
+
* inputs always produced the same bytes.
|
|
121
|
+
*
|
|
122
|
+
* Two renders with equal `inputDigest` and different `contentDigest` mean
|
|
123
|
+
* the render is not a function of its declared inputs — the chart is
|
|
124
|
+
* unstable (generated values, timestamps) or an input escaped declaration.
|
|
125
|
+
* That divergence is the signal this helper exists to name; a single render
|
|
126
|
+
* per input proves nothing and lands in `stable` by default.
|
|
127
|
+
*
|
|
128
|
+
* Grouping keys on `(inputDigest, name)` because the release name is a real
|
|
129
|
+
* render input baked into the bytes but deliberately absent from
|
|
130
|
+
* `inputDigest` (see `helmInputDigest`) — two differently named renders of
|
|
131
|
+
* the same chart legitimately differ in content and must not be read as
|
|
132
|
+
* instability.
|
|
133
|
+
*/
|
|
134
|
+
export declare function renderStability(records: readonly HelmRenderRecord[]): RenderStabilityReport;
|
|
135
|
+
//# sourceMappingURL=render-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-digest.d.ts","sourceRoot":"","sources":["../src/render-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAarE;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoB3D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,mFAAmF;AACnF,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,qBAAqB,CAwB3F"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RenderManifest + content-addressed render storage (#1238, epic #1228
|
|
3
|
+
* Phase 2).
|
|
4
|
+
*
|
|
5
|
+
* #1237 gave a pinned render its identities — `inputDigest` over the
|
|
6
|
+
* declared inputs, `contentDigest` over the canonical rendered bytes. This
|
|
7
|
+
* module makes the render durable: the canonical bytes land in a
|
|
8
|
+
* content-addressed store keyed by `contentDigest`, and a `RenderManifest`
|
|
9
|
+
* — modeled on core's `BuildArchiveManifest`
|
|
10
|
+
* (packages/core/src/components/verbs/build-archive.ts) — records what the
|
|
11
|
+
* bytes are, what produced them, and how to find each document inside them.
|
|
12
|
+
*
|
|
13
|
+
* Storage layout, under `~/.chant/helm-renders/` (override with
|
|
14
|
+
* `CHANT_HELM_RENDER_ROOT`):
|
|
15
|
+
*
|
|
16
|
+
* ```
|
|
17
|
+
* sha256-<64 hex>/ one per distinct contentDigest
|
|
18
|
+
* content.yaml the canonical rendered bytes (canonicalizeRender)
|
|
19
|
+
* manifest.json the RenderManifest
|
|
20
|
+
* inputs/<64 hex>.json inputs index: full-render-inputs key -> digests
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The `sha256-<hex>` entries are the new root the issue asks for: the
|
|
24
|
+
* pre-#1238 cache keyed entries by a *truncated, input-derived* hash
|
|
25
|
+
* (16 hex characters, no algorithm prefix), which is a cache key, not an
|
|
26
|
+
* artifact identity. Those legacy entries are left exactly where they are —
|
|
27
|
+
* unpinned renders keep using them — and pinned renders write here instead.
|
|
28
|
+
* No migration: a truncated key cannot be turned back into a digest.
|
|
29
|
+
*
|
|
30
|
+
* Two renders that produce the same bytes share one `sha256-<hex>` entry —
|
|
31
|
+
* the content file and manifest are written once and never rewritten
|
|
32
|
+
* (first writer wins; the store is immutable, like a build archive entry).
|
|
33
|
+
* Dedup falls out of content addressing rather than being a feature.
|
|
34
|
+
*
|
|
35
|
+
* The inputs index preserves cache-hit behavior: before shelling out to
|
|
36
|
+
* helm, `HelmRender` computes the full-inputs key and reads
|
|
37
|
+
* `inputs/<key>.json` to find the bytes a previous identical render stored.
|
|
38
|
+
* The index key deliberately differs from `inputDigest`: the release name
|
|
39
|
+
* and namespace are baked into the rendered bytes (`.Release.Name`,
|
|
40
|
+
* `--namespace`) but are excluded from `inputDigest` because the release
|
|
41
|
+
* ledger uses that digest as a cross-environment join key (see
|
|
42
|
+
* `helmInputDigest` in ./render-digest.ts). A cache must key on everything
|
|
43
|
+
* that changes the bytes, so the index key includes both.
|
|
44
|
+
*
|
|
45
|
+
* Retention: none, deliberately. The build archive this is modeled on has
|
|
46
|
+
* no garbage collection — an archive entry lives until someone deletes it —
|
|
47
|
+
* and the pre-#1238 render cache behaved the same way. This store follows
|
|
48
|
+
* suit: entries accumulate until removed by hand. If the archive ever grows
|
|
49
|
+
* a retention story, this store should adopt the same one.
|
|
50
|
+
*/
|
|
51
|
+
import type { HelmCapabilityProfile } from "./config.js";
|
|
52
|
+
import type { ValueOrigin } from "./values-probe.js";
|
|
53
|
+
/**
|
|
54
|
+
* One document's entry in a render's document index: enough identity to ask
|
|
55
|
+
* "give me the ServiceAccount named X in namespace Y" and enough addressing
|
|
56
|
+
* to answer it without parsing the whole stream.
|
|
57
|
+
*/
|
|
58
|
+
export interface RenderDocumentEntry {
|
|
59
|
+
/** Kubernetes kind, e.g. `Deployment`. */
|
|
60
|
+
kind: string;
|
|
61
|
+
/** apiVersion as rendered, e.g. `apps/v1`. */
|
|
62
|
+
apiVersion: string;
|
|
63
|
+
/** `metadata.name`. */
|
|
64
|
+
name: string;
|
|
65
|
+
/** `metadata.namespace`, or `null` for cluster-scoped / namespace-less documents. */
|
|
66
|
+
namespace: string | null;
|
|
67
|
+
/** The helm-inserted `# Source:` origin path, when the document carries one. */
|
|
68
|
+
source: string | null;
|
|
69
|
+
/**
|
|
70
|
+
* Byte offset of this document's first byte inside `content.yaml`
|
|
71
|
+
* (pointing just past the `---` separator line, at the `# Source:` header
|
|
72
|
+
* when there is one).
|
|
73
|
+
*/
|
|
74
|
+
start: number;
|
|
75
|
+
/** Byte length of the document, up to the next separator (or end of file). */
|
|
76
|
+
length: number;
|
|
77
|
+
/** `sha256:` over exactly those bytes — lets a reader verify a slice without trusting offsets. */
|
|
78
|
+
digest: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The durable record of one pinned render — what `manifest.json` holds.
|
|
82
|
+
* Modeled on `BuildArchiveManifest`: versioned, content-addressed, and
|
|
83
|
+
* carrying both identity sides the epic's Decisions require — the
|
|
84
|
+
* input-side join key (`inputDigest`, with `valuesDigest` as its
|
|
85
|
+
* values-only component) for cross-environment questions, and
|
|
86
|
+
* `contentDigest` proving what this cluster's profile actually received.
|
|
87
|
+
*/
|
|
88
|
+
export interface RenderManifest {
|
|
89
|
+
/** Manifest schema version, so an incompatible future shape is detected before being misread. */
|
|
90
|
+
version: 1;
|
|
91
|
+
/** Chart name or local chart path, as the render declared it. */
|
|
92
|
+
chart: string;
|
|
93
|
+
/** Pinned chart version, or `null` for a local chart rendered without one. */
|
|
94
|
+
chartVersion: string | null;
|
|
95
|
+
/** Chart repo URL, or `null` for a local chart. */
|
|
96
|
+
repo: string | null;
|
|
97
|
+
/** Helm release name baked into the bytes (`.Release.Name`). */
|
|
98
|
+
releaseName: string;
|
|
99
|
+
/** Namespace the render targeted (`--namespace`), or `null`. */
|
|
100
|
+
namespace: string | null;
|
|
101
|
+
/**
|
|
102
|
+
* `sha256:` over the canonical JSON of the resolved values alone — the
|
|
103
|
+
* input-side join key the epic's ledger queries use together with
|
|
104
|
+
* `(chart, chartVersion)`.
|
|
105
|
+
*/
|
|
106
|
+
valuesDigest: string;
|
|
107
|
+
/**
|
|
108
|
+
* `sha256:` over the full declared-input set (chart reference, version,
|
|
109
|
+
* values, capability facts) — `helmInputDigest`, the same digest the
|
|
110
|
+
* release ledger records on deploy (#1243).
|
|
111
|
+
*/
|
|
112
|
+
inputDigest: string;
|
|
113
|
+
/** The capability profile the render was pinned against. `cluster` is the profile's declared name — profiles are per cluster. */
|
|
114
|
+
capabilityProfile: {
|
|
115
|
+
cluster: string;
|
|
116
|
+
kubeVersion: string;
|
|
117
|
+
apiVersions: string[];
|
|
118
|
+
};
|
|
119
|
+
/** `sha256:` over the canonical rendered bytes — the artifact identity, and this entry's storage key. */
|
|
120
|
+
contentDigest: string;
|
|
121
|
+
/** Number of documents in the canonical stream (including any the index could not identify). */
|
|
122
|
+
docCount: number;
|
|
123
|
+
/** Index of identifiable documents: kind/namespace/name -> byte span + per-document digest. */
|
|
124
|
+
documents: RenderDocumentEntry[];
|
|
125
|
+
/** ISO-8601 timestamp this manifest was written. Not part of any digest. */
|
|
126
|
+
renderedAt: string;
|
|
127
|
+
/**
|
|
128
|
+
* Version of the helm binary that produced the bytes. Load-bearing: the
|
|
129
|
+
* default kube version is a property of the binary (epic finding 1), so
|
|
130
|
+
* this field is what explains a digest mismatch between two machines.
|
|
131
|
+
*/
|
|
132
|
+
helmVersion: string;
|
|
133
|
+
/** chant version that wrote this manifest. */
|
|
134
|
+
chantVersion: string;
|
|
135
|
+
/** Source ref/commit the render was produced from, when the caller supplied one. */
|
|
136
|
+
sourceRef: string | null;
|
|
137
|
+
/**
|
|
138
|
+
* `sha256:` over the canonical JSON of the coalesced values the
|
|
139
|
+
* build-time probe (#1251) observed for every chart instance, keyed by
|
|
140
|
+
* scope path — `coalescedValuesDigest` from `./values-probe.ts`. `null`
|
|
141
|
+
* when the probe did not run for this render (a repo-fetched chart, whose
|
|
142
|
+
* source the probe needs on disk, or a probe failure — never fabricated).
|
|
143
|
+
*/
|
|
144
|
+
coalescedValuesDigest: string | null;
|
|
145
|
+
/**
|
|
146
|
+
* Each coalesced value's winning layer (#1252), dot-joined root-coordinate
|
|
147
|
+
* path to `ValueOrigin` — `computeValueSources` from `./values-probe.ts`.
|
|
148
|
+
* `null` under the same conditions as `coalescedValuesDigest`.
|
|
149
|
+
*/
|
|
150
|
+
valueSources: Record<string, ValueOrigin> | null;
|
|
151
|
+
}
|
|
152
|
+
/** What `inputs/<key>.json` holds: the digests a full-inputs cache key resolves to. */
|
|
153
|
+
export interface RenderInputsIndexEntry {
|
|
154
|
+
version: 1;
|
|
155
|
+
inputDigest: string;
|
|
156
|
+
contentDigest: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Root of the render store. `CHANT_HELM_RENDER_ROOT` overrides the default
|
|
160
|
+
* `~/.chant/helm-renders` — the same directory the legacy input-keyed cache
|
|
161
|
+
* lives in; the two coexist because legacy entries are bare 16-hex names
|
|
162
|
+
* and store entries are `sha256-` prefixed.
|
|
163
|
+
*/
|
|
164
|
+
export declare function renderStoreRoot(): string;
|
|
165
|
+
/** The full set of inputs that determine a pinned render's bytes. */
|
|
166
|
+
export interface RenderCacheKeySource {
|
|
167
|
+
/** Chart reference — a local path, or `<repo-url>/<chart>` for repo-fetched charts (same convention `helmInputDigest` uses). */
|
|
168
|
+
chart: string;
|
|
169
|
+
chartVersion?: string;
|
|
170
|
+
/** Release name — baked into the bytes via `.Release.Name`, so a real cache input even though `inputDigest` excludes it. */
|
|
171
|
+
releaseName: string;
|
|
172
|
+
/** Namespace — baked in via `--namespace`, likewise excluded from `inputDigest`. */
|
|
173
|
+
namespace?: string;
|
|
174
|
+
values?: Record<string, unknown>;
|
|
175
|
+
capabilityProfile: HelmCapabilityProfile;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Cache key over *everything* that changes a pinned render's bytes — a
|
|
179
|
+
* strict superset of `helmInputDigest`'s inputs (adds release name,
|
|
180
|
+
* namespace, and the profile's declared name, mirroring the legacy cache
|
|
181
|
+
* key's fields). 64 hex characters, no prefix: this is a lookup key, not an
|
|
182
|
+
* artifact identity.
|
|
183
|
+
*/
|
|
184
|
+
export declare function renderCacheKey(source: RenderCacheKeySource): string;
|
|
185
|
+
/**
|
|
186
|
+
* `sha256:` over the canonical JSON of the resolved values alone — the
|
|
187
|
+
* `valuesDigest` half of the ledger's input-side join key
|
|
188
|
+
* `(chart, chartVersion, valuesDigest)`. Absent values digest as `{}`,
|
|
189
|
+
* matching `helmInputDigest`'s treatment.
|
|
190
|
+
*/
|
|
191
|
+
export declare function helmValuesDigest(values?: Record<string, unknown>): string;
|
|
192
|
+
/**
|
|
193
|
+
* Build the document index over a canonical stream: for every identifiable
|
|
194
|
+
* document (it parses and carries `kind` + `metadata.name`), its
|
|
195
|
+
* kind/namespace/name identity, byte span, and per-document digest.
|
|
196
|
+
* Returns the index and the total document count — the count includes
|
|
197
|
+
* documents the index could not identify, so `docCount` is always the
|
|
198
|
+
* number of documents the artifact carries.
|
|
199
|
+
*/
|
|
200
|
+
export declare function indexRenderDocuments(canonical: string): {
|
|
201
|
+
documents: RenderDocumentEntry[];
|
|
202
|
+
docCount: number;
|
|
203
|
+
};
|
|
204
|
+
export interface PersistHelmRenderInput {
|
|
205
|
+
/** The `helm template` output — raw or already canonical; it is canonicalized before storage either way. */
|
|
206
|
+
rendered: string;
|
|
207
|
+
/** Release name the render was produced under (`HelmRenderProps.name`). */
|
|
208
|
+
releaseName: string;
|
|
209
|
+
/** Chart name or local chart path, as declared. */
|
|
210
|
+
chart: string;
|
|
211
|
+
/** Chart repo URL for repo-fetched charts. */
|
|
212
|
+
repo?: string;
|
|
213
|
+
chartVersion?: string;
|
|
214
|
+
namespace?: string;
|
|
215
|
+
values?: Record<string, unknown>;
|
|
216
|
+
/**
|
|
217
|
+
* The capability profile the render was pinned against. Absent means the
|
|
218
|
+
* render was unpinned — persistence is refused, because an unpinned
|
|
219
|
+
* render's bytes are a function of the local helm binary's defaults and
|
|
220
|
+
* have no identity worth storing.
|
|
221
|
+
*/
|
|
222
|
+
capabilityProfile?: HelmCapabilityProfile;
|
|
223
|
+
/** Version of the helm binary that produced the bytes. Recorded as `"unknown"` when not supplied. */
|
|
224
|
+
helmVersion?: string;
|
|
225
|
+
/** Source ref/commit, when the caller has one. Never fabricated. */
|
|
226
|
+
sourceRef?: string;
|
|
227
|
+
/**
|
|
228
|
+
* The build-time coalesced-values probe's digest (#1251), when the caller
|
|
229
|
+
* ran one for this render. Absent (not merely `undefined`-passed) records
|
|
230
|
+
* `null` in the manifest — the probe needs the chart source on disk, so a
|
|
231
|
+
* repo-fetched render legitimately has none.
|
|
232
|
+
*/
|
|
233
|
+
coalescedValuesDigest?: string;
|
|
234
|
+
/** The probe's value-source attribution (#1252), alongside `coalescedValuesDigest`. */
|
|
235
|
+
valueSources?: Record<string, ValueOrigin>;
|
|
236
|
+
/** Clock override for tests. */
|
|
237
|
+
now?: () => Date;
|
|
238
|
+
/** Store root override; defaults to `renderStoreRoot()`. */
|
|
239
|
+
root?: string;
|
|
240
|
+
}
|
|
241
|
+
export interface PersistedHelmRender {
|
|
242
|
+
/** The manifest now on disk — the existing one when the content was already stored. */
|
|
243
|
+
manifest: RenderManifest;
|
|
244
|
+
/** Directory the render lives in: `<root>/sha256-<hex>`. */
|
|
245
|
+
dir: string;
|
|
246
|
+
/**
|
|
247
|
+
* True when this contentDigest was already in the store — the bytes and
|
|
248
|
+
* manifest were left untouched (only the inputs index was updated).
|
|
249
|
+
*/
|
|
250
|
+
deduplicated: boolean;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Persist one pinned render: canonical bytes under their `contentDigest`,
|
|
254
|
+
* the `RenderManifest` beside them, and an inputs-index entry so an
|
|
255
|
+
* identical future render is a cache hit.
|
|
256
|
+
*
|
|
257
|
+
* Content-addressed entries are immutable: when the digest directory
|
|
258
|
+
* already holds a manifest, both files are left as they are and the
|
|
259
|
+
* existing manifest is returned (`deduplicated: true`). The inputs index is
|
|
260
|
+
* still written — a new input combination can legitimately map to bytes the
|
|
261
|
+
* store already holds.
|
|
262
|
+
*
|
|
263
|
+
* Refuses an unpinned render (no capability profile) with the specific
|
|
264
|
+
* reason: no profile means the bytes depend on the local helm binary's
|
|
265
|
+
* defaulted capabilities, so they have no stable content identity to store
|
|
266
|
+
* under.
|
|
267
|
+
*/
|
|
268
|
+
export declare function persistHelmRender(input: PersistHelmRenderInput): PersistedHelmRender;
|
|
269
|
+
/** Load the `RenderManifest` stored under a content digest, or `undefined` when the store has no such entry. */
|
|
270
|
+
export declare function loadRenderManifest(contentDigest: string, opts?: {
|
|
271
|
+
root?: string;
|
|
272
|
+
}): RenderManifest | undefined;
|
|
273
|
+
/** Load the canonical rendered bytes stored under a content digest, or `undefined` when absent. */
|
|
274
|
+
export declare function loadRenderContent(contentDigest: string, opts?: {
|
|
275
|
+
root?: string;
|
|
276
|
+
}): string | undefined;
|
|
277
|
+
/** Resolve a full-inputs cache key through the inputs index, or `undefined` on a miss. */
|
|
278
|
+
export declare function findRenderByCacheKey(cacheKey: string, opts?: {
|
|
279
|
+
root?: string;
|
|
280
|
+
}): RenderInputsIndexEntry | undefined;
|
|
281
|
+
/**
|
|
282
|
+
* Every manifest in the store, sorted by `renderedAt` then `contentDigest`
|
|
283
|
+
* for a stable listing. Entries whose manifest is missing or unreadable are
|
|
284
|
+
* skipped — a listing never fails on one corrupt entry. This is the query
|
|
285
|
+
* surface the diff issues (#1249/#1250) resolve digests against.
|
|
286
|
+
*/
|
|
287
|
+
export declare function listRenderManifests(opts?: {
|
|
288
|
+
root?: string;
|
|
289
|
+
}): RenderManifest[];
|
|
290
|
+
/** How a caller names one document inside a stored render. */
|
|
291
|
+
export interface RenderDocumentRef {
|
|
292
|
+
kind: string;
|
|
293
|
+
name: string;
|
|
294
|
+
/** Omit (or pass `null`) to match a cluster-scoped / namespace-less document. */
|
|
295
|
+
namespace?: string | null;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Resolve one document by kind/namespace/name to its exact bytes inside a
|
|
299
|
+
* stored render, via the manifest's document index. The slice is verified
|
|
300
|
+
* against the entry's per-document digest before being returned — corrupt
|
|
301
|
+
* content is an error, never silently wrong bytes. `undefined` means the
|
|
302
|
+
* store has no such render or the index has no such document.
|
|
303
|
+
*/
|
|
304
|
+
export declare function readRenderDocument(contentDigest: string, ref: RenderDocumentRef, opts?: {
|
|
305
|
+
root?: string;
|
|
306
|
+
}): {
|
|
307
|
+
entry: RenderDocumentEntry;
|
|
308
|
+
text: string;
|
|
309
|
+
} | undefined;
|
|
310
|
+
//# sourceMappingURL=render-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-store.d.ts","sourceRoot":"","sources":["../src/render-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAYH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gFAAgF;IAChF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,iGAAiG;IACjG,OAAO,EAAE,CAAC,CAAC;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mDAAmD;IACnD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,iIAAiI;IACjI,iBAAiB,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACnF,yGAAyG;IACzG,aAAa,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;;OAMG;IACH,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC;CAClD;AAED,uFAAuF;AACvF,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAsBD,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,gIAAgI;IAChI,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4HAA4H;IAC5H,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,iBAAiB,EAAE,qBAAqB,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAcnE;AAaD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEzE;AAkFD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAyB9G;AAID,MAAM,WAAW,sBAAsB;IACrC,4GAA4G;IAC5G,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,qGAAqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,uFAAuF;IACvF,QAAQ,EAAE,cAAc,CAAC;IACzB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,mBAAmB,CA0EpF;AAID,gHAAgH;AAChH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,GAAG,SAAS,CAS9G;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAKrG;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvB,sBAAsB,GAAG,SAAS,CAOpC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,EAAE,CAmB9E;AAED,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,iBAAiB,EACtB,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAoB1D"}
|