@openge/forge-release-vercel 0.2.0 → 0.3.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 +13 -7
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/node/managed-budget.d.ts +2 -1
- package/dist/node/managed-budget.d.ts.map +1 -1
- package/dist/node/managed-budget.js +4 -2
- package/dist/node/managed-budget.js.map +1 -1
- package/dist/node/managed-closure.d.ts +2 -0
- package/dist/node/managed-closure.d.ts.map +1 -1
- package/dist/node/managed-closure.js +11 -0
- package/dist/node/managed-closure.js.map +1 -1
- package/dist/node/managed-disposition.d.ts +36 -0
- package/dist/node/managed-disposition.d.ts.map +1 -0
- package/dist/node/managed-disposition.js +114 -0
- package/dist/node/managed-disposition.js.map +1 -0
- package/dist/node/managed-history.d.ts +6 -0
- package/dist/node/managed-history.d.ts.map +1 -0
- package/dist/node/managed-history.js +48 -0
- package/dist/node/managed-history.js.map +1 -0
- package/dist/node/managed-io.d.ts +2 -2
- package/dist/node/managed-io.d.ts.map +1 -1
- package/dist/node/managed-io.js +25 -8
- package/dist/node/managed-io.js.map +1 -1
- package/dist/node/managed-metadata.d.ts +12 -0
- package/dist/node/managed-metadata.d.ts.map +1 -0
- package/dist/node/managed-metadata.js +73 -0
- package/dist/node/managed-metadata.js.map +1 -0
- package/dist/node/managed-paths.d.ts.map +1 -1
- package/dist/node/managed-paths.js +13 -5
- package/dist/node/managed-paths.js.map +1 -1
- package/dist/node/managed-process.d.ts.map +1 -1
- package/dist/node/managed-process.js +47 -13
- package/dist/node/managed-process.js.map +1 -1
- package/dist/node/managed-recovery-lock.d.ts +1 -1
- package/dist/node/managed-recovery-lock.d.ts.map +1 -1
- package/dist/node/managed-recovery-lock.js +28 -7
- package/dist/node/managed-recovery-lock.js.map +1 -1
- package/dist/node/managed-recovery.d.ts +2 -0
- package/dist/node/managed-recovery.d.ts.map +1 -1
- package/dist/node/managed-recovery.js +73 -65
- package/dist/node/managed-recovery.js.map +1 -1
- package/dist/node/managed-release.d.ts.map +1 -1
- package/dist/node/managed-release.js +18 -3
- package/dist/node/managed-release.js.map +1 -1
- package/dist/node/managed-remote-state.d.ts +8 -0
- package/dist/node/managed-remote-state.d.ts.map +1 -0
- package/dist/node/managed-remote-state.js +63 -0
- package/dist/node/managed-remote-state.js.map +1 -0
- package/dist/node/managed-retirement.d.ts.map +1 -1
- package/dist/node/managed-retirement.js +2 -8
- package/dist/node/managed-retirement.js.map +1 -1
- package/dist/node/managed-state.d.ts.map +1 -1
- package/dist/node/managed-state.js +26 -5
- package/dist/node/managed-state.js.map +1 -1
- package/dist/node/managed-terminal.d.ts +42 -0
- package/dist/node/managed-terminal.d.ts.map +1 -0
- package/dist/node/managed-terminal.js +163 -0
- package/dist/node/managed-terminal.js.map +1 -0
- package/dist/node/publication.d.ts.map +1 -1
- package/dist/node/publication.js +5 -1
- package/dist/node/publication.js.map +1 -1
- package/dist/node/release-context.d.ts +20 -4
- package/dist/node/release-context.d.ts.map +1 -1
- package/dist/node/retirement-claim.d.ts +1 -1
- package/dist/node/retirement-claim.d.ts.map +1 -1
- package/dist/node/retirement-claim.js +3 -3
- package/dist/node/retirement-claim.js.map +1 -1
- package/dist/node/retirement-record.js +1 -1
- package/dist/node/retirement-record.js.map +1 -1
- package/dist/node/workspace-release.js +1 -1
- package/dist/node/workspace-release.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,7 +82,11 @@ Logical-byte accounting includes every slot entry plus the source anchor; hardli
|
|
|
82
82
|
|
|
83
83
|
An internal symlink or Windows junction may temporarily point to a missing target during installation. The observer validates existing ancestors within the owned root, bounds link resolution to 40 hops, and counts the link itself; materialized target files count through the ordinary directory scan. External targets, cycles, root replacement and unprovable observations still fail. This also lets `recover` inspect a retained installation containing pending internal links. Recovery still requires recorded process-closure evidence: absent PIDs cannot repair a historical gap or release its lock.
|
|
84
84
|
|
|
85
|
-
Commands must finish in the foreground. Managed execution requires Windows x64 Job Objects or Linux/glibc x64 subreaper/wait/pidfd support. A runner manual gate persists the real identity, scope ID and exact run/command binding, rechecks budget/ownership, then authorizes the job. Only matching OS-proven normal/empty closure permits
|
|
85
|
+
Commands must finish in the foreground. Managed execution requires Windows x64 Job Objects or Linux/glibc x64 subreaper/wait/pidfd support. A runner manual gate persists the real identity, scope ID and exact run/command binding, rechecks budget/ownership, then authorizes the job. Only matching OS-proven normal/empty closure permits another command within that run. A controlled abort or timeout may separately prove resource cessation when the Provider reports `terminated`, final emptiness, and the exact scope/binding/root identity. The command remains failed or cancelled; a subsequent run must pass every ordinary gate. Owner loss, Provider failure, unexpected surviving descendants, identity changes and crash gaps remain blocked. Historical schema-2 polling witnesses remain readable but cannot establish cessation. Old gate/result files are never executed or automatically removed.
|
|
86
|
+
|
|
87
|
+
New active journals use schema 3. Before authorizing a command, the tool reserves 1 MiB within the configured budget for bounded terminal metadata; each `terminal.json` is at most 256 KiB. Its checksum, stable proof digest, host and exact metadata file identities permit read-only recovery when the ordinary state merge fails. Writing this receipt does not scan checkout payload or invoke Git. Invalid payload still blocks execution, reuse and cleanup. Metadata replacement, insufficient disk space and actual write failures remain failures. No previous `.tmp` contents or Codex runtime are needed to develop or start a new checkout; recovery of an existing run requires its original local evidence on the original host.
|
|
88
|
+
|
|
89
|
+
Before replacing state, the terminal receipt seals the identities and digests of both the original file and the fsynced temporary file. Recovery accepts either exact image after a coordinator exit; copying the same bytes to another file still fails. After archiving original evidence, the exclusive recovery transaction can discard only the matching uncommitted temporary file. Unknown remnants remain blocked, and historical state and remote effects stay unchanged.
|
|
86
90
|
|
|
87
91
|
Koffi 3.3.3 is a pinned, lazy native dependency. This repository and tarball consumers disable its install script with `allowBuilds.koffi: false`; consumers should do the same. Missing prebuilds/capabilities fail before the job, with no runtime download, compilation or fallback. Owned scopes manage trusted commands, not a security sandbox: do not delegate work to WMI/system services or other external process owners. Workspace mode retains its existing behavior.
|
|
88
92
|
|
|
@@ -95,16 +99,18 @@ Koffi 3.3.3 is a pinned, lazy native dependency. This repository and tarball con
|
|
|
95
99
|
| `status` | Read a deployment for `--sha`, otherwise the latest publish receipt's frozen SHA, otherwise local HEAD if no receipt exists. Returns deployment state; successful querying alone does not imply READY. No checks, acceptance, or pushes. |
|
|
96
100
|
| `verify` | Independently query project and deployment, require READY and correct Git source, then verify production alias, anonymous build marker, and acceptance jobs. Uses the same SHA selection as `status`. No pushes. |
|
|
97
101
|
| `login` | Explicitly delegate to the pinned official Vercel CLI and let the user authorize it. No release config is required. Bounded to ten minutes. The CLI prints login instructions to stderr. |
|
|
98
|
-
| `recover` | Managed mode only:
|
|
102
|
+
| `recover` | Managed mode only: verify cessation and ownership, archive original outcomes, observe refs and finish local cleanup. Vercel login and unchanged remote tips are not local prerequisites. No install, checks, acceptance, pushes, deployment creation or rollback. |
|
|
99
103
|
| `retire` | Managed mode only: explicitly select an interrupted run, bind its original host, require an independently observed later OS boot, archive the unchanged historical evidence and release its exact lock. Historical verification remains UNKNOWN; a new publish must pass all ordinary gates. |
|
|
100
104
|
|
|
101
|
-
Shared options are `--cwd DIR`, `--config FILE`, and `--sha SHA` (only `status`/`verify`); `retire` additionally accepts `--run-id UUID` and `--confirm-origin SHA256`. `--help` prints JSON usage. Standard output is one structured JSON report. Exit codes: `0` successful command, `1` operational failure or pending retirement proof, `2` invalid CLI arguments. SIGINT/SIGTERM cancel active work; managed locks are released only with proven
|
|
105
|
+
Shared options are `--cwd DIR`, `--config FILE`, and `--sha SHA` (only `status`/`verify`); `retire` additionally accepts `--run-id UUID` and `--confirm-origin SHA256`. `--help` prints JSON usage. Standard output is one structured JSON report. Exit codes: `0` successful command, `1` operational failure or pending retirement proof, `2` invalid CLI arguments. SIGINT/SIGTERM cancel active work; managed locks are released only with proven cessation and trusted local metadata, or explicit completed retirement. No command automatically commits, switches branches, force-pushes, creates/uploads deployments, rolls back, or rewrites history. Vercel requests are GET through `vercel api --raw --non-interactive`, reusing the official CLI session. Only `login` initiates login.
|
|
106
|
+
|
|
107
|
+
Execution outcome, process cessation, local disposition and remote effects are separate facts. Safe local cleanup preserves the original state, receipts and `unknown` effects in bounded immutable `history/<RUN_ID>.json` records. The archive's `release-ready` flag authorizes exact lock release; it does not claim the subsequent unlink succeeded. Its optional `outcome` records execution before that release. New runs bind previous history contents and file identities, so a later check cannot erase uncertainty and missing/replaced history fails closed.
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
The normal managed entry can finish a previously stopped run before starting fresh checks. `recover` also provides an explicit entry. Local cleanup can complete when remote refs advance or become unreachable. Every later remote mutation rechecks unresolved historical intents: current candidate or `superseded` ancestry can establish the current remote fact; `before`, `diverged` or `unknown` blocks mutation. Original effects remain unchanged. If a lost-response intent targets the same SHA, repository and branch and fresh reads show that candidate is already current, the new run records `already-current` without sending that push again. Other pushes remain ordinary exact-SHA, non-force operations. No recovery command creates deployments. Missing cessation evidence or an active/unknown coordinator still blocks reuse; PID absence alone never repairs a crash gap.
|
|
104
110
|
|
|
105
111
|
### Explicit retirement of an interrupted run
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
When reliable cessation evidence is irretrievably missing, `recover` points to `retire --run-id UUID`; `recovery.reportExists` distinguishes an existing receipt from an intended path. Retirement never reconstructs a successful publish receipt or changes an old command to closed.
|
|
108
114
|
|
|
109
115
|
```sh
|
|
110
116
|
pnpm exec forge-vercel-release retire --run-id <RUN_ID>
|
|
@@ -118,7 +124,7 @@ pnpm exec forge-vercel-release retire --run-id <RUN_ID> --confirm-origin <ORIGIN
|
|
|
118
124
|
|
|
119
125
|
The saved origin is explicitly `operator-confirmed-origin`, not a reconstructed machine observation. A confirmation cannot override an already recorded different host or changed evidence. The command saves a checkpoint and exits 1 with `SUBSEQUENT_BOOT_REQUIRED` until it can prove a later boot on that same host. The tool never restarts the machine. After arranging a real restart, rerun the first command promptly. On Windows, proof requires the OS uptime counter to be at least 60 seconds lower than the saved baseline; sleep and wall-clock changes are insufficient. On Linux, a different kernel boot ID is required. A short baseline or a long delay after restarting can leave Windows proof insufficient; the baseline is not silently reset. Host observation requires the Windows machine identity registry value or Linux machine-id and kernel boot-id files; unavailable observations fail closed.
|
|
120
126
|
|
|
121
|
-
A native Windows mutex or Linux directory flock serializes retirement. OS release of that lease proves only the end of
|
|
127
|
+
A native Windows mutex or Linux directory flock serializes recovery and retirement metadata transactions. OS release of that lease proves only the end of that transaction, never historical process cessation. Each protocol can resume only its own abandoned claim; foreign claims remain protected. Exact file contents and identities and original source/config remain mandatory. Remote observations are recorded separately; successor, diverged or unavailable refs and Vercel authentication do not block local retirement. The tool writes an archive under `retired/<RUN_ID>.json` before releasing the original lock. Original state and existing receipts remain unchanged; each history/retirement archive is bounded to 8 MiB and counts against the slot budget. New runs refuse insufficient history space; records are not silently pruned. Interrupted finalization can be resumed without rewriting historical results or creating another slot.
|
|
122
128
|
|
|
123
129
|
Exit 0 with `retirement.status: "retired"` means resource retirement completed. `historicalVerification: "unknown"` and original push effects remain in the report and archive. Follow its next command to start a new, fully checked publish on the same slot. This operation does not grant new Git or deployment authorization. `--run-id` and `--confirm-origin` are accepted only by `retire`; workspace mode does not support it.
|
|
124
130
|
|
|
@@ -142,7 +148,7 @@ if (!report.ok) console.error(report.error);
|
|
|
142
148
|
|
|
143
149
|
The root exports only contracts and `releaseErrorCodes`, and is browser-safe. `./node` is explicitly `browser: null` and exports `runRelease`, `validateReleaseConfig`, and `ReleaseError`. Options include `command`, `cwd`, `configPath`, workspace-only `config`, `sha`, `signal`, `transport`, and `onLoginOutput`. Config objects are cloned/validated; managed callers must use a committed file. `transport` supplies only explicit `api(path, signal)` and anonymous `buildInfo(url, signal)` boundaries and must honor abort signals. Node callers supply `onLoginOutput` to display redacted official login instructions.
|
|
144
150
|
|
|
145
|
-
Reports include schema 2, timestamps, SHA/config digest, source/execution roots, run/slot identity, stage, budget/process summaries, bounded job steps, separate push effects, deployment and errors. Managed metadata lives in the slot: ownership, run/recovery locks, state and separate latest-check/latest-publish receipts. The source `.tmp/forge-vercel-release/managed.json` anchors slot/config/publish identity. A state/receipt is at most 1 MiB, anchor at most 64 KiB, and each persisted step stdout/stderr at most 2048 UTF-8 bytes with `truncated`; effects/diagnostics are never clipped. Writes reserve peak bytes and verify
|
|
151
|
+
Reports include schema 2, timestamps, SHA/config digest, source/execution roots, run/slot identity, stage, budget/process summaries, bounded job steps, separate push effects, deployment and errors. Managed metadata lives in the slot: ownership, run/recovery locks, state, terminal proof, immutable history and separate latest-check/latest-publish receipts. The source `.tmp/forge-vercel-release/managed.json` anchors slot/config/publish identity. A state/receipt is at most 1 MiB, anchor at most 64 KiB, and each persisted step stdout/stderr at most 2048 UTF-8 bytes with `truncated`; effects/diagnostics are never clipped. Writes reserve peak bytes and verify the relevant ownership boundaries. Foreign slots, unproven locks and unknown atomic-write remnants are not automatically removed. Workspace mode retains `.tmp/forge-vercel-release/latest-publish.json` and its config-digest/explicit-SHA selection; recover is unsupported there. Receipts are local recovery evidence, not signed authorization. Abrupt termination may retain locks. Live login output buffers partial lines for cross-chunk redaction and uses the same finite per-stream budget.
|
|
146
152
|
|
|
147
153
|
## Error codes
|
|
148
154
|
|
package/dist/contracts.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ export interface ReleaseStep {
|
|
|
79
79
|
readonly exitCode?: number | null;
|
|
80
80
|
}
|
|
81
81
|
export type ReleasePushEffect = 'not-attempted' | 'pushed' | 'already-current' | 'unknown' | 'not-current';
|
|
82
|
-
export type ReleaseRefRelation = 'candidate' | 'before' | '
|
|
82
|
+
export type ReleaseRefRelation = 'candidate' | 'before' | 'superseded' | 'diverged' | 'unknown';
|
|
83
83
|
export interface ReleaseRecoveryObservation {
|
|
84
84
|
readonly owner: 'inactive' | 'active' | 'unknown';
|
|
85
85
|
readonly processes: 'closed' | 'running' | 'unknown';
|
package/dist/contracts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ export declare class BudgetMonitor {
|
|
|
11
11
|
readonly paths: ManagedPaths;
|
|
12
12
|
readonly config: ManagedSourceConfig;
|
|
13
13
|
private readonly observe;
|
|
14
|
+
private readonly reservedBytes;
|
|
14
15
|
private count;
|
|
15
16
|
private maxBytes;
|
|
16
17
|
private minFree;
|
|
@@ -19,7 +20,7 @@ export declare class BudgetMonitor {
|
|
|
19
20
|
private complete;
|
|
20
21
|
private running;
|
|
21
22
|
private sampling;
|
|
22
|
-
constructor(paths: ManagedPaths, config: ManagedSourceConfig, observe?: typeof observeBudget);
|
|
23
|
+
constructor(paths: ManagedPaths, config: ManagedSourceConfig, observe?: typeof observeBudget, reservedBytes?: number);
|
|
23
24
|
sample(): Promise<void>;
|
|
24
25
|
private sampleNow;
|
|
25
26
|
run<T>(operation: (signal: AbortSignal) => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-budget.d.ts","sourceRoot":"","sources":["../../src/node/managed-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAuB,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,WAAW,iBAAiB;IAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AACtH,wBAAsB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,iCAA0B,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAahJ;AACD,qBAAa,aAAa;IASZ,QAAQ,CAAC,KAAK,EAAE,YAAY;IAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO;
|
|
1
|
+
{"version":3,"file":"managed-budget.d.ts","sourceRoot":"","sources":["../../src/node/managed-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAuB,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,WAAW,iBAAiB;IAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AACtH,wBAAsB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,iCAA0B,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAahJ;AACD,qBAAa,aAAa;IASZ,QAAQ,CAAC,KAAK,EAAE,YAAY;IAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAwC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAThG,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAqB;gBAChB,KAAK,EAAE,YAAY,EAAW,MAAM,EAAE,mBAAmB,EAC3D,OAAO,GAAE,OAAO,aAA6B,EAAmB,aAAa,SAAI;IAC9F,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;YAKf,SAAS;IASjB,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IA2B9F,OAAO,IAAI,aAAa;CAEzB"}
|
|
@@ -28,6 +28,7 @@ export class BudgetMonitor {
|
|
|
28
28
|
paths;
|
|
29
29
|
config;
|
|
30
30
|
observe;
|
|
31
|
+
reservedBytes;
|
|
31
32
|
count = 0;
|
|
32
33
|
maxBytes = 0;
|
|
33
34
|
minFree = Number.MAX_SAFE_INTEGER;
|
|
@@ -36,10 +37,11 @@ export class BudgetMonitor {
|
|
|
36
37
|
complete = true;
|
|
37
38
|
running = false;
|
|
38
39
|
sampling = Promise.resolve();
|
|
39
|
-
constructor(paths, config, observe = observeBudget) {
|
|
40
|
+
constructor(paths, config, observe = observeBudget, reservedBytes = 0) {
|
|
40
41
|
this.paths = paths;
|
|
41
42
|
this.config = config;
|
|
42
43
|
this.observe = observe;
|
|
44
|
+
this.reservedBytes = reservedBytes;
|
|
43
45
|
}
|
|
44
46
|
async sample() {
|
|
45
47
|
const observation = this.sampling.then(() => this.sampleNow());
|
|
@@ -63,7 +65,7 @@ export class BudgetMonitor {
|
|
|
63
65
|
if (this.lastObserved !== undefined)
|
|
64
66
|
this.maxGap = Math.max(this.maxGap, observation.observedAt - this.lastObserved);
|
|
65
67
|
this.lastObserved = observation.observedAt;
|
|
66
|
-
if (observation.bytes > this.config.maxBytes || observation.freeBytes < this.config.minFreeBytes)
|
|
68
|
+
if (observation.bytes + this.reservedBytes > this.config.maxBytes || observation.freeBytes - this.reservedBytes < this.config.minFreeBytes)
|
|
67
69
|
throw new ReleaseError('BUDGET_EXCEEDED', { bytes: observation.bytes, freeBytes: observation.freeBytes });
|
|
68
70
|
}
|
|
69
71
|
async run(operation, signal) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-budget.js","sourceRoot":"","sources":["../../src/node/managed-budget.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAmB,EAAE,MAA2B,EAAE,IAAI,GAAG,uBAAuB;IAClH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,KAAgD,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACtK,CAAC,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;QAC7B,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAAC,OAAO,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACvH,CAAC,CAAC;IACF,IAAI,CAAC;QAAC,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;IAAC,CAAC;IAC7D,OAAO,KAAK,EAAE,CAAC;QAAC,IAAI,KAAK,YAAY,YAAY;YAAE,MAAM,KAAK,CAAC;QAAC,MAAM,IAAI,YAAY,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;IAAC,CAAC;YACrI,CAAC;QAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAAC,CAAC;AAClC,CAAC;AACD,MAAM,OAAO,aAAa;IASH;IAA8B;IAChC;
|
|
1
|
+
{"version":3,"file":"managed-budget.js","sourceRoot":"","sources":["../../src/node/managed-budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ManagedCommand } from './release-context.js';
|
|
2
2
|
/** 历史轮询见证保留可读;只有同一实例和绑定的 OS 关闭事实可以复用。 */
|
|
3
3
|
export declare function hasVerifiedManagedClosure(command: ManagedCommand): boolean;
|
|
4
|
+
/** 资源停止与正常关闭分别判断;受控终止不能升级历史命令结果。 */
|
|
5
|
+
export declare function hasVerifiedManagedStop(command: ManagedCommand): boolean;
|
|
4
6
|
//# sourceMappingURL=managed-closure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-closure.d.ts","sourceRoot":"","sources":["../../src/node/managed-closure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,yCAAyC;AACzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAO1E"}
|
|
1
|
+
{"version":3,"file":"managed-closure.d.ts","sourceRoot":"","sources":["../../src/node/managed-closure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,yCAAyC;AACzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAO1E;AAED,oCAAoC;AACpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAQvE"}
|
|
@@ -7,4 +7,15 @@ export function hasVerifiedManagedClosure(command) {
|
|
|
7
7
|
&& owned.scopeId === command.scope.scopeId && owned.binding === command.scope.binding
|
|
8
8
|
&& owned.rootIdentity.pid === command.identity.pid && owned.rootIdentity.startToken === command.identity.startToken;
|
|
9
9
|
}
|
|
10
|
+
/** 资源停止与正常关闭分别判断;受控终止不能升级历史命令结果。 */
|
|
11
|
+
export function hasVerifiedManagedStop(command) {
|
|
12
|
+
if (hasVerifiedManagedClosure(command))
|
|
13
|
+
return true;
|
|
14
|
+
const closure = command.closure, owned = closure?.ownedScope;
|
|
15
|
+
return command.status === 'stopped' && command.observationComplete && !!command.identity && !!command.scope && !!closure
|
|
16
|
+
&& ['abort', 'timeout'].includes(closure.requestedTermination ?? '') && Number.isFinite(Date.parse(closure.observedAt))
|
|
17
|
+
&& owned?.status === 'unknown' && owned.reason === 'terminated' && owned.empty === true
|
|
18
|
+
&& owned.scopeId === command.scope.scopeId && owned.binding === command.scope.binding
|
|
19
|
+
&& owned.rootIdentity?.pid === command.identity.pid && owned.rootIdentity.startToken === command.identity.startToken;
|
|
20
|
+
}
|
|
10
21
|
//# sourceMappingURL=managed-closure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-closure.js","sourceRoot":"","sources":["../../src/node/managed-closure.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,UAAU,yBAAyB,CAAC,OAAuB;IAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,UAAU,CAAC;IAC7D,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,mBAAmB,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO;WAClH,OAAO,CAAC,WAAW,KAAK,MAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;WACrG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,EAAE,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;WAClI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO;WAClF,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;AACxH,CAAC"}
|
|
1
|
+
{"version":3,"file":"managed-closure.js","sourceRoot":"","sources":["../../src/node/managed-closure.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,UAAU,yBAAyB,CAAC,OAAuB;IAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,UAAU,CAAC;IAC7D,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,mBAAmB,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO;WAClH,OAAO,CAAC,WAAW,KAAK,MAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;WACrG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,EAAE,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;WAClI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO;WAClF,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;AACxH,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,sBAAsB,CAAC,OAAuB;IAC5D,IAAI,yBAAyB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,UAAU,CAAC;IAC7D,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,mBAAmB,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO;WACnH,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;WACpH,KAAK,EAAE,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;WACpF,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO;WAClF,KAAK,CAAC,YAAY,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;AACzH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReleaseRecoveryObservation, ReleaseReport } from '../contracts.js';
|
|
2
|
+
import type { ManagedPaths, ManagedState } from './release-context.js';
|
|
3
|
+
import { type MetadataFile } from './managed-metadata.js';
|
|
4
|
+
declare const names: (paths: ManagedPaths) => {
|
|
5
|
+
state: string;
|
|
6
|
+
owner: string;
|
|
7
|
+
anchor: string;
|
|
8
|
+
lock: string;
|
|
9
|
+
terminal: string;
|
|
10
|
+
check: string;
|
|
11
|
+
publish: string;
|
|
12
|
+
};
|
|
13
|
+
type Entry = keyof ReturnType<typeof names>;
|
|
14
|
+
export interface ManagedDisposition {
|
|
15
|
+
readonly schemaVersion: 1;
|
|
16
|
+
readonly kind: 'managed-run-disposition';
|
|
17
|
+
readonly runId: string;
|
|
18
|
+
readonly slotId: string;
|
|
19
|
+
readonly snapshot: Readonly<Record<Entry, string | null>>;
|
|
20
|
+
readonly files: Readonly<Record<Entry, MetadataFile | null>>;
|
|
21
|
+
readonly stopped: ManagedState;
|
|
22
|
+
readonly local: 'release-ready';
|
|
23
|
+
readonly recordedAt: string;
|
|
24
|
+
readonly observation?: ReleaseRecoveryObservation;
|
|
25
|
+
readonly outcome?: ReleaseReport;
|
|
26
|
+
readonly checksum: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const dispositionPath: (paths: ManagedPaths, runId: string) => string;
|
|
29
|
+
export declare function parseManagedDisposition(value: unknown): ManagedDisposition;
|
|
30
|
+
export declare function readManagedDisposition(paths: ManagedPaths, runId: string): Promise<ManagedDisposition | undefined>;
|
|
31
|
+
export declare function assertDispositionSnapshot(paths: ManagedPaths, evidence: ManagedDisposition, includeLock?: boolean): Promise<void>;
|
|
32
|
+
export declare function hasManagedDisposition(paths: ManagedPaths, state: ManagedState): Promise<boolean>;
|
|
33
|
+
/** 保存原始结果和只读归并的停止事实;历史副作用不因本地解锁而改写。 */
|
|
34
|
+
export declare function archiveManagedDisposition(paths: ManagedPaths, original: ManagedState, stopped: ManagedState, guard: () => Promise<void>, observation?: ReleaseRecoveryObservation, omitLock?: boolean, outcome?: ReleaseReport): Promise<ManagedDisposition>;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=managed-disposition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-disposition.d.ts","sourceRoot":"","sources":["../../src/node/managed-disposition.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EAAgF,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAKxI,QAAA,MAAM,KAAK,GAAI,OAAO,YAAY;;;;;;;;CACyJ,CAAC;AAC5L,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AAC5C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACrH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7D,QAAQ,CAAC,WAAW,CAAC,EAAE,0BAA0B,CAAC;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AACD,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,EAAE,OAAO,MAAM,KAAG,MAA6D,CAAC;AACnI,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAiC1E;AACD,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAIxH;AACD,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpI;AACD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAKtG;AACD,uCAAuC;AACvC,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,0BAA0B,EAAE,QAAQ,UAAQ,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsBhQ"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { record, ReleaseError } from './errors.js';
|
|
4
|
+
import { assertPathChain, atomicJson, readBoundedJson, readBoundedText } from './managed-io.js';
|
|
5
|
+
import { assertMetadataFile, assertMetadataPaths, inspectMetadataFile, metadataDigest } from './managed-metadata.js';
|
|
6
|
+
import { hasVerifiedManagedStop } from './managed-closure.js';
|
|
7
|
+
import { parseManagedReceipt, parseManagedState, summarizeReport } from './managed-state.js';
|
|
8
|
+
const historyLimit = 8_388_608;
|
|
9
|
+
const names = (paths) => ({ state: paths.statePath, owner: paths.ownershipPath, anchor: paths.anchorPath,
|
|
10
|
+
lock: paths.lockPath, terminal: resolve(paths.slotRoot, 'terminal.json'), check: resolve(paths.slotRoot, 'latest-check.json'), publish: resolve(paths.slotRoot, 'latest-publish.json') });
|
|
11
|
+
export const dispositionPath = (paths, runId) => resolve(paths.slotRoot, 'history', `${runId}.json`);
|
|
12
|
+
export function parseManagedDisposition(value) {
|
|
13
|
+
const item = record(value), { checksum, ...body } = item;
|
|
14
|
+
if (typeof checksum !== 'string' || metadataDigest(JSON.stringify(body)) !== checksum)
|
|
15
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_CHECKSUM' });
|
|
16
|
+
const snapshot = record(item.snapshot), files = record(item.files), stopped = record(item.stopped);
|
|
17
|
+
if (item.schemaVersion !== 1 || item.kind !== 'managed-run-disposition' || item.local !== 'release-ready'
|
|
18
|
+
|| typeof item.runId !== 'string' || !/^[a-f0-9-]{36}$/u.test(item.runId) || item.runId !== stopped.runId || item.slotId !== stopped.slotId
|
|
19
|
+
|| typeof item.recordedAt !== 'string' || !Number.isFinite(Date.parse(item.recordedAt)))
|
|
20
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_BINDING' });
|
|
21
|
+
for (const key of ['state', 'owner', 'anchor', 'lock', 'terminal', 'check', 'publish']) {
|
|
22
|
+
const file = record(files[key]), identity = record(file.identity);
|
|
23
|
+
if (snapshot[key] === null && files[key] === null)
|
|
24
|
+
continue;
|
|
25
|
+
if (typeof snapshot[key] !== 'string' || file.sha256 !== metadataDigest(snapshot[key])
|
|
26
|
+
|| ![identity.dev, identity.ino].every(part => typeof part === 'string' && /^\d+$/u.test(part)))
|
|
27
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_FILE' });
|
|
28
|
+
}
|
|
29
|
+
if (typeof snapshot.state !== 'string' || typeof snapshot.owner !== 'string')
|
|
30
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_STATE' });
|
|
31
|
+
const result = value;
|
|
32
|
+
const original = parseManagedState(JSON.parse(snapshot.state), result.stopped.source, result.slotId);
|
|
33
|
+
parseManagedState(result.stopped, original.source, original.slotId);
|
|
34
|
+
if (result.outcome) {
|
|
35
|
+
parseManagedReceipt({ schemaVersion: 2, slotId: result.slotId, source: original.source, report: result.outcome }, original.source, result.slotId);
|
|
36
|
+
if (result.outcome.runId !== result.runId)
|
|
37
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_OUTCOME' });
|
|
38
|
+
}
|
|
39
|
+
const commandsMatch = original.processes.length === result.stopped.processes.length && original.processes.every((command, index) => {
|
|
40
|
+
const stopped = result.stopped.processes[index];
|
|
41
|
+
if (!stopped || command.id !== stopped.id || command.name !== stopped.name)
|
|
42
|
+
return false;
|
|
43
|
+
if (index < original.processes.length - 1)
|
|
44
|
+
return JSON.stringify(command) === JSON.stringify(stopped);
|
|
45
|
+
return (command.scope === undefined || JSON.stringify(command.scope) === JSON.stringify(stopped.scope))
|
|
46
|
+
&& (command.identity === undefined || JSON.stringify(command.identity) === JSON.stringify(stopped.identity))
|
|
47
|
+
&& (command.terminalSha256 === undefined || command.terminalSha256 === stopped.terminalSha256)
|
|
48
|
+
&& JSON.stringify(command.descendants) === JSON.stringify(stopped.descendants);
|
|
49
|
+
});
|
|
50
|
+
if (original.runId !== result.runId || JSON.stringify({ ...original, processes: [] }) !== JSON.stringify({ ...result.stopped, processes: [] })
|
|
51
|
+
|| !commandsMatch || !result.stopped.processes.every(hasVerifiedManagedStop))
|
|
52
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_STOP' });
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
export async function readManagedDisposition(paths, runId) {
|
|
56
|
+
const path = dispositionPath(paths, runId);
|
|
57
|
+
await assertMetadataPaths(paths);
|
|
58
|
+
await assertPathChain(paths.slotRoot, path);
|
|
59
|
+
const value = await readBoundedJson(path, historyLimit);
|
|
60
|
+
return value === undefined ? undefined : parseManagedDisposition(value);
|
|
61
|
+
}
|
|
62
|
+
export async function assertDispositionSnapshot(paths, evidence, includeLock = true) {
|
|
63
|
+
await assertMetadataPaths(paths);
|
|
64
|
+
for (const [key, path] of Object.entries(names(paths))) {
|
|
65
|
+
if (key === 'lock' && !includeLock)
|
|
66
|
+
continue;
|
|
67
|
+
await assertMetadataFile(path, evidence.files[key]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export async function hasManagedDisposition(paths, state) {
|
|
71
|
+
const evidence = await readManagedDisposition(paths, state.runId);
|
|
72
|
+
if (!evidence)
|
|
73
|
+
return false;
|
|
74
|
+
if (evidence.slotId !== state.slotId || JSON.stringify(JSON.parse(evidence.snapshot.state ?? 'null')) !== JSON.stringify(state))
|
|
75
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_STATE_BINDING' });
|
|
76
|
+
await assertDispositionSnapshot(paths, evidence, false);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** 保存原始结果和只读归并的停止事实;历史副作用不因本地解锁而改写。 */
|
|
80
|
+
export async function archiveManagedDisposition(paths, original, stopped, guard, observation, omitLock = false, outcome) {
|
|
81
|
+
await guard();
|
|
82
|
+
const existing = await readManagedDisposition(paths, original.runId);
|
|
83
|
+
if (existing) {
|
|
84
|
+
await hasManagedDisposition(paths, original);
|
|
85
|
+
return existing;
|
|
86
|
+
}
|
|
87
|
+
const entries = await Promise.all(Object.entries(names(paths)).map(async ([key, path]) => {
|
|
88
|
+
const witness = key === 'lock' && omitLock ? null : await inspectMetadataFile(path);
|
|
89
|
+
const text = witness ? await readBoundedText(path) ?? null : null;
|
|
90
|
+
if (witness && (text === null || metadataDigest(text) !== witness.sha256))
|
|
91
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_INPUT_CHANGED' });
|
|
92
|
+
if (!(key === 'lock' && omitLock))
|
|
93
|
+
await assertMetadataFile(path, witness);
|
|
94
|
+
return [key, text, witness];
|
|
95
|
+
}));
|
|
96
|
+
const body = { schemaVersion: 1, kind: 'managed-run-disposition', runId: original.runId, slotId: original.slotId,
|
|
97
|
+
snapshot: Object.fromEntries(entries.map(([key, text]) => [key, text])),
|
|
98
|
+
files: Object.fromEntries(entries.map(([key, , witness]) => [key, witness])),
|
|
99
|
+
stopped, local: 'release-ready', recordedAt: new Date().toISOString(), ...(observation ? { observation } : {}), ...(outcome ? { outcome: summarizeReport(outcome) } : {}) };
|
|
100
|
+
const evidence = parseManagedDisposition({ ...body, checksum: metadataDigest(JSON.stringify(body)) });
|
|
101
|
+
if (JSON.stringify(JSON.parse(evidence.snapshot.state ?? 'null')) !== JSON.stringify(original))
|
|
102
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_STATE_CHANGED' });
|
|
103
|
+
const config = original.source.config.source;
|
|
104
|
+
if (config.mode !== 'managed-commit')
|
|
105
|
+
throw new ReleaseError('SOURCE_UNSUPPORTED');
|
|
106
|
+
const path = dispositionPath(paths, original.runId);
|
|
107
|
+
await assertPathChain(paths.slotRoot, path);
|
|
108
|
+
await mkdir(dirname(path), { recursive: true });
|
|
109
|
+
const writeGuard = async () => { await guard(); await assertDispositionSnapshot(paths, evidence, !omitLock); };
|
|
110
|
+
await atomicJson(path, evidence, historyLimit, paths, writeGuard, config.maxBytes, config.minFreeBytes);
|
|
111
|
+
await writeGuard();
|
|
112
|
+
return evidence;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=managed-disposition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-disposition.js","sourceRoot":"","sources":["../../src/node/managed-disposition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ManagedHistoryReference, ManagedPaths, ManagedState } from './release-context.js';
|
|
2
|
+
export declare const historyFileLimit = 8388608;
|
|
3
|
+
/** 新活动状态绑定已有历史的内容与文件身份;清单缺失不能被理解为没有旧意图。 */
|
|
4
|
+
export declare function captureManagedHistory(paths: ManagedPaths): Promise<ManagedHistoryReference[]>;
|
|
5
|
+
export declare function assertManagedHistory(paths: ManagedPaths, state: ManagedState): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=managed-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-history.d.ts","sourceRoot":"","sources":["../../src/node/managed-history.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOhG,eAAO,MAAM,gBAAgB,UAAY,CAAC;AAC1C,2CAA2C;AAC3C,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAkBnG;AACD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlG"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { opendir } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { assertPathChain, pathExists, readBoundedJson } from './managed-io.js';
|
|
4
|
+
import { assertMetadataFile, assertMetadataPaths, inspectMetadataFile } from './managed-metadata.js';
|
|
5
|
+
import { parseManagedDisposition } from './managed-disposition.js';
|
|
6
|
+
import { parseRetirementRecord } from './retirement-record.js';
|
|
7
|
+
import { ReleaseError } from './errors.js';
|
|
8
|
+
export const historyFileLimit = 8_388_608;
|
|
9
|
+
/** 新活动状态绑定已有历史的内容与文件身份;清单缺失不能被理解为没有旧意图。 */
|
|
10
|
+
export async function captureManagedHistory(paths) {
|
|
11
|
+
await assertMetadataPaths(paths);
|
|
12
|
+
const result = [];
|
|
13
|
+
for (const kind of ['history', 'retired']) {
|
|
14
|
+
const directory = resolve(paths.slotRoot, kind);
|
|
15
|
+
await assertPathChain(paths.slotRoot, directory);
|
|
16
|
+
if (!await pathExists(directory))
|
|
17
|
+
continue;
|
|
18
|
+
for await (const entry of await opendir(directory)) {
|
|
19
|
+
if (result.length >= 10_000)
|
|
20
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_LIMIT' });
|
|
21
|
+
if (!entry.isFile() || !/^[a-f0-9-]{36}\.json$/u.test(entry.name))
|
|
22
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_ENTRY' });
|
|
23
|
+
const name = `${kind}/${entry.name}`, path = resolve(paths.slotRoot, name), file = await inspectMetadataFile(path, historyFileLimit);
|
|
24
|
+
if (!file)
|
|
25
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_MISSING' });
|
|
26
|
+
const value = await readBoundedJson(path, historyFileLimit);
|
|
27
|
+
const evidence = kind === 'history' ? parseManagedDisposition(value) : parseRetirementRecord(value);
|
|
28
|
+
if (`${evidence.runId}.json` !== entry.name)
|
|
29
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_NAME' });
|
|
30
|
+
await assertMetadataFile(path, file, historyFileLimit);
|
|
31
|
+
result.push({ path: name, file });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result.sort((a, b) => a.path.localeCompare(b.path));
|
|
35
|
+
}
|
|
36
|
+
export async function assertManagedHistory(paths, state) {
|
|
37
|
+
await assertMetadataPaths(paths);
|
|
38
|
+
if (state.schemaVersion === 2)
|
|
39
|
+
return;
|
|
40
|
+
if (!state.history)
|
|
41
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'HISTORY_BINDING_MISSING' });
|
|
42
|
+
for (const entry of state.history) {
|
|
43
|
+
const path = resolve(paths.slotRoot, entry.path);
|
|
44
|
+
await assertPathChain(paths.slotRoot, path);
|
|
45
|
+
await assertMetadataFile(path, entry.file, historyFileLimit);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=managed-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-history.js","sourceRoot":"","sources":["../../src/node/managed-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileIdentity, ManagedPaths } from './release-context.js';
|
|
1
|
+
import type { FileIdentity, ManagedPaths, MetadataFile } from './release-context.js';
|
|
2
2
|
export declare const within: (root: string, path: string) => boolean;
|
|
3
3
|
export declare const fileIdentity: (path: string) => Promise<FileIdentity>;
|
|
4
4
|
export declare const sameIdentity: (a: {
|
|
@@ -20,5 +20,5 @@ export declare function measureManagedUsage(paths: ManagedPaths, signal?: AbortS
|
|
|
20
20
|
bytes: number;
|
|
21
21
|
freeBytes: number;
|
|
22
22
|
}>;
|
|
23
|
-
export declare function atomicJson(path: string, value: unknown, maxBytes: number, paths: ManagedPaths, guard: () => Promise<void>, maxTotal: number, minFree: number): Promise<void>;
|
|
23
|
+
export declare function atomicJson(path: string, value: unknown, maxBytes: number, paths: ManagedPaths, guard: () => Promise<void>, maxTotal: number, minFree: number, beforeCommit?: (prepared: MetadataFile) => Promise<void>): Promise<void>;
|
|
24
24
|
//# sourceMappingURL=managed-io.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-io.d.ts","sourceRoot":"","sources":["../../src/node/managed-io.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"managed-io.d.ts","sourceRoot":"","sources":["../../src/node/managed-io.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,OAEnD,CAAC;AACF,eAAO,MAAM,YAAY,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,YAAY,CAAyH,CAAC;AAChM,eAAO,MAAM,YAAY,GAAI,GAAG;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,KAAG,OAG3I,CAAC;AACF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/D;AACD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/E;AACD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiBrG;AACD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAI1F;AA8CD,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAsCtI;AACD,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,iCAA0B,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAQlK;AACD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EACjK,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BzE"}
|
package/dist/node/managed-io.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { lstat, open, opendir, readlink, realpath, rename, statfs, unlink } from 'node:fs/promises';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
3
4
|
import { record, ReleaseError } from './errors.js';
|
|
4
5
|
export const within = (root, path) => {
|
|
@@ -222,7 +223,7 @@ export async function measureManagedUsage(paths, signal, scan = measureManagedUs
|
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
|
-
export async function atomicJson(path, value, maxBytes, paths, guard, maxTotal, minFree) {
|
|
226
|
+
export async function atomicJson(path, value, maxBytes, paths, guard, maxTotal, minFree, beforeCommit) {
|
|
226
227
|
const bytes = Buffer.from(`${JSON.stringify(value)}\n`, 'utf8');
|
|
227
228
|
if (bytes.length > maxBytes)
|
|
228
229
|
throw new ReleaseError('BUDGET_EXCEEDED', { reason: 'METADATA_LIMIT' });
|
|
@@ -232,18 +233,34 @@ export async function atomicJson(path, value, maxBytes, paths, guard, maxTotal,
|
|
|
232
233
|
if (usage.bytes + bytes.length > maxTotal || usage.freeBytes - bytes.length < minFree)
|
|
233
234
|
throw new ReleaseError('BUDGET_EXCEEDED', { reason: 'METADATA_ADMISSION' });
|
|
234
235
|
const temporary = resolve(dirname(path), `.${path.slice(dirname(path).length + 1)}.next`);
|
|
235
|
-
const handle = await open(temporary, 'wx');
|
|
236
|
+
const handle = await open(temporary, 'wx'), created = await handle.stat({ bigint: true });
|
|
237
|
+
const prepared = { identity: { dev: created.dev.toString(), ino: created.ino.toString() }, sha256: createHash('sha256').update(bytes).digest('hex') };
|
|
238
|
+
let renamed = false;
|
|
239
|
+
const intact = async () => sameIdentity(created, await lstat(temporary, { bigint: true }))
|
|
240
|
+
&& await readBoundedText(temporary, maxBytes) === bytes.toString('utf8');
|
|
236
241
|
try {
|
|
237
242
|
await handle.writeFile(bytes);
|
|
238
243
|
await handle.sync();
|
|
244
|
+
await handle.close();
|
|
245
|
+
// 在目标替换前持久预告暂存文件的精确身份,恢复可区分 rename 两侧的合法状态。
|
|
246
|
+
await beforeCommit?.(prepared);
|
|
247
|
+
await guard();
|
|
248
|
+
if (!await intact())
|
|
249
|
+
throw new ReleaseError('SLOT_STATE', { reason: 'METADATA_TEMP_REPLACED' });
|
|
250
|
+
await rename(temporary, path);
|
|
251
|
+
renamed = true;
|
|
239
252
|
}
|
|
240
|
-
|
|
253
|
+
finally {
|
|
241
254
|
await handle.close();
|
|
242
|
-
|
|
243
|
-
|
|
255
|
+
if (!renamed) {
|
|
256
|
+
// 已知失败不遗留本次完整暂存文件;未知归属/内容与崩溃残留仍由恢复门禁处理。
|
|
257
|
+
try {
|
|
258
|
+
await guard();
|
|
259
|
+
if (await pathExists(temporary) && await intact())
|
|
260
|
+
await unlink(temporary);
|
|
261
|
+
}
|
|
262
|
+
catch { /* 保留首错,不清理无法证明归属的文件。 */ }
|
|
263
|
+
}
|
|
244
264
|
}
|
|
245
|
-
await handle.close();
|
|
246
|
-
await guard();
|
|
247
|
-
await rename(temporary, path);
|
|
248
265
|
}
|
|
249
266
|
//# sourceMappingURL=managed-io.js.map
|