@clossys/launcher 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1328 -60
- package/contracts/conversation-contract.md +2 -1
- package/contracts/product-ci-workflow.yml +74 -0
- package/contracts/repository-inventory.json +53 -0
- package/dist/admission-fixture.d.ts +168 -0
- package/dist/admission-fixture.d.ts.map +1 -0
- package/dist/admission-fixture.js +453 -0
- package/dist/admission-fixture.js.map +1 -0
- package/dist/admission.d.ts +124 -0
- package/dist/admission.d.ts.map +1 -0
- package/dist/admission.js +799 -0
- package/dist/admission.js.map +1 -0
- package/dist/agents-guide.d.ts +9 -0
- package/dist/agents-guide.d.ts.map +1 -0
- package/dist/agents-guide.js +26 -0
- package/dist/agents-guide.js.map +1 -0
- package/dist/apply-command-options.check.d.ts +12 -0
- package/dist/apply-command-options.check.d.ts.map +1 -0
- package/dist/apply-command-options.check.js +20 -0
- package/dist/apply-command-options.check.js.map +1 -0
- package/dist/apply-plan-cli.d.ts +39 -1
- package/dist/apply-plan-cli.d.ts.map +1 -1
- package/dist/apply-plan-cli.js +432 -15
- package/dist/apply-plan-cli.js.map +1 -1
- package/dist/apply-plan.d.ts +46 -59
- package/dist/apply-plan.d.ts.map +1 -1
- package/dist/apply-plan.js +112 -97
- package/dist/apply-plan.js.map +1 -1
- package/dist/apply-step-fixture.d.ts +87 -0
- package/dist/apply-step-fixture.d.ts.map +1 -0
- package/dist/apply-step-fixture.js +199 -0
- package/dist/apply-step-fixture.js.map +1 -0
- package/dist/apply-store.d.ts +93 -0
- package/dist/apply-store.d.ts.map +1 -0
- package/dist/apply-store.js +625 -0
- package/dist/apply-store.js.map +1 -0
- package/dist/approval-sheet.d.ts +21 -0
- package/dist/approval-sheet.d.ts.map +1 -0
- package/dist/approval-sheet.js +157 -0
- package/dist/approval-sheet.js.map +1 -0
- package/dist/body-command.d.ts +42 -0
- package/dist/body-command.d.ts.map +1 -0
- package/dist/body-command.js +143 -0
- package/dist/body-command.js.map +1 -0
- package/dist/change-set-contract.d.ts +381 -0
- package/dist/change-set-contract.d.ts.map +1 -0
- package/dist/change-set-contract.js +738 -0
- package/dist/change-set-contract.js.map +1 -0
- package/dist/change-set-digest.d.ts +28 -0
- package/dist/change-set-digest.d.ts.map +1 -0
- package/dist/change-set-digest.js +65 -0
- package/dist/change-set-digest.js.map +1 -0
- package/dist/check-cli.d.ts.map +1 -1
- package/dist/check-cli.js +14 -3
- package/dist/check-cli.js.map +1 -1
- package/dist/cli.d.ts +17 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -23
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +79 -22
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +843 -268
- package/dist/core.js.map +1 -1
- package/dist/dry-materialize.d.ts +63 -0
- package/dist/dry-materialize.d.ts.map +1 -0
- package/dist/dry-materialize.js +330 -0
- package/dist/dry-materialize.js.map +1 -0
- package/dist/generated/contract-schema.generated.d.ts +97 -0
- package/dist/generated/contract-schema.generated.d.ts.map +1 -0
- package/dist/generated/contract-schema.generated.js +496 -0
- package/dist/generated/contract-schema.generated.js.map +1 -0
- package/dist/generated/package-scope.generated.d.ts +6 -0
- package/dist/generated/package-scope.generated.d.ts.map +1 -0
- package/dist/generated/package-scope.generated.js +10 -0
- package/dist/generated/package-scope.generated.js.map +1 -0
- package/dist/generated/plan-contracts.generated.d.ts +3 -0
- package/dist/generated/plan-contracts.generated.d.ts.map +1 -0
- package/dist/generated/plan-contracts.generated.js +2840 -0
- package/dist/generated/plan-contracts.generated.js.map +1 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +11 -0
- package/dist/host.js.map +1 -1
- package/dist/identity.d.ts +15 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +48 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +34 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/inventory-adoption.d.ts +24 -5
- package/dist/inventory-adoption.d.ts.map +1 -1
- package/dist/inventory-adoption.js +70 -25
- package/dist/inventory-adoption.js.map +1 -1
- package/dist/inventory-choice.d.ts +40 -0
- package/dist/inventory-choice.d.ts.map +1 -0
- package/dist/inventory-choice.js +156 -0
- package/dist/inventory-choice.js.map +1 -0
- package/dist/inventory-contract.d.ts +89 -0
- package/dist/inventory-contract.d.ts.map +1 -0
- package/dist/inventory-contract.js +121 -0
- package/dist/inventory-contract.js.map +1 -0
- package/dist/key-editor.d.ts +30 -0
- package/dist/key-editor.d.ts.map +1 -0
- package/dist/key-editor.js +445 -0
- package/dist/key-editor.js.map +1 -0
- package/dist/ledger-contract.d.ts +187 -0
- package/dist/ledger-contract.d.ts.map +1 -0
- package/dist/ledger-contract.js +532 -0
- package/dist/ledger-contract.js.map +1 -0
- package/dist/ledger-trust.d.ts +90 -0
- package/dist/ledger-trust.d.ts.map +1 -0
- package/dist/ledger-trust.js +198 -0
- package/dist/ledger-trust.js.map +1 -0
- package/dist/lockfile-invariants.d.ts +48 -0
- package/dist/lockfile-invariants.d.ts.map +1 -0
- package/dist/lockfile-invariants.js +375 -0
- package/dist/lockfile-invariants.js.map +1 -0
- package/dist/lockfile-readers.d.ts +72 -0
- package/dist/lockfile-readers.d.ts.map +1 -0
- package/dist/lockfile-readers.js +713 -0
- package/dist/lockfile-readers.js.map +1 -0
- package/dist/lockfile-regen.d.ts +106 -0
- package/dist/lockfile-regen.d.ts.map +1 -0
- package/dist/lockfile-regen.js +760 -0
- package/dist/lockfile-regen.js.map +1 -0
- package/dist/lockfile-tool-env.d.ts +29 -0
- package/dist/lockfile-tool-env.d.ts.map +1 -0
- package/dist/lockfile-tool-env.js +111 -0
- package/dist/lockfile-tool-env.js.map +1 -0
- package/dist/materialize.d.ts +113 -0
- package/dist/materialize.d.ts.map +1 -0
- package/dist/materialize.js +840 -0
- package/dist/materialize.js.map +1 -0
- package/dist/observe-repository.d.ts +90 -0
- package/dist/observe-repository.d.ts.map +1 -0
- package/dist/observe-repository.js +1367 -0
- package/dist/observe-repository.js.map +1 -0
- package/dist/plan-bundle-setup-fixture.d.ts +68 -0
- package/dist/plan-bundle-setup-fixture.d.ts.map +1 -0
- package/dist/plan-bundle-setup-fixture.js +167 -0
- package/dist/plan-bundle-setup-fixture.js.map +1 -0
- package/dist/plan-bundle.d.ts +250 -0
- package/dist/plan-bundle.d.ts.map +1 -0
- package/dist/plan-bundle.js +827 -0
- package/dist/plan-bundle.js.map +1 -0
- package/dist/plan-command.d.ts +29 -0
- package/dist/plan-command.d.ts.map +1 -0
- package/dist/plan-command.js +493 -0
- package/dist/plan-command.js.map +1 -0
- package/dist/plan-contract.d.ts +153 -0
- package/dist/plan-contract.d.ts.map +1 -0
- package/dist/plan-contract.js +61 -0
- package/dist/plan-contract.js.map +1 -0
- package/dist/plan-digest.d.ts +25 -0
- package/dist/plan-digest.d.ts.map +1 -0
- package/dist/plan-digest.js +106 -0
- package/dist/plan-digest.js.map +1 -0
- package/dist/plan-rules.d.ts +23 -0
- package/dist/plan-rules.d.ts.map +1 -0
- package/dist/plan-rules.js +177 -0
- package/dist/plan-rules.js.map +1 -0
- package/dist/planned-bundle.d.ts +20 -0
- package/dist/planned-bundle.d.ts.map +1 -0
- package/dist/planned-bundle.js +191 -0
- package/dist/planned-bundle.js.map +1 -0
- package/dist/product-repository.d.ts +4 -0
- package/dist/product-repository.d.ts.map +1 -1
- package/dist/product-repository.js +9 -1
- package/dist/product-repository.js.map +1 -1
- package/dist/provenance-gate.d.ts +48 -0
- package/dist/provenance-gate.d.ts.map +1 -0
- package/dist/provenance-gate.js +324 -0
- package/dist/provenance-gate.js.map +1 -0
- package/dist/pull-request-body.d.ts +45 -0
- package/dist/pull-request-body.d.ts.map +1 -0
- package/dist/pull-request-body.js +232 -0
- package/dist/pull-request-body.js.map +1 -0
- package/dist/registry-snapshot.d.ts +141 -0
- package/dist/registry-snapshot.d.ts.map +1 -0
- package/dist/registry-snapshot.js +483 -0
- package/dist/registry-snapshot.js.map +1 -0
- package/dist/release-age-edit.d.ts +52 -0
- package/dist/release-age-edit.d.ts.map +1 -0
- package/dist/release-age-edit.js +413 -0
- package/dist/release-age-edit.js.map +1 -0
- package/dist/root-entries.d.ts +36 -0
- package/dist/root-entries.d.ts.map +1 -0
- package/dist/root-entries.js +80 -0
- package/dist/root-entries.js.map +1 -0
- package/dist/setup-template-scripts.d.ts +34 -0
- package/dist/setup-template-scripts.d.ts.map +1 -0
- package/dist/setup-template-scripts.js +557 -0
- package/dist/setup-template-scripts.js.map +1 -0
- package/dist/setup-templates.d.ts +54 -0
- package/dist/setup-templates.d.ts.map +1 -0
- package/dist/setup-templates.js +427 -0
- package/dist/setup-templates.js.map +1 -0
- package/dist/skills.d.ts +34 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +129 -17
- package/dist/skills.js.map +1 -1
- package/dist/status.d.ts +63 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +539 -0
- package/dist/status.js.map +1 -0
- package/dist/types.d.ts +151 -13
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -5
- package/skeleton/README.md +14 -9
- package/skeleton/package.json +2 -1
- package/skill/SKILL.md +20 -16
- package/skill-catalogue/advisor/SKILL.md +100 -11
- package/skill-catalogue/architect/SKILL.md +2 -13
- package/skill-catalogue/bouncer/SKILL.md +2 -13
- package/skill-catalogue/builder/SKILL.md +2 -13
- package/skill-catalogue/butler/SKILL.md +2 -13
- package/skill-catalogue/controller/SKILL.md +2 -13
- package/skill-catalogue/customer/SKILL.md +4 -13
- package/skill-catalogue/designer/SKILL.md +9 -14
- package/skill-catalogue/giver/SKILL.md +2 -13
- package/skill-catalogue/influencer/SKILL.md +2 -13
- package/skill-catalogue/inspector/SKILL.md +2 -13
- package/skill-catalogue/integrator/SKILL.md +2 -13
- package/skill-catalogue/keeper/SKILL.md +2 -13
- package/skill-catalogue/launcher/SKILL.md +20 -16
- package/skill-catalogue/locksmith/SKILL.md +2 -13
- package/skill-catalogue/messenger/SKILL.md +2 -13
- package/skill-catalogue/observer/SKILL.md +2 -13
- package/skill-catalogue/publisher/SKILL.md +11 -17
- package/skill-catalogue/starter/SKILL.md +3 -13
- package/skill-catalogue/strategist/SKILL.md +14 -17
- package/skill-catalogue/writer/SKILL.md +7 -14
- package/src/admission-fixture.ts +572 -0
- package/src/admission.ts +816 -0
- package/src/agents-guide.ts +29 -0
- package/src/apply-command-options.check.ts +27 -0
- package/src/apply-plan-cli.ts +454 -14
- package/src/apply-plan.ts +112 -124
- package/src/apply-step-fixture.ts +236 -0
- package/src/apply-store.ts +584 -0
- package/src/approval-sheet.ts +164 -0
- package/src/body-command.ts +162 -0
- package/src/change-set-contract.ts +937 -0
- package/src/change-set-digest.ts +70 -0
- package/src/check-cli.ts +14 -3
- package/src/cli.ts +90 -22
- package/src/core.ts +973 -275
- package/src/dry-materialize.ts +353 -0
- package/src/generated/contract-schema.generated.ts +520 -0
- package/src/generated/package-scope.generated.ts +10 -0
- package/src/generated/plan-contracts.generated.ts +2840 -0
- package/src/host.ts +10 -0
- package/src/identity.ts +51 -0
- package/src/index.ts +72 -3
- package/src/inventory-adoption.ts +107 -29
- package/src/inventory-choice.ts +172 -0
- package/src/inventory-contract.ts +166 -0
- package/src/key-editor.ts +446 -0
- package/src/ledger-contract.ts +637 -0
- package/src/ledger-trust.ts +267 -0
- package/src/lockfile-invariants.ts +421 -0
- package/src/lockfile-readers.ts +749 -0
- package/src/lockfile-regen.ts +851 -0
- package/src/lockfile-tool-env.ts +131 -0
- package/src/materialize.ts +886 -0
- package/src/observe-repository.ts +1365 -0
- package/src/plan-bundle-setup-fixture.ts +200 -0
- package/src/plan-bundle.ts +964 -0
- package/src/plan-command.ts +509 -0
- package/src/plan-contract.ts +179 -0
- package/src/plan-digest.ts +102 -0
- package/src/plan-rules.ts +188 -0
- package/src/planned-bundle.ts +211 -0
- package/src/product-repository.ts +10 -1
- package/src/provenance-gate.ts +352 -0
- package/src/pull-request-body.ts +261 -0
- package/src/registry-snapshot.ts +534 -0
- package/src/release-age-edit.ts +430 -0
- package/src/root-entries.ts +81 -0
- package/src/setup-template-scripts.ts +571 -0
- package/src/setup-templates.ts +471 -0
- package/src/skills.ts +161 -18
- package/src/status.ts +557 -0
- package/src/types.ts +148 -13
- package/CHANGELOG.md +0 -131
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
// The hub's two apply stores (issue #1178): every repository change set (kept
|
|
2
|
+
// append-only, bar the body hash of a set, below) and every apply bundle (the newest computation replacing the
|
|
3
|
+
// last under one digest) this hub has computed, kept by digest under
|
|
4
|
+
// clossys/.state/apply/ so a later step (the ledger, an approval, a resumed
|
|
5
|
+
// apply) can read back the exact document a digest names instead of trusting
|
|
6
|
+
// whatever is passed to it in memory.
|
|
7
|
+
//
|
|
8
|
+
// Both stores are content-addressed: a file's name is its document's own
|
|
9
|
+
// digest. The change-set store is append-only: a name is only ever bound to
|
|
10
|
+
// the first bytes stored under it, and writing over it with different bytes
|
|
11
|
+
// is refused rather than silently replacing history a ledger or an approval
|
|
12
|
+
// may already cite. The bundle store is not, by design (RFC 12.2, 12.3 and
|
|
13
|
+
// 12.7, issue #1693): a bundle's digest covers the plan digest and the
|
|
14
|
+
// change-set digests only, not its authorization, clock, mode or verdicts, so
|
|
15
|
+
// a rerun of `plan` over an unchanged hub yields the same digest with newer
|
|
16
|
+
// bytes. Storing a bundle under a digest that already names a file replaces
|
|
17
|
+
// that file atomically with the newest computation; only that one name is
|
|
18
|
+
// touched, and superseded computations are not recorded. Admission reads a
|
|
19
|
+
// stored bundle for its digest, its plan digest and the change sets it holds,
|
|
20
|
+
// never for its authorization or verdicts, which it re-checks at apply time.
|
|
21
|
+
// A planned bundle is the exception to that replacement (issue #1708): a report
|
|
22
|
+
// never replaces a stored bundle that verifies as planned under the same
|
|
23
|
+
// digest, because a planned file records approvals a report does not, and a
|
|
24
|
+
// rerun with less (an approval no longer committed, an uncommitted plan edit)
|
|
25
|
+
// must not quietly erase them. The refusal names no path. A planned bundle
|
|
26
|
+
// replaces a report or a planned one, and a file that does not verify (any
|
|
27
|
+
// bytes that do not read back as a valid bundle of that digest) is replaced by
|
|
28
|
+
// either, since it protects nothing. Writing the same bytes again is a no-op
|
|
29
|
+
// in both stores. The change-set store has one exception to append-only (issue
|
|
30
|
+
// #1716): bindChangeSetBody records the hash of the pull request body rendered
|
|
31
|
+
// for a stored set as that set's `pullRequest.bodySha256`, the one member the
|
|
32
|
+
// digest excludes, replacing that one file atomically. It never rebinds: a set
|
|
33
|
+
// already bound to another hash is refused, and the same hash is a no-op.
|
|
34
|
+
// Binds of one set are serialised by a per-digest lock file, taken exclusively
|
|
35
|
+
// and never waited for or broken (issue #1738), and a set that changed or was
|
|
36
|
+
// removed while it was being bound is refused, never replaced or recreated.
|
|
37
|
+
// A stored file's recomputed digest proves its integrity, not
|
|
38
|
+
// its provenance: anyone who can write the hub directory can add a set that
|
|
39
|
+
// verifies, the same way anyone who can write a git object store can add a
|
|
40
|
+
// commit. A read never trusts a file
|
|
41
|
+
// merely because it parses: the document must validate against its contract,
|
|
42
|
+
// recompute to the digest the file name claims, and (for a change set) to
|
|
43
|
+
// the digest the document itself carries -- so a renamed or hand-edited file
|
|
44
|
+
// reads as absent rather than as something it no longer is.
|
|
45
|
+
//
|
|
46
|
+
// Every store directory segment, from the hub root down to change-sets/ or
|
|
47
|
+
// bundles/, is walked one lstat at a time (issue #1545 fix 5): a symbolic
|
|
48
|
+
// link anywhere in that chain is refused rather than followed, so a symlinked
|
|
49
|
+
// clossys/, .state/, apply/, change-sets/ or bundles/ can never redirect a
|
|
50
|
+
// write or a read outside the hub. Every filesystem error this module
|
|
51
|
+
// rethrows, other than ENOENT (which a read turns into null, and a write
|
|
52
|
+
// turns into directory creation), names only the failing operation and the
|
|
53
|
+
// error's code -- never a path, digest or other value a `cause` might carry.
|
|
54
|
+
//
|
|
55
|
+
// This module does I/O (mkdirSync, open/write/link/rename/read on the hub
|
|
56
|
+
// directory) and so must never be imported by plan-bundle.ts, which computes
|
|
57
|
+
// change sets and bundles without touching a filesystem.
|
|
58
|
+
import { randomBytes } from "node:crypto";
|
|
59
|
+
import { closeSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeSync } from "node:fs";
|
|
60
|
+
import { isAbsolute, join, relative, sep } from "node:path";
|
|
61
|
+
import { bundleDigest, changeSetDigest } from "./change-set-digest.js";
|
|
62
|
+
import { validateApplyBundle, validateRepositoryChangeSet } from "./change-set-contract.js";
|
|
63
|
+
import { readContractDocument } from "./generated/contract-schema.generated.js";
|
|
64
|
+
/** Where every repository change set this hub has computed is kept, one file per digest, relative to the hub root. */
|
|
65
|
+
export const CHANGE_SET_STORE_REL = "clossys/.state/apply/change-sets";
|
|
66
|
+
/** Where every apply bundle this hub has computed is kept, one file per digest, relative to the hub root. */
|
|
67
|
+
export const BUNDLE_STORE_REL = "clossys/.state/apply/bundles";
|
|
68
|
+
/** A digest as every store file is named for: `sha256:` and exactly 64 lowercase hex digits. */
|
|
69
|
+
const DIGEST_SHAPE = /^sha256:[0-9a-f]{64}$/u;
|
|
70
|
+
/** Throws before any path is built from `digest`, naming no value: only a caller that already holds a well-shaped digest may reach the store. */
|
|
71
|
+
function assertDigestShape(digest) {
|
|
72
|
+
if (!DIGEST_SHAPE.test(digest))
|
|
73
|
+
throw new TypeError("a stored digest must match sha256: followed by exactly 64 lowercase hex digits");
|
|
74
|
+
}
|
|
75
|
+
/** The file name a digest is stored under: its 64 hex digits, with no `sha256:` prefix or colon. */
|
|
76
|
+
function digestFileName(digest) {
|
|
77
|
+
return `${digest.slice("sha256:".length)}.json`;
|
|
78
|
+
}
|
|
79
|
+
/** A document's bytes as every store file holds them: two-space JSON with a final newline. */
|
|
80
|
+
function serializeStoredDocument(value) {
|
|
81
|
+
return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
82
|
+
}
|
|
83
|
+
/** Wraps a filesystem error, other than ENOENT (handled by each caller), so its message names only the failing operation and the
|
|
84
|
+
* error's code -- never a path, digest or other value; the original error is never attached as `cause`. */
|
|
85
|
+
function wrapFsError(operation, cause) {
|
|
86
|
+
const code = typeof cause === "object" && cause !== null && "code" in cause ? String(cause.code) : "unknown";
|
|
87
|
+
return new Error(`${operation} failed (${code})`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* `hubDirectory` must be an absolute path and its own real path: no symbolic
|
|
91
|
+
* link anywhere in it. Every store operation checks this first, before
|
|
92
|
+
* building any path under it.
|
|
93
|
+
*/
|
|
94
|
+
function assertHubDirectory(hubDirectory) {
|
|
95
|
+
if (!isAbsolute(hubDirectory))
|
|
96
|
+
throw new TypeError("hubDirectory must be an absolute path");
|
|
97
|
+
let real;
|
|
98
|
+
try {
|
|
99
|
+
real = realpathSync(hubDirectory);
|
|
100
|
+
}
|
|
101
|
+
catch (cause) {
|
|
102
|
+
throw wrapFsError("hub directory resolve", cause);
|
|
103
|
+
}
|
|
104
|
+
if (real !== hubDirectory)
|
|
105
|
+
throw new TypeError("hubDirectory must be its own real path, with no symbolic link in it");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Walks every path segment from `hubDirectory` down to `directory`
|
|
109
|
+
* (hubDirectory joined with a store's relative path), lstat-ing each one so a
|
|
110
|
+
* symbolic link anywhere in the chain is refused rather than followed. On a
|
|
111
|
+
* write (`mode: "write"`), a missing segment is created with a non-recursive
|
|
112
|
+
* `mkdirSync` and lstat-ed again; on a read (`mode: "read"`), a missing
|
|
113
|
+
* segment means the file being read is absent, and this returns `false`. A
|
|
114
|
+
* segment that is a symbolic link, or exists but is not a directory, throws a
|
|
115
|
+
* TypeError naming no path. Any other filesystem error is rethrown wrapped,
|
|
116
|
+
* naming only the operation and its code.
|
|
117
|
+
*/
|
|
118
|
+
function ensureRealDirectory(hubDirectory, directory, mode) {
|
|
119
|
+
const relativePath = relative(hubDirectory, directory);
|
|
120
|
+
const segments = relativePath === "" ? [] : relativePath.split(sep);
|
|
121
|
+
let current = hubDirectory;
|
|
122
|
+
for (const segment of segments) {
|
|
123
|
+
current = join(current, segment);
|
|
124
|
+
let info;
|
|
125
|
+
try {
|
|
126
|
+
info = lstatSync(current);
|
|
127
|
+
}
|
|
128
|
+
catch (cause) {
|
|
129
|
+
if (cause.code !== "ENOENT")
|
|
130
|
+
throw wrapFsError("hub store directory stat", cause);
|
|
131
|
+
if (mode === "read")
|
|
132
|
+
return false;
|
|
133
|
+
try {
|
|
134
|
+
mkdirSync(current);
|
|
135
|
+
}
|
|
136
|
+
catch (createCause) {
|
|
137
|
+
if (createCause.code !== "EEXIST")
|
|
138
|
+
throw wrapFsError("hub store directory create", createCause);
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
info = lstatSync(current);
|
|
142
|
+
}
|
|
143
|
+
catch (recheckCause) {
|
|
144
|
+
throw wrapFsError("hub store directory create", recheckCause);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (!info.isDirectory())
|
|
148
|
+
throw new TypeError("a hub store directory segment is a symbolic link or not a directory");
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Writes `bytes` under `fileName` in `hubDirectory`/`storeRel` without ever
|
|
154
|
+
* replacing an existing file: the bytes go to a temporary file in the same
|
|
155
|
+
* directory (created exclusively, flushed to disk), which is then
|
|
156
|
+
* hard-linked to the final name, so a name already taken fails the link with
|
|
157
|
+
* EEXIST rather than overwriting it. On EEXIST the existing file is
|
|
158
|
+
* lstat-ed -- a symbolic link there is refused -- then re-read: identical
|
|
159
|
+
* bytes is a no-op; when `equivalent` says the existing and incoming
|
|
160
|
+
* documents validate to the same digest the name claims, that is a no-op
|
|
161
|
+
* too; and any other different bytes is refused. The temporary file is
|
|
162
|
+
* always removed. Every store directory segment is a real directory, never a
|
|
163
|
+
* symbolic link (see `ensureRealDirectory()`). Returns the final path.
|
|
164
|
+
*/
|
|
165
|
+
/** When both buffers are valid stored change sets for `digest`, true; when existing bytes do not validate to that digest, false. */
|
|
166
|
+
function storedChangeSetsShareDigest(existing, incoming, digest) {
|
|
167
|
+
const digestOf = (buf) => {
|
|
168
|
+
try {
|
|
169
|
+
const document = readContractDocument(buf);
|
|
170
|
+
if (!validateRepositoryChangeSet(document).valid)
|
|
171
|
+
return null;
|
|
172
|
+
const set = document;
|
|
173
|
+
const recomputed = changeSetDigest(set);
|
|
174
|
+
if (recomputed !== set.changeSetDigest || recomputed !== digest)
|
|
175
|
+
return null;
|
|
176
|
+
return recomputed;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const left = digestOf(existing);
|
|
183
|
+
const right = digestOf(incoming);
|
|
184
|
+
return left !== null && right !== null && left === right;
|
|
185
|
+
}
|
|
186
|
+
function writeAppendOnly(hubDirectory, storeRel, fileName, bytes, equivalent) {
|
|
187
|
+
assertHubDirectory(hubDirectory);
|
|
188
|
+
const directory = join(hubDirectory, storeRel);
|
|
189
|
+
ensureRealDirectory(hubDirectory, directory, "write");
|
|
190
|
+
const finalPath = join(directory, fileName);
|
|
191
|
+
const temporaryPath = join(directory, `.${fileName}.${randomBytes(8).toString("hex")}.tmp`);
|
|
192
|
+
let descriptor;
|
|
193
|
+
try {
|
|
194
|
+
try {
|
|
195
|
+
descriptor = openSync(temporaryPath, "wx", 0o644);
|
|
196
|
+
}
|
|
197
|
+
catch (cause) {
|
|
198
|
+
throw wrapFsError("hub store write", cause);
|
|
199
|
+
}
|
|
200
|
+
let written = 0;
|
|
201
|
+
try {
|
|
202
|
+
while (written < bytes.length)
|
|
203
|
+
written += writeSync(descriptor, bytes, written, bytes.length - written);
|
|
204
|
+
fsyncSync(descriptor);
|
|
205
|
+
closeSync(descriptor);
|
|
206
|
+
}
|
|
207
|
+
catch (cause) {
|
|
208
|
+
throw wrapFsError("hub store write", cause);
|
|
209
|
+
}
|
|
210
|
+
descriptor = undefined;
|
|
211
|
+
try {
|
|
212
|
+
linkSync(temporaryPath, finalPath);
|
|
213
|
+
}
|
|
214
|
+
catch (cause) {
|
|
215
|
+
if (cause.code !== "EEXIST")
|
|
216
|
+
throw wrapFsError("hub store write", cause);
|
|
217
|
+
let info;
|
|
218
|
+
try {
|
|
219
|
+
info = lstatSync(finalPath);
|
|
220
|
+
}
|
|
221
|
+
catch (statCause) {
|
|
222
|
+
throw wrapFsError("hub store write", statCause);
|
|
223
|
+
}
|
|
224
|
+
if (!info.isFile())
|
|
225
|
+
throw new TypeError("a hub store file name is occupied by a symbolic link or a non-regular file");
|
|
226
|
+
let existing;
|
|
227
|
+
try {
|
|
228
|
+
existing = readFileSync(finalPath);
|
|
229
|
+
}
|
|
230
|
+
catch (readCause) {
|
|
231
|
+
throw wrapFsError("hub store write", readCause);
|
|
232
|
+
}
|
|
233
|
+
if (!existing.equals(bytes) && !equivalent?.(existing, bytes)) {
|
|
234
|
+
throw new TypeError("this digest already names a stored document with different bytes; the store is append-only");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
if (descriptor !== undefined) {
|
|
240
|
+
try {
|
|
241
|
+
closeSync(descriptor);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Already failing; the original error is the one reported.
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
rmSync(temporaryPath, { force: true });
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Best-effort cleanup; the original error (or success) is what is reported.
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return finalPath;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Stores `bytes` under `fileName` in `hubDirectory`/`storeRel`, replacing
|
|
258
|
+
* whatever regular file already holds that one name (unless `refuseOver` says
|
|
259
|
+
* the file as it is now must not be replaced, which throws its message; with
|
|
260
|
+
* `refuseOver.whenMissing` a name that holds no file is refused the same way
|
|
261
|
+
* instead of being created, for a caller that read the file first and must not
|
|
262
|
+
* recreate one removed since): the bytes go to a
|
|
263
|
+
* temporary file in the same real directory (created exclusively, flushed to
|
|
264
|
+
* disk), which is then renamed over the final name, so a reader sees the old
|
|
265
|
+
* file or the new one and never a partial file, and an interrupted write
|
|
266
|
+
* leaves at most a temporary file under another name. Identical existing
|
|
267
|
+
* bytes are a no-op and write nothing. A name held by a symbolic link or any
|
|
268
|
+
* other non-regular file is refused before anything is written. Every store
|
|
269
|
+
* directory segment is a real directory, never a symbolic link (see
|
|
270
|
+
* `ensureRealDirectory()`). The temporary file is always removed. Returns the
|
|
271
|
+
* final path.
|
|
272
|
+
*/
|
|
273
|
+
function writeReplacing(hubDirectory, storeRel, fileName, bytes, refuseOver) {
|
|
274
|
+
assertHubDirectory(hubDirectory);
|
|
275
|
+
const directory = join(hubDirectory, storeRel);
|
|
276
|
+
ensureRealDirectory(hubDirectory, directory, "write");
|
|
277
|
+
const finalPath = join(directory, fileName);
|
|
278
|
+
let occupied = true;
|
|
279
|
+
try {
|
|
280
|
+
const info = lstatSync(finalPath);
|
|
281
|
+
if (!info.isFile())
|
|
282
|
+
throw new TypeError("a hub store file name is occupied by a symbolic link or a non-regular file");
|
|
283
|
+
}
|
|
284
|
+
catch (cause) {
|
|
285
|
+
if (cause instanceof TypeError)
|
|
286
|
+
throw cause;
|
|
287
|
+
if (cause.code !== "ENOENT")
|
|
288
|
+
throw wrapFsError("hub store write", cause);
|
|
289
|
+
if (refuseOver?.whenMissing === true)
|
|
290
|
+
throw new TypeError(refuseOver.message);
|
|
291
|
+
occupied = false;
|
|
292
|
+
}
|
|
293
|
+
if (occupied) {
|
|
294
|
+
let existing;
|
|
295
|
+
try {
|
|
296
|
+
existing = readFileSync(finalPath);
|
|
297
|
+
}
|
|
298
|
+
catch (cause) {
|
|
299
|
+
throw wrapFsError("hub store write", cause);
|
|
300
|
+
}
|
|
301
|
+
if (refuseOver?.when(existing) === true)
|
|
302
|
+
throw new TypeError(refuseOver.message);
|
|
303
|
+
if (existing.equals(bytes))
|
|
304
|
+
return finalPath;
|
|
305
|
+
}
|
|
306
|
+
const temporaryPath = join(directory, `.${fileName}.${randomBytes(8).toString("hex")}.tmp`);
|
|
307
|
+
let descriptor;
|
|
308
|
+
try {
|
|
309
|
+
try {
|
|
310
|
+
descriptor = openSync(temporaryPath, "wx", 0o644);
|
|
311
|
+
}
|
|
312
|
+
catch (cause) {
|
|
313
|
+
throw wrapFsError("hub store write", cause);
|
|
314
|
+
}
|
|
315
|
+
let written = 0;
|
|
316
|
+
try {
|
|
317
|
+
while (written < bytes.length)
|
|
318
|
+
written += writeSync(descriptor, bytes, written, bytes.length - written);
|
|
319
|
+
fsyncSync(descriptor);
|
|
320
|
+
closeSync(descriptor);
|
|
321
|
+
}
|
|
322
|
+
catch (cause) {
|
|
323
|
+
throw wrapFsError("hub store write", cause);
|
|
324
|
+
}
|
|
325
|
+
descriptor = undefined;
|
|
326
|
+
try {
|
|
327
|
+
renameSync(temporaryPath, finalPath);
|
|
328
|
+
}
|
|
329
|
+
catch (cause) {
|
|
330
|
+
throw wrapFsError("hub store write", cause);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
if (descriptor !== undefined) {
|
|
335
|
+
try {
|
|
336
|
+
closeSync(descriptor);
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
// Already failing; the original error is the one reported.
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
rmSync(temporaryPath, { force: true });
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// Best-effort cleanup; the original error (or success) is what is reported.
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return finalPath;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Reads and re-reads bytes stored at `hubDirectory`/`storeRel`/`fileName`,
|
|
353
|
+
* strictly: a missing store directory or a missing file reads as `null`, and
|
|
354
|
+
* bytes that are not exactly one strict-JSON value also read as `null`
|
|
355
|
+
* (never thrown), because a store read never trusts a file merely because
|
|
356
|
+
* something is there. Every store directory segment down to `storeRel` is
|
|
357
|
+
* checked to be a real directory, never a symbolic link (see
|
|
358
|
+
* `ensureRealDirectory()`); a symbolic link found there throws rather than
|
|
359
|
+
* being followed.
|
|
360
|
+
*/
|
|
361
|
+
function readStoredBytes(hubDirectory, storeRel, fileName) {
|
|
362
|
+
assertHubDirectory(hubDirectory);
|
|
363
|
+
const directory = join(hubDirectory, storeRel);
|
|
364
|
+
if (!ensureRealDirectory(hubDirectory, directory, "read"))
|
|
365
|
+
return null;
|
|
366
|
+
const path = join(directory, fileName);
|
|
367
|
+
let bytes;
|
|
368
|
+
try {
|
|
369
|
+
bytes = readFileSync(path);
|
|
370
|
+
}
|
|
371
|
+
catch (cause) {
|
|
372
|
+
if (cause.code === "ENOENT")
|
|
373
|
+
return null;
|
|
374
|
+
throw wrapFsError("hub store read", cause);
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
return readContractDocument(bytes);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Stores `set` under `hubDirectory`/CHANGE_SET_STORE_REL, named for its own
|
|
385
|
+
* `changeSetDigest`. Throws a TypeError, naming no path, id or value, when
|
|
386
|
+
* the set does not validate against the change-set contract, when its
|
|
387
|
+
* `changeSetDigest` is not `changeSetDigest(set)`, or when that name is
|
|
388
|
+
* already taken by different bytes (the store is append-only). Storing the
|
|
389
|
+
* same set again, byte for byte, is a no-op; so is storing another document
|
|
390
|
+
* that validates to the same changeSetDigest. Returns the file's path.
|
|
391
|
+
*/
|
|
392
|
+
export function storeChangeSet(hubDirectory, set) {
|
|
393
|
+
const validation = validateRepositoryChangeSet(set);
|
|
394
|
+
if (!validation.valid)
|
|
395
|
+
throw new TypeError(`a change set must validate against its contract before it can be stored: ${validation.reason}`);
|
|
396
|
+
if (set.changeSetDigest !== changeSetDigest(set))
|
|
397
|
+
throw new TypeError("a change set's changeSetDigest must equal changeSetDigest(set) before it can be stored");
|
|
398
|
+
assertDigestShape(set.changeSetDigest);
|
|
399
|
+
const digest = set.changeSetDigest;
|
|
400
|
+
return writeAppendOnly(hubDirectory, CHANGE_SET_STORE_REL, digestFileName(digest), serializeStoredDocument(set), (existing, incoming) => storedChangeSetsShareDigest(existing, incoming, digest));
|
|
401
|
+
}
|
|
402
|
+
/** Thrown by bindChangeSetBody when the stored set is already bound to another body. Names no path, digest or hash. */
|
|
403
|
+
export class BodyBoundError extends TypeError {
|
|
404
|
+
constructor() {
|
|
405
|
+
super("this stored change set is already bound to another pull request body");
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Records `bodySha256`, the hash of the pull request body rendered for the
|
|
410
|
+
* change set stored under `digest` (issue #1716), as that set's
|
|
411
|
+
* `pullRequest.bodySha256` -- the one member it changes. The digest excludes
|
|
412
|
+
* that member, so the file's name and every digest stay as they were. The set
|
|
413
|
+
* is read here, from the store, and must verify exactly as readStoredChangeSet
|
|
414
|
+
* verifies it; a set that is not stored, or does not verify, is a TypeError.
|
|
415
|
+
* A set already bound to the same hash is a no-op that writes nothing; one
|
|
416
|
+
* bound to another hash throws BodyBoundError and is left as it was: a bound
|
|
417
|
+
* body is never rebound, and storeChangeSet never replaces a stored set, so it
|
|
418
|
+
* cannot unbind one either. The write replaces only that one file, atomically
|
|
419
|
+
* (a temporary file in the same directory, renamed over the name), and is
|
|
420
|
+
* refused when the file is not the bytes that were read, a symbolic link or not
|
|
421
|
+
* a regular file, or when a store directory segment is a symbolic link. Every
|
|
422
|
+
* error names no path, digest or hash, and no other file is touched. Returns
|
|
423
|
+
* the file's path.
|
|
424
|
+
*
|
|
425
|
+
* Two binds of one set are serialised by a per-digest lock (issue #1738): a
|
|
426
|
+
* dot-prefixed file in the change-sets directory, created exclusively before
|
|
427
|
+
* the set is first read and removed once this call is done, only by the call
|
|
428
|
+
* that created it. A bind that finds the lock already held throws a TypeError
|
|
429
|
+
* and changes nothing, so of two binds with different hashes exactly one
|
|
430
|
+
* renames; it never waits and never breaks a lock. A crash mid-bind leaves the
|
|
431
|
+
* lock, and later binds of that set then refuse (fails closed). A set removed
|
|
432
|
+
* after this call read it is refused rather than written again already bound.
|
|
433
|
+
*/
|
|
434
|
+
export function bindChangeSetBody(hubDirectory, digest, bodySha256) {
|
|
435
|
+
assertDigestShape(digest);
|
|
436
|
+
if (typeof bodySha256 !== "string" || !DIGEST_SHAPE.test(bodySha256))
|
|
437
|
+
throw new TypeError("a body hash must match sha256: followed by exactly 64 lowercase hex digits");
|
|
438
|
+
assertHubDirectory(hubDirectory);
|
|
439
|
+
const directory = join(hubDirectory, CHANGE_SET_STORE_REL);
|
|
440
|
+
const absent = () => new TypeError("no verified change set is stored under this digest");
|
|
441
|
+
if (!ensureRealDirectory(hubDirectory, directory, "read"))
|
|
442
|
+
throw absent();
|
|
443
|
+
const fileName = digestFileName(digest);
|
|
444
|
+
const path = join(directory, fileName);
|
|
445
|
+
const lockPath = join(directory, `.${fileName}.bind.lock`);
|
|
446
|
+
let lockDescriptor;
|
|
447
|
+
try {
|
|
448
|
+
lockDescriptor = openSync(lockPath, "wx", 0o600);
|
|
449
|
+
}
|
|
450
|
+
catch (cause) {
|
|
451
|
+
if (cause.code === "EEXIST")
|
|
452
|
+
throw new TypeError("this stored change set is being bound by another call, or an earlier bind of it did not finish");
|
|
453
|
+
throw wrapFsError("hub store write", cause);
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
try {
|
|
457
|
+
closeSync(lockDescriptor);
|
|
458
|
+
}
|
|
459
|
+
catch (cause) {
|
|
460
|
+
throw wrapFsError("hub store write", cause);
|
|
461
|
+
}
|
|
462
|
+
return bindLocked(hubDirectory, digest, bodySha256, directory, fileName, path, absent);
|
|
463
|
+
}
|
|
464
|
+
finally {
|
|
465
|
+
try {
|
|
466
|
+
rmSync(lockPath, { force: true });
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
// Best-effort; a lock left behind makes later binds of this set refuse, which fails closed.
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/** The body of bindChangeSetBody once the per-digest lock is held: read, verify, and replace the one file. */
|
|
474
|
+
function bindLocked(hubDirectory, digest, bodySha256, directory, fileName, path, absent) {
|
|
475
|
+
let info;
|
|
476
|
+
try {
|
|
477
|
+
info = lstatSync(path);
|
|
478
|
+
}
|
|
479
|
+
catch (cause) {
|
|
480
|
+
if (cause.code === "ENOENT")
|
|
481
|
+
throw absent();
|
|
482
|
+
throw wrapFsError("hub store read", cause);
|
|
483
|
+
}
|
|
484
|
+
if (!info.isFile())
|
|
485
|
+
throw new TypeError("a hub store file name is occupied by a symbolic link or a non-regular file");
|
|
486
|
+
let existing;
|
|
487
|
+
try {
|
|
488
|
+
existing = readFileSync(path);
|
|
489
|
+
}
|
|
490
|
+
catch (cause) {
|
|
491
|
+
throw wrapFsError("hub store read", cause);
|
|
492
|
+
}
|
|
493
|
+
let document;
|
|
494
|
+
try {
|
|
495
|
+
document = readContractDocument(existing);
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
throw absent();
|
|
499
|
+
}
|
|
500
|
+
if (!validateRepositoryChangeSet(document).valid)
|
|
501
|
+
throw absent();
|
|
502
|
+
const set = document;
|
|
503
|
+
const recomputed = changeSetDigest(set);
|
|
504
|
+
if (recomputed !== set.changeSetDigest || recomputed !== digest)
|
|
505
|
+
throw absent();
|
|
506
|
+
const current = set.pullRequest.bodySha256;
|
|
507
|
+
if (current === bodySha256)
|
|
508
|
+
return path;
|
|
509
|
+
if (current !== undefined)
|
|
510
|
+
throw new BodyBoundError();
|
|
511
|
+
const next = { ...set, pullRequest: { ...set.pullRequest, bodySha256 } };
|
|
512
|
+
if (!validateRepositoryChangeSet(next).valid || changeSetDigest(next) !== digest)
|
|
513
|
+
throw new TypeError("a change set must still validate, under its own digest, once its body is bound");
|
|
514
|
+
return writeReplacing(hubDirectory, CHANGE_SET_STORE_REL, fileName, serializeStoredDocument(next), {
|
|
515
|
+
when: (now) => !now.equals(existing),
|
|
516
|
+
message: "the stored change set changed while its body was being bound",
|
|
517
|
+
whenMissing: true,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Stores `bundle` under `hubDirectory`/BUNDLE_STORE_REL, named for its own
|
|
522
|
+
* `bundleDigest`. Throws a TypeError, naming no path, id or value, when the
|
|
523
|
+
* bundle does not validate against the apply-bundle contract, when the
|
|
524
|
+
* digest is malformed, or when a store directory segment or the file name is
|
|
525
|
+
* a symbolic link; nothing is written or replaced in those cases. The digest
|
|
526
|
+
* excludes the authorization, the clock, the mode and the verdicts (RFC
|
|
527
|
+
* 12.3), so a bundle whose digest already names a stored file replaces that
|
|
528
|
+
* one file atomically with these bytes, the newest computation; the same
|
|
529
|
+
* bytes again are a no-op. A report bundle never replaces a stored file that
|
|
530
|
+
* verifies as a planned bundle of this digest (a TypeError, naming no path);
|
|
531
|
+
* a planned bundle replaces anything. A bundle with any other digest never
|
|
532
|
+
* touches another file. Superseded computations are not recorded. Returns the
|
|
533
|
+
* file's path.
|
|
534
|
+
*/
|
|
535
|
+
export function storeApplyBundle(hubDirectory, bundle) {
|
|
536
|
+
const validation = validateApplyBundle(bundle);
|
|
537
|
+
if (!validation.valid)
|
|
538
|
+
throw new TypeError(`an apply bundle must validate against its contract before it can be stored: ${validation.reason}`);
|
|
539
|
+
assertDigestShape(bundle.bundleDigest);
|
|
540
|
+
const digest = bundle.bundleDigest;
|
|
541
|
+
return writeReplacing(hubDirectory, BUNDLE_STORE_REL, digestFileName(digest), serializeStoredDocument(bundle), bundle.mode === "report" ? { when: (existing) => verifiesAsPlanned(existing, digest), message: "a stored planned apply bundle is never replaced by a report of the same digest" } : undefined);
|
|
542
|
+
}
|
|
543
|
+
/** Whether `bytes` read back as a valid, digest-verified apply bundle of `digest` whose mode is planned: exactly what a read would return. */
|
|
544
|
+
function verifiesAsPlanned(bytes, digest) {
|
|
545
|
+
let document;
|
|
546
|
+
try {
|
|
547
|
+
document = readContractDocument(bytes);
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
return verifiedBundle(document, digest)?.mode === "planned";
|
|
553
|
+
}
|
|
554
|
+
/** The document as a bundle when it validates and its digest, recomputed from the plan digest and each computed repository, is `digest` and its own. */
|
|
555
|
+
function verifiedBundle(document, digest) {
|
|
556
|
+
if (!validateApplyBundle(document).valid)
|
|
557
|
+
return null;
|
|
558
|
+
const bundle = document;
|
|
559
|
+
const computed = bundle.repositories.flatMap((entry) => "changeSet" in entry ? [{ id: entry.id, changeSetDigest: entry.changeSet }] : []);
|
|
560
|
+
const recomputed = bundleDigest(bundle.plan.digest, computed);
|
|
561
|
+
return recomputed === bundle.bundleDigest && recomputed === digest ? bundle : null;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Reads the change set stored for `digest` under `hubDirectory`/CHANGE_SET_STORE_REL.
|
|
565
|
+
* `digest` must match `sha256:` and 64 lowercase hex digits before any path
|
|
566
|
+
* is built from it; a malformed digest throws a TypeError naming no value,
|
|
567
|
+
* before touching the filesystem. Otherwise: a missing file, bytes that are
|
|
568
|
+
* not strict JSON, a document that does not validate against the change-set
|
|
569
|
+
* contract, or one whose `changeSetDigest` -- recomputed and read from the
|
|
570
|
+
* document -- does not equal both `digest` and the document's own
|
|
571
|
+
* `changeSetDigest`, all read as `null`. A file can therefore never be read
|
|
572
|
+
* back under a name, or with content, other than its own digest.
|
|
573
|
+
*/
|
|
574
|
+
/**
|
|
575
|
+
* Every change set stored under `hubDirectory`/CHANGE_SET_STORE_REL whose file
|
|
576
|
+
* name is 64 lowercase hex digits and `.json`, in directory listing order.
|
|
577
|
+
* Entries that do not read back as a valid stored set are omitted.
|
|
578
|
+
*/
|
|
579
|
+
export function listStoredChangeSets(hubDirectory) {
|
|
580
|
+
assertHubDirectory(hubDirectory);
|
|
581
|
+
const directory = join(hubDirectory, CHANGE_SET_STORE_REL);
|
|
582
|
+
if (!ensureRealDirectory(hubDirectory, directory, "read"))
|
|
583
|
+
return [];
|
|
584
|
+
const sets = [];
|
|
585
|
+
for (const name of readdirSync(directory)) {
|
|
586
|
+
if (!/^[0-9a-f]{64}\.json$/u.test(name))
|
|
587
|
+
continue;
|
|
588
|
+
const set = readStoredChangeSet(hubDirectory, `sha256:${name.slice(0, 64)}`);
|
|
589
|
+
if (set !== null)
|
|
590
|
+
sets.push(set);
|
|
591
|
+
}
|
|
592
|
+
return sets;
|
|
593
|
+
}
|
|
594
|
+
export function readStoredChangeSet(hubDirectory, digest) {
|
|
595
|
+
assertDigestShape(digest);
|
|
596
|
+
const document = readStoredBytes(hubDirectory, CHANGE_SET_STORE_REL, digestFileName(digest));
|
|
597
|
+
if (document === null)
|
|
598
|
+
return null;
|
|
599
|
+
if (!validateRepositoryChangeSet(document).valid)
|
|
600
|
+
return null;
|
|
601
|
+
const set = document;
|
|
602
|
+
const recomputed = changeSetDigest(set);
|
|
603
|
+
if (recomputed !== set.changeSetDigest || recomputed !== digest)
|
|
604
|
+
return null;
|
|
605
|
+
return set;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Reads the apply bundle stored for `digest` under `hubDirectory`/BUNDLE_STORE_REL.
|
|
609
|
+
* `digest` must match `sha256:` and 64 lowercase hex digits before any path
|
|
610
|
+
* is built from it; a malformed digest throws a TypeError naming no value,
|
|
611
|
+
* before touching the filesystem. Otherwise: a missing file, bytes that are
|
|
612
|
+
* not strict JSON, a document that does not validate against the
|
|
613
|
+
* apply-bundle contract, or one whose bundle digest -- recomputed from its
|
|
614
|
+
* `plan.digest` and each repository that carries a change set, in the same
|
|
615
|
+
* order applyBundleRuleViolations' A2 rule computes it -- does not equal
|
|
616
|
+
* both `digest` and the document's own `bundleDigest`, all read as `null`.
|
|
617
|
+
*/
|
|
618
|
+
export function readStoredApplyBundle(hubDirectory, digest) {
|
|
619
|
+
assertDigestShape(digest);
|
|
620
|
+
const document = readStoredBytes(hubDirectory, BUNDLE_STORE_REL, digestFileName(digest));
|
|
621
|
+
if (document === null)
|
|
622
|
+
return null;
|
|
623
|
+
return verifiedBundle(document, digest);
|
|
624
|
+
}
|
|
625
|
+
//# sourceMappingURL=apply-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-store.js","sourceRoot":"","sources":["../src/apply-store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+GAA+G;AAC/G,qEAAqE;AACrE,4EAA4E;AAC5E,6EAA6E;AAC7E,sCAAsC;AACtC,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,2EAA2E;AAC3E,uEAAuE;AACvE,8EAA8E;AAC9E,4EAA4E;AAC5E,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,8EAA8E;AAC9E,6EAA6E;AAC7E,gFAAgF;AAChF,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;AAC1E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,8DAA8D;AAC9D,4EAA4E;AAC5E,2EAA2E;AAC3E,qCAAqC;AACrC,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,4DAA4D;AAC5D,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,sEAAsE;AACtE,yEAAyE;AACzE,2EAA2E;AAC3E,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,yDAAyD;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjK,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEhF,sHAAsH;AACtH,MAAM,CAAC,MAAM,oBAAoB,GAAG,kCAAkC,CAAC;AAEvE,6GAA6G;AAC7G,MAAM,CAAC,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AAE/D,gGAAgG;AAChG,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C,iJAAiJ;AACjJ,SAAS,iBAAiB,CAAC,MAAc;IACvC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,gFAAgF,CAAC,CAAC;AACxI,CAAC;AAED,oGAAoG;AACpG,SAAS,cAAc,CAAC,MAAc;IACpC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;AAClD,CAAC;AAED,8FAA8F;AAC9F,SAAS,uBAAuB,CAAC,KAAc;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpE,CAAC;AAED;2GAC2G;AAC3G,SAAS,WAAW,CAAC,SAAiB,EAAE,KAAc;IACpD,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAE,KAA+B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxI,OAAO,IAAI,KAAK,CAAC,GAAG,SAAS,YAAY,IAAI,GAAG,CAAC,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,YAAoB;IAC9C,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC5F,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,WAAW,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,IAAI,KAAK,YAAY;QAAE,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;AACxH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,mBAAmB,CAAC,YAAoB,EAAE,SAAiB,EAAE,IAAsB;IAC1F,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpE,IAAI,OAAO,GAAG,YAAY,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC;QACT,IAAI,CAAC;YACH,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,WAAW,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAC7G,IAAI,IAAI,KAAK,MAAM;gBAAE,OAAO,KAAK,CAAC;YAClC,IAAI,CAAC;gBACH,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;YAAC,OAAO,WAAW,EAAE,CAAC;gBACrB,IAAK,WAAqC,CAAC,IAAI,KAAK,QAAQ;oBAAE,MAAM,WAAW,CAAC,4BAA4B,EAAE,WAAW,CAAC,CAAC;YAC7H,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,YAAY,EAAE,CAAC;gBACtB,MAAM,WAAW,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;IACtH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,oIAAoI;AACpI,SAAS,2BAA2B,CAAC,QAAgB,EAAE,QAAgB,EAAE,MAAc;IACrF,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAiB,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC9D,MAAM,GAAG,GAAG,QAA+B,CAAC;YAC5C,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,UAAU,KAAK,GAAG,CAAC,eAAe,IAAI,UAAU,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC;YAC7E,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC;AAC3D,CAAC;AAED,SAAS,eAAe,CAAC,YAAoB,EAAE,QAAgB,EAAE,QAAgB,EAAE,KAAa,EAAE,UAA4D;IAC5J,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC/C,mBAAmB,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,IAAI,CAAC;YACH,UAAU,GAAG,QAAQ,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,OAAO,GAAG,KAAK,CAAC,MAAM;gBAAE,OAAO,IAAI,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;YACxG,SAAS,CAAC,UAAU,CAAC,CAAC;YACtB,SAAS,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,UAAU,GAAG,SAAS,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;YACpG,IAAI,IAAI,CAAC;YACT,IAAI,CAAC;gBACH,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;YAC9B,CAAC;YAAC,OAAO,SAAS,EAAE,CAAC;gBACnB,MAAM,WAAW,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,CAAC,CAAC;YACtH,IAAI,QAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YACrC,CAAC;YAAC,OAAO,SAAS,EAAE,CAAC;gBACnB,MAAM,WAAW,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,SAAS,CAAC,4FAA4F,CAAC,CAAC;YACpH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,SAAS,CAAC,UAAU,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,2DAA2D;YAC7D,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,cAAc,CAAC,YAAoB,EAAE,QAAgB,EAAE,QAAgB,EAAE,KAAa,EAAE,UAAuH;IACtN,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC/C,mBAAmB,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC5C,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,CAAC,CAAC;IACxH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,SAAS;YAAE,MAAM,KAAK,CAAC;QAC5C,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QACpG,IAAI,UAAU,EAAE,WAAW,KAAK,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC9E,QAAQ,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACjF,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;IAC/C,CAAC;IACD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,IAAI,CAAC;YACH,UAAU,GAAG,QAAQ,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,OAAO,GAAG,KAAK,CAAC,MAAM;gBAAE,OAAO,IAAI,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;YACxG,SAAS,CAAC,UAAU,CAAC,CAAC;YACtB,SAAS,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,UAAU,GAAG,SAAS,CAAC;QACvB,IAAI,CAAC;YACH,UAAU,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,SAAS,CAAC,UAAU,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,2DAA2D;YAC7D,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,eAAe,CAAC,YAAoB,EAAE,QAAgB,EAAE,QAAgB;IAC/E,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACpE,MAAM,WAAW,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC;QACH,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,GAAwB;IAC3E,MAAM,UAAU,GAAG,2BAA2B,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,CAAC,KAAK;QAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5I,IAAI,GAAG,CAAC,eAAe,KAAK,eAAe,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,wFAAwF,CAAC,CAAC;IAChK,iBAAiB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC;IACnC,OAAO,eAAe,CACpB,YAAY,EACZ,oBAAoB,EACpB,cAAc,CAAC,MAAM,CAAC,EACtB,uBAAuB,CAAC,GAAG,CAAC,EAC5B,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAChF,CAAC;AACJ,CAAC;AAED,uHAAuH;AACvH,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C;QACE,KAAK,CAAC,sEAAsE,CAAC,CAAC;IAChF,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAoB,EAAE,MAAc,EAAE,UAAkB;IACxF,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,CAAC,CAAC;IACxK,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAc,EAAE,CAAC,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;IACpG,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC;QAAE,MAAM,MAAM,EAAE,CAAC;IAC1E,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,QAAQ,YAAY,CAAC,CAAC;IAC3D,IAAI,cAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,cAAc,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,SAAS,CAAC,gGAAgG,CAAC,CAAC;QAC9K,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC;QACH,IAAI,CAAC;YACH,SAAS,CAAC,cAAc,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzF,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,4FAA4F;QAC9F,CAAC;IACH,CAAC;AACH,CAAC;AAED,8GAA8G;AAC9G,SAAS,UAAU,CAAC,YAAoB,EAAE,MAAc,EAAE,UAAkB,EAAE,SAAiB,EAAE,QAAgB,EAAE,IAAY,EAAE,MAAuB;IACtJ,IAAI,IAAI,CAAC;IACT,IAAI,CAAC;QACH,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,MAAM,EAAE,CAAC;QACvE,MAAM,WAAW,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,CAAC,CAAC;IACtH,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,WAAW,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,MAAM,EAAE,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,KAAK;QAAE,MAAM,MAAM,EAAE,CAAC;IACjE,MAAM,GAAG,GAAG,QAA+B,CAAC;IAC5C,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,UAAU,KAAK,GAAG,CAAC,eAAe,IAAI,UAAU,KAAK,MAAM;QAAE,MAAM,MAAM,EAAE,CAAC;IAChF,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC;IAC3C,IAAI,OAAO,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,OAAO,KAAK,SAAS;QAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IACtD,MAAM,IAAI,GAAwB,EAAE,GAAG,GAAG,EAAE,WAAW,EAAE,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,CAAC;IAC9F,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,SAAS,CAAC,gFAAgF,CAAC,CAAC;IACxL,OAAO,cAAc,CAAC,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAAE;QACjG,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QACpC,OAAO,EAAE,8DAA8D;QACvE,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB,EAAE,MAAmB;IACxE,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,KAAK;QAAE,MAAM,IAAI,SAAS,CAAC,+EAA+E,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/I,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;IACnC,OAAO,cAAc,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,gFAAgF,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChT,CAAC;AAED,8IAA8I;AAC9I,SAAS,iBAAiB,CAAC,KAAa,EAAE,MAAc;IACtD,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,IAAI,KAAK,SAAS,CAAC;AAC9D,CAAC;AAED,wJAAwJ;AACxJ,SAAS,cAAc,CAAC,QAAiB,EAAE,MAAc;IACvD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,MAAM,GAAG,QAAuB,CAAC;IACvC,MAAM,QAAQ,GAAgE,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,KAA4B,EAAE,EAAE,CACzI,WAAW,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CACjF,CAAC;IACF,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO,UAAU,KAAK,MAAM,CAAC,YAAY,IAAI,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACrF,CAAC;AAED;;;;;;;;;;GAUG;AACH;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,YAAoB;IACvD,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IAC3D,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACrE,MAAM,IAAI,GAA0B,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAClD,MAAM,GAAG,GAAG,mBAAmB,CAAC,YAAY,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7E,IAAI,GAAG,KAAK,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,YAAoB,EAAE,MAAc;IACtE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,eAAe,CAAC,YAAY,EAAE,oBAAoB,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7F,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,GAAG,GAAG,QAA+B,CAAC;IAC5C,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,UAAU,KAAK,GAAG,CAAC,eAAe,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB,EAAE,MAAc;IACxE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,eAAe,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC"}
|