@microwiseai/snapshot 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/current.d.ts +5 -1
- package/dist/commands/current.d.ts.map +1 -1
- package/dist/commands/current.js +89 -2
- package/dist/commands/current.js.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +83 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/install.d.ts +41 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +396 -216
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/publish.d.ts +0 -4
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +44 -58
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +52 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/index.js +22 -28
- package/dist/index.js.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/core-floor.d.ts +49 -0
- package/dist/lib/core-floor.d.ts.map +1 -0
- package/dist/lib/core-floor.js +78 -0
- package/dist/lib/core-floor.js.map +1 -0
- package/dist/lib/gitlab.d.ts.map +1 -1
- package/dist/lib/gitlab.js +8 -6
- package/dist/lib/gitlab.js.map +1 -1
- package/dist/lib/install-verify.d.ts +101 -0
- package/dist/lib/install-verify.d.ts.map +1 -0
- package/dist/lib/install-verify.js +143 -0
- package/dist/lib/install-verify.js.map +1 -0
- package/dist/lib/ledger.d.ts +212 -0
- package/dist/lib/ledger.d.ts.map +1 -0
- package/dist/lib/ledger.js +266 -0
- package/dist/lib/ledger.js.map +1 -0
- package/dist/lib/pin-override.d.ts +53 -0
- package/dist/lib/pin-override.d.ts.map +1 -0
- package/dist/lib/pin-override.js +77 -0
- package/dist/lib/pin-override.js.map +1 -0
- package/dist/lib/prerequisites.d.ts +33 -0
- package/dist/lib/prerequisites.d.ts.map +1 -0
- package/dist/lib/prerequisites.js +123 -0
- package/dist/lib/prerequisites.js.map +1 -0
- package/dist/lib/transitive-resolver.d.ts +0 -121
- package/dist/lib/transitive-resolver.d.ts.map +1 -1
- package/dist/lib/transitive-resolver.js +0 -190
- package/dist/lib/transitive-resolver.js.map +1 -1
- package/dist/lib/version-validator.d.ts +9 -0
- package/dist/lib/version-validator.d.ts.map +1 -1
- package/dist/lib/version-validator.js +69 -0
- package/dist/lib/version-validator.js.map +1 -1
- package/package.json +9 -19
- package/dist/commands/clone-all.d.ts +0 -21
- package/dist/commands/clone-all.d.ts.map +0 -1
- package/dist/commands/clone-all.js +0 -57
- package/dist/commands/clone-all.js.map +0 -1
- package/dist/commands/preflight.d.ts +0 -31
- package/dist/commands/preflight.d.ts.map +0 -1
- package/dist/commands/preflight.js +0 -83
- package/dist/commands/preflight.js.map +0 -1
- package/dist/lib/distkit-closure-bridge.d.ts +0 -102
- package/dist/lib/distkit-closure-bridge.d.ts.map +0 -1
- package/dist/lib/distkit-closure-bridge.js +0 -177
- package/dist/lib/distkit-closure-bridge.js.map +0 -1
- package/dist/lib/distkit-closure-parity.d.ts +0 -110
- package/dist/lib/distkit-closure-parity.d.ts.map +0 -1
- package/dist/lib/distkit-closure-parity.js +0 -134
- package/dist/lib/distkit-closure-parity.js.map +0 -1
- package/dist/lib/distkit-routing-port.d.ts +0 -37
- package/dist/lib/distkit-routing-port.d.ts.map +0 -1
- package/dist/lib/distkit-routing-port.js +0 -72
- package/dist/lib/distkit-routing-port.js.map +0 -1
- package/dist/lib/install-timeline.d.ts +0 -81
- package/dist/lib/install-timeline.d.ts.map +0 -1
- package/dist/lib/install-timeline.js +0 -243
- package/dist/lib/install-timeline.js.map +0 -1
- package/dist/lib/preflight-adapter.d.ts +0 -52
- package/dist/lib/preflight-adapter.d.ts.map +0 -1
- package/dist/lib/preflight-adapter.js +0 -224
- package/dist/lib/preflight-adapter.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/README.md +0 -117
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.d.ts +0 -9
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.js +0 -154
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/clone.d.ts +0 -21
- package/node_modules/@gitdot/clone-lib/dist/clone.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/clone.js +0 -228
- package/node_modules/@gitdot/clone-lib/dist/clone.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/dotpath.d.ts +0 -10
- package/node_modules/@gitdot/clone-lib/dist/dotpath.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/dotpath.js +0 -27
- package/node_modules/@gitdot/clone-lib/dist/dotpath.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/git.d.ts +0 -23
- package/node_modules/@gitdot/clone-lib/dist/git.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/git.js +0 -134
- package/node_modules/@gitdot/clone-lib/dist/git.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/index.d.ts +0 -17
- package/node_modules/@gitdot/clone-lib/dist/index.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/index.js +0 -35
- package/node_modules/@gitdot/clone-lib/dist/index.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/lock.d.ts +0 -24
- package/node_modules/@gitdot/clone-lib/dist/lock.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/lock.js +0 -97
- package/node_modules/@gitdot/clone-lib/dist/lock.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.d.ts +0 -15
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.js +0 -124
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.d.ts +0 -12
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.js +0 -31
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.d.ts +0 -32
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.js +0 -159
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.d.ts +0 -44
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.js +0 -163
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.d.ts +0 -18
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.js +0 -155
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/types.d.ts +0 -225
- package/node_modules/@gitdot/clone-lib/dist/types.d.ts.map +0 -1
- package/node_modules/@gitdot/clone-lib/dist/types.js +0 -9
- package/node_modules/@gitdot/clone-lib/dist/types.js.map +0 -1
- package/node_modules/@gitdot/clone-lib/package.json +0 -53
- package/node_modules/@microwiseai/install-preflight/dist/index.d.ts +0 -27
- package/node_modules/@microwiseai/install-preflight/dist/index.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/index.js +0 -26
- package/node_modules/@microwiseai/install-preflight/dist/index.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/policy.d.ts +0 -42
- package/node_modules/@microwiseai/install-preflight/dist/policy.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/policy.js +0 -79
- package/node_modules/@microwiseai/install-preflight/dist/policy.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/preflight.d.ts +0 -18
- package/node_modules/@microwiseai/install-preflight/dist/preflight.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/preflight.js +0 -0
- package/node_modules/@microwiseai/install-preflight/dist/preflight.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.d.ts +0 -26
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.js +0 -63
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/semver.d.ts +0 -45
- package/node_modules/@microwiseai/install-preflight/dist/semver.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/semver.js +0 -195
- package/node_modules/@microwiseai/install-preflight/dist/semver.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/types.d.ts +0 -136
- package/node_modules/@microwiseai/install-preflight/dist/types.d.ts.map +0 -1
- package/node_modules/@microwiseai/install-preflight/dist/types.js +0 -11
- package/node_modules/@microwiseai/install-preflight/dist/types.js.map +0 -1
- package/node_modules/@microwiseai/install-preflight/package.json +0 -49
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-verify.js","sourceRoot":"","sources":["../../src/lib/install-verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* Install Ledger (S3 — beta-pipeline-robustness-2026-08-30 §4)
|
|
4
|
+
* ============================================================
|
|
5
|
+
*
|
|
6
|
+
* Records, at the END of an install, the provenance of every npm package that
|
|
7
|
+
* was installed: the manifest pin we asked for (`expected`), the version that
|
|
8
|
+
* actually landed on disk (`resolved`), the tarball URL it came from, the
|
|
9
|
+
* installer/step that produced it, and the ordered list of install steps.
|
|
10
|
+
*
|
|
11
|
+
* Goal (AC3.1): after any install, "이 버전이 어디서 왔나" ("where did this
|
|
12
|
+
* version come from?") is answerable from the ledger ALONE — no reverse
|
|
13
|
+
* engineering of the global node_modules.
|
|
14
|
+
*
|
|
15
|
+
* SCHEMA OWNERSHIP (manager freeze 2026-08-30): this file is the SSOT for the
|
|
16
|
+
* ledger schema; ledger.json is owned by S3 (this worker). Field names follow
|
|
17
|
+
* the 기획서. S1 (verify) and FB (pin override) live in verify-owned libs and
|
|
18
|
+
* do NOT own this schema. Dependency direction is one-way (verify → ledger):
|
|
19
|
+
* ledger.ts imports NOTHING from install-verify.ts / pin-override.ts.
|
|
20
|
+
*
|
|
21
|
+
* Writing the ledger MUST NOT break an install — every entry point here is
|
|
22
|
+
* best-effort and swallows its own errors.
|
|
23
|
+
*/
|
|
24
|
+
/** Current ledger schema version. Bump on breaking field changes. */
|
|
25
|
+
export declare const LEDGER_SCHEMA_VERSION: 1;
|
|
26
|
+
/** One recorded install step, in execution order. */
|
|
27
|
+
export interface LedgerStep {
|
|
28
|
+
/** 1-based execution order across the whole install. */
|
|
29
|
+
order: number;
|
|
30
|
+
/**
|
|
31
|
+
* Which phase of the install produced this step. Stable identifiers:
|
|
32
|
+
* 'pre-install-batch' — the single up-front `npm install -g` batch
|
|
33
|
+
* 'pre-install-fallback' — per-package retry after the pre-install batch failed
|
|
34
|
+
* 'layer-batch' — a per-snapshot-layer npm batch (installSnapshot)
|
|
35
|
+
* 'layer-fallback' — per-package retry after a layer batch failed
|
|
36
|
+
* 'layer-parallel' — non-npm (glpkg/generic) parallel install
|
|
37
|
+
* 'skit' — skit-adapter install
|
|
38
|
+
*/
|
|
39
|
+
phase: string;
|
|
40
|
+
/** Installer name: 'npm-proxy' | 'glpkg' | 'skit' | ... */
|
|
41
|
+
installer: string;
|
|
42
|
+
/** The exact command executed (or a synthetic label for non-shell installers). */
|
|
43
|
+
command: string;
|
|
44
|
+
/** name@version specs this step targeted. */
|
|
45
|
+
specs: string[];
|
|
46
|
+
/** Outcome of the step. */
|
|
47
|
+
result: 'ok' | 'fallback' | 'failed';
|
|
48
|
+
}
|
|
49
|
+
/** Provenance for a single npm package, resolved after install. */
|
|
50
|
+
export interface LedgerPackage {
|
|
51
|
+
/** Package name, e.g. "@ist/sesh". */
|
|
52
|
+
name: string;
|
|
53
|
+
/** Manifest pin we requested (SSOT intent). null if not declared as npm here. */
|
|
54
|
+
expected: string | null;
|
|
55
|
+
/** Version actually on disk after install (from `npm ls -g`). null if absent. */
|
|
56
|
+
resolved: string | null;
|
|
57
|
+
/** Tarball URL the resolved version was fetched from (from `npm ls -g`). */
|
|
58
|
+
tarballUrl: string | null;
|
|
59
|
+
/** Human/structured summary answering "where did this version come from?". */
|
|
60
|
+
resolutionSource: string;
|
|
61
|
+
/** Installer that handled this package. */
|
|
62
|
+
installer: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* S1 (verify) verdict, folded into the ledger so verification and provenance
|
|
66
|
+
* live in one artifact. WRITTEN BY THE VERIFY WIRING (install.ts integrator),
|
|
67
|
+
* shaped to verifyInstallMap()'s return contract. Optional: absent until the
|
|
68
|
+
* verify pass runs.
|
|
69
|
+
*/
|
|
70
|
+
export interface LedgerVerification {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
verifiedCount: number;
|
|
73
|
+
total: number;
|
|
74
|
+
mismatches: Array<{
|
|
75
|
+
name: string;
|
|
76
|
+
expected: string | null;
|
|
77
|
+
got: string | null;
|
|
78
|
+
}>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* AC1.4 — core-floor verdict folded into the ledger. Records every below-floor
|
|
82
|
+
* copy of the singleton package (@ist/adapters-core) found in the nested tree.
|
|
83
|
+
* Written by the install.ts integrator (coreFloorAssert lives in core-floor.ts).
|
|
84
|
+
*/
|
|
85
|
+
export interface LedgerCoreFloor {
|
|
86
|
+
ok: boolean;
|
|
87
|
+
pkg: string;
|
|
88
|
+
minVersion: string;
|
|
89
|
+
offenders: Array<{
|
|
90
|
+
path: string;
|
|
91
|
+
version: string;
|
|
92
|
+
}>;
|
|
93
|
+
}
|
|
94
|
+
/** The install ledger written to ~/.config/ist-snapshot/ledger.json. */
|
|
95
|
+
export interface InstallLedger {
|
|
96
|
+
schemaVersion: typeof LEDGER_SCHEMA_VERSION;
|
|
97
|
+
snapshot: {
|
|
98
|
+
name: string;
|
|
99
|
+
version: string;
|
|
100
|
+
};
|
|
101
|
+
/** ISO timestamp the ledger was recorded. */
|
|
102
|
+
recordedAt: string;
|
|
103
|
+
/** snapshot CLI version that produced this ledger. */
|
|
104
|
+
cliVersion: string;
|
|
105
|
+
/** Registry the packages were fetched through (registry-proxy URL). */
|
|
106
|
+
registry: string;
|
|
107
|
+
packages: LedgerPackage[];
|
|
108
|
+
installSteps: LedgerStep[];
|
|
109
|
+
/** FB pin overrides applied this install (name → version). Empty unless FB used. */
|
|
110
|
+
overrides: Record<string, string>;
|
|
111
|
+
/** S1 verification verdict, if the verify pass ran. */
|
|
112
|
+
verification?: LedgerVerification;
|
|
113
|
+
/** AC1.4 core-floor verdict (nested singleton floor), if the assert ran. */
|
|
114
|
+
coreFloor?: LedgerCoreFloor;
|
|
115
|
+
/**
|
|
116
|
+
* DEEP (NOT --depth=0) `npm ls -g <names> --json --all` output captured
|
|
117
|
+
* post-install, stored verbatim. Scoped to the install's npm packages +
|
|
118
|
+
* @ist/adapters-core so NESTED copies are visible — this both (a) recovers
|
|
119
|
+
* "who required version X?" and (b) feeds coreFloorAssert (AC1.4). null if the
|
|
120
|
+
* query failed.
|
|
121
|
+
*/
|
|
122
|
+
dependencyTreeRaw: unknown | null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Accumulates install steps in execution order. One instance per install;
|
|
126
|
+
* threaded through installSnapshot via InstallSnapshotOptions.recorder.
|
|
127
|
+
*/
|
|
128
|
+
export declare class StepRecorder {
|
|
129
|
+
private steps;
|
|
130
|
+
record(step: Omit<LedgerStep, 'order'>): void;
|
|
131
|
+
getSteps(): LedgerStep[];
|
|
132
|
+
}
|
|
133
|
+
/** Path to the ledger file (sits next to current.json). */
|
|
134
|
+
export declare function getLedgerPath(): string;
|
|
135
|
+
export interface ResolvedQuery {
|
|
136
|
+
/** name → { version, tarballUrl } as read from the global tree. */
|
|
137
|
+
map: Map<string, {
|
|
138
|
+
version: string | null;
|
|
139
|
+
tarballUrl: string | null;
|
|
140
|
+
}>;
|
|
141
|
+
/** The raw parsed `npm ls` JSON (for dependencyTreeRaw), or null on failure. */
|
|
142
|
+
raw: unknown | null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Query the globally-installed version + tarball URL for the given package
|
|
146
|
+
* names via a single `npm ls -g ... --json` call, and return the raw tree too.
|
|
147
|
+
* Best-effort: on total failure returns an all-null map and raw=null.
|
|
148
|
+
*
|
|
149
|
+
* NOTE: this is provenance extraction (version + tarball + raw tree), NOT the
|
|
150
|
+
* verify worker's single-name readInstalledNpmVersion(). No duplication of
|
|
151
|
+
* that helper — S3 never imports install-verify.
|
|
152
|
+
*/
|
|
153
|
+
export declare function queryResolvedVersions(names: string[]): ResolvedQuery;
|
|
154
|
+
/**
|
|
155
|
+
* Derive the canonical npm tarball URL for a resolved package.
|
|
156
|
+
*
|
|
157
|
+
* npm 7+ does NOT persist the fetched tarball URL for global installs
|
|
158
|
+
* (`npm ls -g --json` omits `resolved`, package.json is stripped of `_resolved`,
|
|
159
|
+
* and there is no global lockfile). So when the authoritative URL is missing we
|
|
160
|
+
* reconstruct the standard registry path — the same one npm would fetch from the
|
|
161
|
+
* scope's configured registry: `<registry>/<name>/-/<unscoped>-<version>.tgz`.
|
|
162
|
+
*
|
|
163
|
+
* Returns null when the version is unknown (nothing to point at). Best-effort:
|
|
164
|
+
* the registry is the one configured for the scope during install (registry-proxy).
|
|
165
|
+
*/
|
|
166
|
+
export declare function deriveTarballUrl(registry: string, name: string, version: string | null): string | null;
|
|
167
|
+
/**
|
|
168
|
+
* Capture a DEEP dependency tree (`npm ls -g <names> --json --all`) for the
|
|
169
|
+
* ledger's `dependencyTreeRaw` and for coreFloorAssert (AC1.4).
|
|
170
|
+
*
|
|
171
|
+
* ★ Deliberately NOT `--depth=0`: nested copies must be visible (an old
|
|
172
|
+
* @ist/adapters-core buried under another package is exactly what re-fragments
|
|
173
|
+
* the registry). To avoid the cost of dumping the ENTIRE global tree, we scope
|
|
174
|
+
* the query to the install's npm packages + the singleton package — with filter
|
|
175
|
+
* args, `npm ls` prunes to the paths that reach those names (full depth), which
|
|
176
|
+
* is bounded yet still surfaces every nested copy of the targets.
|
|
177
|
+
*
|
|
178
|
+
* Best-effort: returns null on failure (ledger writing never fails an install).
|
|
179
|
+
*/
|
|
180
|
+
export declare function queryDependencyTree(names: string[]): unknown | null;
|
|
181
|
+
export interface BuildLedgerInput {
|
|
182
|
+
snapshotName: string;
|
|
183
|
+
snapshotVersion: string;
|
|
184
|
+
cliVersion: string;
|
|
185
|
+
registry: string;
|
|
186
|
+
/** Manifest pins for npm packages: name -> version. The "expected" set. */
|
|
187
|
+
expected: Record<string, string>;
|
|
188
|
+
/** Installer used for the npm packages (typically 'npm-proxy'). */
|
|
189
|
+
installer: string;
|
|
190
|
+
steps: LedgerStep[];
|
|
191
|
+
/** FB pin overrides (name -> version), if any. */
|
|
192
|
+
overrides?: Record<string, string>;
|
|
193
|
+
/**
|
|
194
|
+
* DEEP dependency tree for `dependencyTreeRaw` (from queryDependencyTree).
|
|
195
|
+
* When provided it takes precedence over the resolver's shallow tree — the
|
|
196
|
+
* integrator captures a nested-visible tree (AC1.4). null/undefined → fall
|
|
197
|
+
* back to the resolver's tree.
|
|
198
|
+
*/
|
|
199
|
+
dependencyTreeRaw?: unknown | null;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Assemble the ledger: query disk for resolved versions/tarballs, then join
|
|
203
|
+
* against the expected pins and install steps to explain each package's origin.
|
|
204
|
+
* `now` is injected (callers stamp the timestamp) to keep this pure/testable.
|
|
205
|
+
* `resolver` is injectable for tests; defaults to the real `npm ls -g` query.
|
|
206
|
+
*/
|
|
207
|
+
export declare function buildLedger(input: BuildLedgerInput, now: string, resolver?: (names: string[]) => ResolvedQuery): InstallLedger;
|
|
208
|
+
/** Write the ledger to disk. Best-effort — never throws into the caller. */
|
|
209
|
+
export declare function writeLedger(ledger: InstallLedger): boolean;
|
|
210
|
+
/** Read the ledger from disk, or null if absent/unreadable. */
|
|
211
|
+
export declare function readLedger(): InstallLedger | null;
|
|
212
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/lib/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { getConfig } from './config.js';
|
|
5
|
+
/**
|
|
6
|
+
* ============================================================
|
|
7
|
+
* Install Ledger (S3 — beta-pipeline-robustness-2026-08-30 §4)
|
|
8
|
+
* ============================================================
|
|
9
|
+
*
|
|
10
|
+
* Records, at the END of an install, the provenance of every npm package that
|
|
11
|
+
* was installed: the manifest pin we asked for (`expected`), the version that
|
|
12
|
+
* actually landed on disk (`resolved`), the tarball URL it came from, the
|
|
13
|
+
* installer/step that produced it, and the ordered list of install steps.
|
|
14
|
+
*
|
|
15
|
+
* Goal (AC3.1): after any install, "이 버전이 어디서 왔나" ("where did this
|
|
16
|
+
* version come from?") is answerable from the ledger ALONE — no reverse
|
|
17
|
+
* engineering of the global node_modules.
|
|
18
|
+
*
|
|
19
|
+
* SCHEMA OWNERSHIP (manager freeze 2026-08-30): this file is the SSOT for the
|
|
20
|
+
* ledger schema; ledger.json is owned by S3 (this worker). Field names follow
|
|
21
|
+
* the 기획서. S1 (verify) and FB (pin override) live in verify-owned libs and
|
|
22
|
+
* do NOT own this schema. Dependency direction is one-way (verify → ledger):
|
|
23
|
+
* ledger.ts imports NOTHING from install-verify.ts / pin-override.ts.
|
|
24
|
+
*
|
|
25
|
+
* Writing the ledger MUST NOT break an install — every entry point here is
|
|
26
|
+
* best-effort and swallows its own errors.
|
|
27
|
+
*/
|
|
28
|
+
/** Current ledger schema version. Bump on breaking field changes. */
|
|
29
|
+
export const LEDGER_SCHEMA_VERSION = 1;
|
|
30
|
+
/**
|
|
31
|
+
* Accumulates install steps in execution order. One instance per install;
|
|
32
|
+
* threaded through installSnapshot via InstallSnapshotOptions.recorder.
|
|
33
|
+
*/
|
|
34
|
+
export class StepRecorder {
|
|
35
|
+
steps = [];
|
|
36
|
+
record(step) {
|
|
37
|
+
this.steps.push({ order: this.steps.length + 1, ...step });
|
|
38
|
+
}
|
|
39
|
+
getSteps() {
|
|
40
|
+
return this.steps.slice();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Path to the ledger file (sits next to current.json). */
|
|
44
|
+
export function getLedgerPath() {
|
|
45
|
+
const config = getConfig();
|
|
46
|
+
return join(config.configDir, 'ledger.json');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Query the globally-installed version + tarball URL for the given package
|
|
50
|
+
* names via a single `npm ls -g ... --json` call, and return the raw tree too.
|
|
51
|
+
* Best-effort: on total failure returns an all-null map and raw=null.
|
|
52
|
+
*
|
|
53
|
+
* NOTE: this is provenance extraction (version + tarball + raw tree), NOT the
|
|
54
|
+
* verify worker's single-name readInstalledNpmVersion(). No duplication of
|
|
55
|
+
* that helper — S3 never imports install-verify.
|
|
56
|
+
*/
|
|
57
|
+
export function queryResolvedVersions(names) {
|
|
58
|
+
const map = new Map();
|
|
59
|
+
if (names.length === 0)
|
|
60
|
+
return { map, raw: null };
|
|
61
|
+
const parse = (text) => {
|
|
62
|
+
const data = JSON.parse(text);
|
|
63
|
+
const deps = data.dependencies || {};
|
|
64
|
+
for (const name of names) {
|
|
65
|
+
const node = deps[name];
|
|
66
|
+
map.set(name, { version: node?.version ?? null, tarballUrl: node?.resolved ?? null });
|
|
67
|
+
}
|
|
68
|
+
lastRaw = data;
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
let lastRaw = null;
|
|
72
|
+
try {
|
|
73
|
+
// --json gives { dependencies: { "<name>": { version, resolved } } }.
|
|
74
|
+
// depth=0 keeps the tree shallow (top-level globals only).
|
|
75
|
+
const cmd = `npm ls -g ${names.map((n) => JSON.stringify(n)).join(' ')} --json --depth=0`;
|
|
76
|
+
const out = execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
77
|
+
parse(out);
|
|
78
|
+
return { map, raw: lastRaw };
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
// `npm ls` exits non-zero on peer/extraneous warnings yet still prints valid
|
|
82
|
+
// JSON on stdout — recover it before giving up.
|
|
83
|
+
const stdout = err?.stdout;
|
|
84
|
+
if (stdout) {
|
|
85
|
+
try {
|
|
86
|
+
parse(stdout.toString());
|
|
87
|
+
return { map, raw: lastRaw };
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* fall through */
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const name of names)
|
|
94
|
+
map.set(name, { version: null, tarballUrl: null });
|
|
95
|
+
return { map, raw: null };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Derive the canonical npm tarball URL for a resolved package.
|
|
100
|
+
*
|
|
101
|
+
* npm 7+ does NOT persist the fetched tarball URL for global installs
|
|
102
|
+
* (`npm ls -g --json` omits `resolved`, package.json is stripped of `_resolved`,
|
|
103
|
+
* and there is no global lockfile). So when the authoritative URL is missing we
|
|
104
|
+
* reconstruct the standard registry path — the same one npm would fetch from the
|
|
105
|
+
* scope's configured registry: `<registry>/<name>/-/<unscoped>-<version>.tgz`.
|
|
106
|
+
*
|
|
107
|
+
* Returns null when the version is unknown (nothing to point at). Best-effort:
|
|
108
|
+
* the registry is the one configured for the scope during install (registry-proxy).
|
|
109
|
+
*/
|
|
110
|
+
export function deriveTarballUrl(registry, name, version) {
|
|
111
|
+
if (!version)
|
|
112
|
+
return null;
|
|
113
|
+
if (!registry)
|
|
114
|
+
return null;
|
|
115
|
+
const base = registry.replace(/\/+$/, '');
|
|
116
|
+
// Scoped "@ist/sesh" → unscoped "sesh"; unscoped "foo" → "foo".
|
|
117
|
+
const unscoped = name.includes('/') ? name.slice(name.indexOf('/') + 1) : name;
|
|
118
|
+
return `${base}/${name}/-/${unscoped}-${version}.tgz`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Capture a DEEP dependency tree (`npm ls -g <names> --json --all`) for the
|
|
122
|
+
* ledger's `dependencyTreeRaw` and for coreFloorAssert (AC1.4).
|
|
123
|
+
*
|
|
124
|
+
* ★ Deliberately NOT `--depth=0`: nested copies must be visible (an old
|
|
125
|
+
* @ist/adapters-core buried under another package is exactly what re-fragments
|
|
126
|
+
* the registry). To avoid the cost of dumping the ENTIRE global tree, we scope
|
|
127
|
+
* the query to the install's npm packages + the singleton package — with filter
|
|
128
|
+
* args, `npm ls` prunes to the paths that reach those names (full depth), which
|
|
129
|
+
* is bounded yet still surfaces every nested copy of the targets.
|
|
130
|
+
*
|
|
131
|
+
* Best-effort: returns null on failure (ledger writing never fails an install).
|
|
132
|
+
*/
|
|
133
|
+
export function queryDependencyTree(names) {
|
|
134
|
+
if (names.length === 0)
|
|
135
|
+
return null;
|
|
136
|
+
const args = names.map((n) => JSON.stringify(n)).join(' ');
|
|
137
|
+
const cmd = `npm ls -g ${args} --json --all`;
|
|
138
|
+
try {
|
|
139
|
+
const out = execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
140
|
+
return JSON.parse(out);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
// `npm ls` exits non-zero on peer/extraneous warnings yet still prints valid
|
|
144
|
+
// JSON on stdout — recover it before giving up.
|
|
145
|
+
const stdout = err?.stdout;
|
|
146
|
+
if (stdout) {
|
|
147
|
+
try {
|
|
148
|
+
return JSON.parse(stdout.toString());
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* fall through */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Derive the registry host label from a tarball URL, for resolutionSource. */
|
|
158
|
+
function registryHostOf(tarballUrl, fallback) {
|
|
159
|
+
if (!tarballUrl)
|
|
160
|
+
return fallback;
|
|
161
|
+
try {
|
|
162
|
+
return new URL(tarballUrl).host;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return fallback;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Find the step (if any) whose specs targeted this package name. */
|
|
169
|
+
function findInstallingStep(name, steps) {
|
|
170
|
+
// Prefer the LAST step that targeted the package: fallbacks run after a failed
|
|
171
|
+
// batch, so the later step is the authoritative one.
|
|
172
|
+
let found;
|
|
173
|
+
for (const step of steps) {
|
|
174
|
+
if (step.specs.some((s) => s === name || s.startsWith(`${name}@`))) {
|
|
175
|
+
found = step;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return found;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Assemble the ledger: query disk for resolved versions/tarballs, then join
|
|
182
|
+
* against the expected pins and install steps to explain each package's origin.
|
|
183
|
+
* `now` is injected (callers stamp the timestamp) to keep this pure/testable.
|
|
184
|
+
* `resolver` is injectable for tests; defaults to the real `npm ls -g` query.
|
|
185
|
+
*/
|
|
186
|
+
export function buildLedger(input, now, resolver = queryResolvedVersions) {
|
|
187
|
+
const names = Object.keys(input.expected);
|
|
188
|
+
const { map: resolvedMap, raw } = resolver(names);
|
|
189
|
+
// Prefer the injected DEEP tree (nested-visible) for dependencyTreeRaw; the
|
|
190
|
+
// resolver's shallow (--depth=0) tree is only a fallback for provenance.
|
|
191
|
+
const dependencyTreeRaw = input.dependencyTreeRaw !== undefined ? input.dependencyTreeRaw : raw;
|
|
192
|
+
const packages = [...names].sort().map((name) => {
|
|
193
|
+
const expected = input.expected[name] ?? null;
|
|
194
|
+
const resolvedInfo = resolvedMap.get(name) ?? { version: null, tarballUrl: null };
|
|
195
|
+
const resolved = resolvedInfo.version;
|
|
196
|
+
// Prefer the authoritative tarball URL from `npm ls` if present; npm 7+ does
|
|
197
|
+
// not persist it for globals, so fall back to the canonical registry path
|
|
198
|
+
// derived from the configured registry + resolved version (provenance
|
|
199
|
+
// completeness). null only when the version itself is unknown.
|
|
200
|
+
const tarballUrl = resolvedInfo.tarballUrl ?? deriveTarballUrl(input.registry, name, resolved);
|
|
201
|
+
const step = findInstallingStep(name, input.steps);
|
|
202
|
+
const host = registryHostOf(tarballUrl, registryHostOf(input.registry, input.registry));
|
|
203
|
+
const parts = [];
|
|
204
|
+
parts.push(resolved
|
|
205
|
+
? `resolved ${resolved} from ${host}`
|
|
206
|
+
: `not found on disk (expected ${expected ?? 'unknown'})`);
|
|
207
|
+
if (step) {
|
|
208
|
+
parts.push(`via ${step.installer} (${step.phase} step #${step.order}, ${step.result})`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
parts.push(`via ${input.installer}`);
|
|
212
|
+
}
|
|
213
|
+
if (expected && resolved && expected !== resolved) {
|
|
214
|
+
parts.push(`⚠ manifest expected ${expected} — DIVERGED`);
|
|
215
|
+
}
|
|
216
|
+
else if (expected) {
|
|
217
|
+
parts.push(`manifest pin ${expected}`);
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
name,
|
|
221
|
+
expected,
|
|
222
|
+
resolved,
|
|
223
|
+
tarballUrl,
|
|
224
|
+
resolutionSource: parts.join('; '),
|
|
225
|
+
installer: step?.installer ?? input.installer,
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
schemaVersion: LEDGER_SCHEMA_VERSION,
|
|
230
|
+
snapshot: { name: input.snapshotName, version: input.snapshotVersion },
|
|
231
|
+
recordedAt: now,
|
|
232
|
+
cliVersion: input.cliVersion,
|
|
233
|
+
registry: input.registry,
|
|
234
|
+
packages,
|
|
235
|
+
installSteps: input.steps,
|
|
236
|
+
overrides: input.overrides ?? {},
|
|
237
|
+
dependencyTreeRaw,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/** Write the ledger to disk. Best-effort — never throws into the caller. */
|
|
241
|
+
export function writeLedger(ledger) {
|
|
242
|
+
try {
|
|
243
|
+
const path = getLedgerPath();
|
|
244
|
+
const dir = dirname(path);
|
|
245
|
+
if (!existsSync(dir))
|
|
246
|
+
mkdirSync(dir, { recursive: true });
|
|
247
|
+
writeFileSync(path, JSON.stringify(ledger, null, 2));
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** Read the ledger from disk, or null if absent/unreadable. */
|
|
255
|
+
export function readLedger() {
|
|
256
|
+
try {
|
|
257
|
+
const path = getLedgerPath();
|
|
258
|
+
if (!existsSync(path))
|
|
259
|
+
return null;
|
|
260
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/lib/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FB — Pin override fallback (hotfix path).
|
|
3
|
+
*
|
|
4
|
+
* `snapshot install @ist/beta --pin @ist/sesh@0.4.0` (repeatable) lets an owner
|
|
5
|
+
* override a single package's version WITHOUT re-publishing the whole manifest.
|
|
6
|
+
* This is the "1-package hotfix / pullback" lever from
|
|
7
|
+
* architecture/beta-pipeline-robustness-2026-08-30 §4 (FB).
|
|
8
|
+
*
|
|
9
|
+
* Overrides are exact-pin only (same reproducibility rule as publish) and are
|
|
10
|
+
* recorded in the install ledger so the override leaves a trace (AC FB.2).
|
|
11
|
+
*/
|
|
12
|
+
export interface PinOverride {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
}
|
|
16
|
+
/** Thrown when a --pin spec is malformed (fail-loud; never silently ignored). */
|
|
17
|
+
export declare class PinParseError extends Error {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a single `--pin` spec of the form `<name>@<exact-version>`.
|
|
21
|
+
*
|
|
22
|
+
* Handles scoped names ("@ist/sesh@0.4.0") by splitting on the LAST '@'. The
|
|
23
|
+
* version must be an exact semver — ranges/tags/wildcards are rejected so an
|
|
24
|
+
* override cannot re-introduce the non-determinism it exists to fix.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parsePin(spec: string): PinOverride;
|
|
27
|
+
/**
|
|
28
|
+
* Parse a repeatable list of `--pin` specs into an override map (name → version).
|
|
29
|
+
* A later spec for the same name wins (last-write). Throws on the first invalid
|
|
30
|
+
* spec (fail-loud).
|
|
31
|
+
*/
|
|
32
|
+
export declare function parsePins(specs: string[] | undefined): Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Apply pin overrides to an install map, returning a NEW map (input untouched).
|
|
35
|
+
* Only overrides packages that are already present in the map — an override for
|
|
36
|
+
* a package the snapshot doesn't declare is surfaced by the caller (see
|
|
37
|
+
* `unmatchedOverrides`) rather than silently injected.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyPinOverrides(installMap: Record<string, string>, overrides: Record<string, string>): Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* Return the override names that did NOT match any package in the install map.
|
|
42
|
+
* The caller warns on these (a --pin for a package not in the snapshot is almost
|
|
43
|
+
* always a typo).
|
|
44
|
+
*/
|
|
45
|
+
export declare function unmatchedOverrides(installMap: Record<string, string>, overrides: Record<string, string>): string[];
|
|
46
|
+
/**
|
|
47
|
+
* The effective version for a package given a set of overrides — the override
|
|
48
|
+
* if one exists, otherwise the manifest version. Used to thread overrides
|
|
49
|
+
* through the recursive installer so a base-snapshot layer cannot clobber an
|
|
50
|
+
* override with its original pin.
|
|
51
|
+
*/
|
|
52
|
+
export declare function effectiveVersion(name: string, version: string, overrides: Record<string, string>): string;
|
|
53
|
+
//# sourceMappingURL=pin-override.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-override.d.ts","sourceRoot":"","sources":["../../src/lib/pin-override.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iFAAiF;AACjF,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAE3C;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAqBlD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,EAAE,CAEV;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAER"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isExactSemver } from './version-validator.js';
|
|
2
|
+
/** Thrown when a --pin spec is malformed (fail-loud; never silently ignored). */
|
|
3
|
+
export class PinParseError extends Error {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parse a single `--pin` spec of the form `<name>@<exact-version>`.
|
|
7
|
+
*
|
|
8
|
+
* Handles scoped names ("@ist/sesh@0.4.0") by splitting on the LAST '@'. The
|
|
9
|
+
* version must be an exact semver — ranges/tags/wildcards are rejected so an
|
|
10
|
+
* override cannot re-introduce the non-determinism it exists to fix.
|
|
11
|
+
*/
|
|
12
|
+
export function parsePin(spec) {
|
|
13
|
+
const trimmed = spec.trim();
|
|
14
|
+
const atIdx = trimmed.lastIndexOf('@');
|
|
15
|
+
// atIdx <= 0 → no version separator, or only the leading scope '@'.
|
|
16
|
+
if (atIdx <= 0) {
|
|
17
|
+
throw new PinParseError(`Invalid --pin "${spec}": expected <name>@<version> (e.g. @ist/sesh@0.4.0)`);
|
|
18
|
+
}
|
|
19
|
+
const name = trimmed.substring(0, atIdx);
|
|
20
|
+
const version = trimmed.substring(atIdx + 1);
|
|
21
|
+
if (!name) {
|
|
22
|
+
throw new PinParseError(`Invalid --pin "${spec}": missing package name`);
|
|
23
|
+
}
|
|
24
|
+
if (!isExactSemver(version)) {
|
|
25
|
+
throw new PinParseError(`Invalid --pin "${spec}": "${version}" is not an exact semver ` +
|
|
26
|
+
`(ranges, tags, and wildcards are not allowed for overrides)`);
|
|
27
|
+
}
|
|
28
|
+
return { name, version };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse a repeatable list of `--pin` specs into an override map (name → version).
|
|
32
|
+
* A later spec for the same name wins (last-write). Throws on the first invalid
|
|
33
|
+
* spec (fail-loud).
|
|
34
|
+
*/
|
|
35
|
+
export function parsePins(specs) {
|
|
36
|
+
const overrides = {};
|
|
37
|
+
if (!specs)
|
|
38
|
+
return overrides;
|
|
39
|
+
for (const spec of specs) {
|
|
40
|
+
const { name, version } = parsePin(spec);
|
|
41
|
+
overrides[name] = version;
|
|
42
|
+
}
|
|
43
|
+
return overrides;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Apply pin overrides to an install map, returning a NEW map (input untouched).
|
|
47
|
+
* Only overrides packages that are already present in the map — an override for
|
|
48
|
+
* a package the snapshot doesn't declare is surfaced by the caller (see
|
|
49
|
+
* `unmatchedOverrides`) rather than silently injected.
|
|
50
|
+
*/
|
|
51
|
+
export function applyPinOverrides(installMap, overrides) {
|
|
52
|
+
const out = { ...installMap };
|
|
53
|
+
for (const [name, version] of Object.entries(overrides)) {
|
|
54
|
+
if (name in out) {
|
|
55
|
+
out[name] = version;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Return the override names that did NOT match any package in the install map.
|
|
62
|
+
* The caller warns on these (a --pin for a package not in the snapshot is almost
|
|
63
|
+
* always a typo).
|
|
64
|
+
*/
|
|
65
|
+
export function unmatchedOverrides(installMap, overrides) {
|
|
66
|
+
return Object.keys(overrides).filter((name) => !(name in installMap));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The effective version for a package given a set of overrides — the override
|
|
70
|
+
* if one exists, otherwise the manifest version. Used to thread overrides
|
|
71
|
+
* through the recursive installer so a base-snapshot layer cannot clobber an
|
|
72
|
+
* override with its original pin.
|
|
73
|
+
*/
|
|
74
|
+
export function effectiveVersion(name, version, overrides) {
|
|
75
|
+
return overrides[name] ?? version;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=pin-override.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-override.js","sourceRoot":"","sources":["../../src/lib/pin-override.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAmBvD,iFAAiF;AACjF,MAAM,OAAO,aAAc,SAAQ,KAAK;CAAG;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,oEAAoE;IACpE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,aAAa,CACrB,kBAAkB,IAAI,qDAAqD,CAC5E,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,aAAa,CAAC,kBAAkB,IAAI,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,aAAa,CACrB,kBAAkB,IAAI,OAAO,OAAO,2BAA2B;YAC7D,6DAA6D,CAChE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAA2B;IACnD,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzC,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkC,EAClC,SAAiC;IAEjC,MAAM,GAAG,GAA2B,EAAE,GAAG,UAAU,EAAE,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACxD,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAkC,EAClC,SAAiC;IAEjC,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,SAAiC;IAEjC,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;AACpC,CAAC"}
|