dsh-plugin-upgrader 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Reading the profile's writer lock, and explaining a timeout on it.
3
+ *
4
+ * The harness serializes writers of `profile/package.json` through a `wx`-created
5
+ * sibling, `package.json.lock`, that records the holder's pid. The manager takes
6
+ * that lock with a two-minute budget; the shared `atomic-write` default for a
7
+ * caller that states none is two seconds. Both have been observed as the last
8
+ * thing an upgrade said before it failed, and the message names a file and a pid
9
+ * nobody watching the tab can act on:
10
+ *
11
+ * atomic-write: timed out waiting for the writer lock at …/package.json.lock
12
+ *
13
+ * Two things are worth doing with that. Before touching the manifest, look at
14
+ * the lock: an entry cannot be dropped while somebody else is rewriting the file,
15
+ * and finding that out first is the difference between a refusal and a profile
16
+ * left without its dependency. And when the manager's own run does time out,
17
+ * say what it means instead of relaying the internal sentence.
18
+ *
19
+ * `atomic-write` never takes over a lock whose recorded pid is its own
20
+ * (`holderExited` returns false for `process.pid`), so a nested acquisition
21
+ * cannot succeed by waiting: it always ends in exactly this timeout. That is the
22
+ * most likely way a step ends up holding a lock it can never get.
23
+ *
24
+ * @module dsh-plugin-upgrader/lib/lock
25
+ */
26
+ import { readFileSync } from 'node:fs';
27
+ import { join } from 'node:path';
28
+ import { MANIFEST_FILE } from './manifest.js';
29
+ /** The lock file's name, as `atomic-write` derives it. */
30
+ export const LOCK_FILE = `${MANIFEST_FILE}.lock`;
31
+ /**
32
+ * Whether a pid is running, by the same signal-probe `atomic-write` uses.
33
+ *
34
+ * @param pid - the process id to probe.
35
+ * @returns true when the process exists and this account may signal it.
36
+ */
37
+ export function pidIsAlive(pid) {
38
+ if (!Number.isInteger(pid) || pid <= 0 || pid > 2147483647)
39
+ return false;
40
+ try {
41
+ process.kill(pid, 0);
42
+ return true;
43
+ }
44
+ catch (error) {
45
+ // EPERM means the process exists under another account: still a holder.
46
+ return error?.code !== 'ESRCH';
47
+ }
48
+ }
49
+ /**
50
+ * Read the profile's writer lock.
51
+ *
52
+ * A lock whose pid cannot be read is reported as alive: the file exists, so
53
+ * somebody created it, and treating an unreadable record as free would defeat
54
+ * the lock it represents.
55
+ *
56
+ * @param dir - the profile directory.
57
+ * @param alive - liveness probe, injectable for tests.
58
+ * @returns the record, or `undefined` when nothing holds the lock.
59
+ */
60
+ export function readWriterLock(dir, alive = pidIsAlive) {
61
+ let raw;
62
+ try {
63
+ raw = readFileSync(join(dir, LOCK_FILE), 'utf8');
64
+ }
65
+ catch {
66
+ return undefined;
67
+ }
68
+ const match = /^(\d+)\s*$/u.exec(raw.trim());
69
+ if (match === null)
70
+ return { alive: true };
71
+ const pid = Number(match[1]);
72
+ return { pid, alive: alive(pid) };
73
+ }
74
+ /**
75
+ * Whether a failure message is the writer-lock timeout.
76
+ *
77
+ * Matched on the `atomic-write` prefix and the sentence rather than on the path:
78
+ * the message is assembled by another package, and the path is the one part of
79
+ * it that varies per profile.
80
+ *
81
+ * @param message - a failure message, or anything that might be one.
82
+ * @returns whether this is the lock timeout.
83
+ */
84
+ export function isWriterLockTimeout(message) {
85
+ return typeof message === 'string' && /atomic-write: timed out waiting for the writer lock/u.test(message);
86
+ }
87
+ /**
88
+ * What the operator can do about a held lock, in both languages.
89
+ *
90
+ * Both travel together for the same reason `restartHint` does: the job log is one
91
+ * stream shown to readers of either language, and the panel cannot translate a
92
+ * sentence the host composed.
93
+ *
94
+ * @param lock - what the lock said, when it was read.
95
+ * @returns one bilingual sentence.
96
+ */
97
+ export function describeWriterLock(lock) {
98
+ if (lock !== undefined && lock.alive) {
99
+ const zh = '另一个操作正在改写 profile 的 package.json(写入锁仍被占用);等它结束再试';
100
+ const en = 'another operation is rewriting the profile manifest and still holds its writer lock; retry once it finishes';
101
+ return `${zh} / ${en}`;
102
+ }
103
+ const zh = 'profile 写入锁没有被释放,可能是上一次升级被强制结束时留下的;重启 DSH 后会自行恢复';
104
+ const en = 'the profile writer lock was never released, most likely left by an upgrade that was killed; restarting DSH clears it';
105
+ return `${zh} / ${en}`;
106
+ }
107
+ /**
108
+ * Turn a writer-lock timeout into something the operator can act on.
109
+ *
110
+ * The original sentence is kept in brackets rather than dropped: it names the
111
+ * file and comes from the package that raised it, so it is the string to search
112
+ * for in a log or a bug report. What it cannot say is whose fault it is or what
113
+ * to do, which is what the leading sentence is for.
114
+ *
115
+ * Any other message is returned untouched.
116
+ *
117
+ * @param message - the failure message.
118
+ * @param dir - the profile directory, used to read the lock's current state.
119
+ * @returns a message to show, or the original when this is not a lock timeout.
120
+ */
121
+ export function explainLockTimeout(message, dir) {
122
+ if (!isWriterLockTimeout(message))
123
+ return message;
124
+ const lock = dir === undefined ? undefined : readWriterLock(dir);
125
+ return `${describeWriterLock(lock)} [${message}]`;
126
+ }
127
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/host/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,0DAA0D;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,aAAa,OAAO,CAAA;AAahD;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,UAAU;QAAE,OAAO,KAAK,CAAA;IACxE,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wEAAwE;QACxE,OAAQ,KAA4B,EAAE,IAAI,KAAK,OAAO,CAAA;IACxD,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,KAAK,GAAkB,UAAU;IAEjC,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IAC5C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5B,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAA;AACnC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,sDAAsD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;AAC5G,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA4B;IAC7D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,kDAAkD,CAAA;QAC7D,MAAM,EAAE,GAAG,6GAA6G,CAAA;QACxH,OAAO,GAAG,EAAE,MAAM,EAAE,EAAE,CAAA;IACxB,CAAC;IACD,MAAM,EAAE,GAAG,kDAAkD,CAAA;IAC7D,MAAM,EAAE,GAAG,sHAAsH,CAAA;IACjI,OAAO,GAAG,EAAE,MAAM,EAAE,EAAE,CAAA;AACxB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,GAAuB;IACzE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IACjD,MAAM,IAAI,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAA;IAChE,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,OAAO,GAAG,CAAA;AACnD,CAAC"}
@@ -1,5 +1,25 @@
1
1
  /** Where a profile keeps its manifest. */
2
2
  export declare const MANIFEST_FILE = "package.json";
3
+ /**
4
+ * Where a pending drop is recorded, next to the manifest it belongs to.
5
+ *
6
+ * The drop has to survive a crash to be undoable. Writing the intent to disk
7
+ * before the entry disappears means the next process to load this plugin can
8
+ * put the entry back, instead of inheriting a profile that declares a package
9
+ * it no longer lists — which is how a failed upgrade lost a theme: pnpm spent
10
+ * two minutes verifying a lockfile, the app was restarted, and the dependency
11
+ * entry was never written back.
12
+ */
13
+ export declare const JOURNAL_FILE = "package.json.upgrader-journal.json";
14
+ /** What a drop records, so a later process can undo it. */
15
+ export interface DropJournal {
16
+ /** The package whose entry was removed. */
17
+ name: string;
18
+ /** The range the entry carried, so it goes back byte for byte. */
19
+ spec: string;
20
+ /** When the drop happened; only ever used for diagnostics. */
21
+ at: number;
22
+ }
3
23
  /**
4
24
  * Resolve the profile directory the running host is managing.
5
25
  *
@@ -20,6 +40,70 @@ export type DropResult = {
20
40
  kind: 'unavailable';
21
41
  reason: string;
22
42
  };
43
+ /**
44
+ * Forget the pending drop.
45
+ *
46
+ * Called once the entry is back, or once pnpm has written a new version in its
47
+ * place — either way there is nothing left to undo.
48
+ *
49
+ * @param dir - the profile directory.
50
+ */
51
+ export declare function clearJournal(dir: string): void;
52
+ /**
53
+ * Read the pending drop, when one is recorded.
54
+ *
55
+ * @param dir - the profile directory.
56
+ * @returns the record, or `undefined` when there is none to read.
57
+ */
58
+ export declare function readJournal(dir: string): DropJournal | undefined;
59
+ /** What a recovery pass did, for the caller to report. */
60
+ export type RecoveryResult = {
61
+ kind: 'none';
62
+ } | {
63
+ kind: 'restored';
64
+ name: string;
65
+ spec: string;
66
+ } | {
67
+ kind: 'settled';
68
+ name: string;
69
+ } | {
70
+ kind: 'failed';
71
+ name: string;
72
+ reason: string;
73
+ };
74
+ /**
75
+ * Undo a drop whose install never finished.
76
+ *
77
+ * This is the crash repair. A drop writes its intent to the journal before the
78
+ * entry leaves the manifest, so whichever process loads the plugin next can see
79
+ * that an entry is missing and put it back. Two outcomes are possible:
80
+ *
81
+ * - the entry is still absent, so pnpm never wrote the new version: restore it;
82
+ * - the entry is present, so the install landed and simply outlived the drop
83
+ * record: forget the record and leave the manifest alone.
84
+ *
85
+ * Doing this at load time rather than at next upgrade matters: a profile with a
86
+ * package on disk and no dependency entry is invisible to the manager, so the
87
+ * plugin cannot be upgraded, removed or seen again until somebody edits JSON by
88
+ * hand.
89
+ *
90
+ * @param dir - the profile directory.
91
+ * @returns what happened.
92
+ */
93
+ export declare function recoverPendingDrop(dir: string): RecoveryResult;
94
+ /**
95
+ * Forget the pending drop once the entry is visibly back.
96
+ *
97
+ * Called after an install reported success. pnpm is what writes the new version
98
+ * into the manifest, so a success that left no entry means the write did not
99
+ * happen after all — and then the record is the only thing that can repair the
100
+ * profile, so it stays until it can actually be settled.
101
+ *
102
+ * @param dir - the profile directory.
103
+ * @param name - the package whose entry should be present.
104
+ * @returns whether the entry was there, and the record therefore cleared.
105
+ */
106
+ export declare function confirmDependency(dir: string, name: string): boolean;
23
107
  /**
24
108
  * Remove one dependency entry, leaving everything else untouched.
25
109
  *
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"AA0BA,0CAA0C;AAC1C,eAAO,MAAM,aAAa,iBAAiB,CAAA;AAE3C;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CASvF;AAED,gDAAgD;AAChD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAsC3C;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAkBpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAgBlF"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"AA0BA,0CAA0C;AAC1C,eAAO,MAAM,aAAa,iBAAiB,CAAA;AAE3C;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,uCAAuC,CAAA;AAEhE,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAA;CACX;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CASvF;AAED,gDAAgD;AAChD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAiE3C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM9C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAiBhE;AAED,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAoC9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQpE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CA6BpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAqBlF"}
@@ -21,10 +21,21 @@
21
21
  *
22
22
  * @module dsh-plugin-upgrader/lib/manifest
23
23
  */
24
- import { readFileSync, writeFileSync, renameSync } from 'node:fs';
24
+ import { readFileSync, writeFileSync, renameSync, rmSync } from 'node:fs';
25
25
  import { join } from 'node:path';
26
26
  /** Where a profile keeps its manifest. */
27
27
  export const MANIFEST_FILE = 'package.json';
28
+ /**
29
+ * Where a pending drop is recorded, next to the manifest it belongs to.
30
+ *
31
+ * The drop has to survive a crash to be undoable. Writing the intent to disk
32
+ * before the entry disappears means the next process to load this plugin can
33
+ * put the entry back, instead of inheriting a profile that declares a package
34
+ * it no longer lists — which is how a failed upgrade lost a theme: pnpm spent
35
+ * two minutes verifying a lockfile, the app was restarted, and the dependency
36
+ * entry was never written back.
37
+ */
38
+ export const JOURNAL_FILE = 'package.json.upgrader-journal.json';
28
39
  /**
29
40
  * Resolve the profile directory the running host is managing.
30
41
  *
@@ -80,6 +91,160 @@ function writeManifest(dir, manifest) {
80
91
  writeFileSync(temporary, `${JSON.stringify(manifest, undefined, 2)}\n`, 'utf8');
81
92
  renameSync(temporary, target);
82
93
  }
94
+ /**
95
+ * Record that an entry is about to disappear, before it disappears.
96
+ *
97
+ * Written with the same temp-then-rename dance as the manifest: a half-written
98
+ * journal would be worse than none, because recovery trusts it.
99
+ *
100
+ * @param dir - the profile directory.
101
+ * @param journal - what is being dropped.
102
+ * @returns whether the record reached the disk.
103
+ */
104
+ function writeJournal(dir, journal) {
105
+ const target = join(dir, JOURNAL_FILE);
106
+ const temporary = `${target}.upgrader-tmp`;
107
+ try {
108
+ writeFileSync(temporary, `${JSON.stringify(journal, undefined, 2)}\n`, 'utf8');
109
+ renameSync(temporary, target);
110
+ return true;
111
+ }
112
+ catch {
113
+ try {
114
+ rmSync(temporary, { force: true });
115
+ }
116
+ catch {
117
+ // Nothing left to clean up: the failure is already being reported.
118
+ }
119
+ return false;
120
+ }
121
+ }
122
+ /**
123
+ * Forget the pending drop.
124
+ *
125
+ * Called once the entry is back, or once pnpm has written a new version in its
126
+ * place — either way there is nothing left to undo.
127
+ *
128
+ * @param dir - the profile directory.
129
+ */
130
+ export function clearJournal(dir) {
131
+ try {
132
+ rmSync(join(dir, JOURNAL_FILE), { force: true });
133
+ }
134
+ catch {
135
+ // A journal that cannot be removed only causes one more no-op recovery.
136
+ }
137
+ }
138
+ /**
139
+ * Read the pending drop, when one is recorded.
140
+ *
141
+ * @param dir - the profile directory.
142
+ * @returns the record, or `undefined` when there is none to read.
143
+ */
144
+ export function readJournal(dir) {
145
+ let raw;
146
+ try {
147
+ raw = readFileSync(join(dir, JOURNAL_FILE), 'utf8');
148
+ }
149
+ catch {
150
+ return undefined;
151
+ }
152
+ try {
153
+ const parsed = JSON.parse(raw);
154
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
155
+ return undefined;
156
+ const record = parsed;
157
+ if (typeof record.name !== 'string' || record.name === '')
158
+ return undefined;
159
+ if (typeof record.spec !== 'string')
160
+ return undefined;
161
+ return { name: record.name, spec: record.spec, at: typeof record.at === 'number' ? record.at : 0 };
162
+ }
163
+ catch {
164
+ return undefined;
165
+ }
166
+ }
167
+ /**
168
+ * Undo a drop whose install never finished.
169
+ *
170
+ * This is the crash repair. A drop writes its intent to the journal before the
171
+ * entry leaves the manifest, so whichever process loads the plugin next can see
172
+ * that an entry is missing and put it back. Two outcomes are possible:
173
+ *
174
+ * - the entry is still absent, so pnpm never wrote the new version: restore it;
175
+ * - the entry is present, so the install landed and simply outlived the drop
176
+ * record: forget the record and leave the manifest alone.
177
+ *
178
+ * Doing this at load time rather than at next upgrade matters: a profile with a
179
+ * package on disk and no dependency entry is invisible to the manager, so the
180
+ * plugin cannot be upgraded, removed or seen again until somebody edits JSON by
181
+ * hand.
182
+ *
183
+ * @param dir - the profile directory.
184
+ * @returns what happened.
185
+ */
186
+ export function recoverPendingDrop(dir) {
187
+ const journal = readJournal(dir);
188
+ if (journal === undefined) {
189
+ clearJournal(dir);
190
+ return { kind: 'none' };
191
+ }
192
+ const { manifest, error } = readManifest(dir);
193
+ if (manifest === undefined)
194
+ return { kind: 'failed', name: journal.name, reason: error ?? 'unreadable manifest' };
195
+ const dependencies = manifest.dependencies;
196
+ const record = dependencies !== null && typeof dependencies === 'object' && !Array.isArray(dependencies)
197
+ ? dependencies
198
+ : undefined;
199
+ if (record === undefined) {
200
+ // No dependencies at all: the manifest was rewritten by something else, so
201
+ // the record no longer describes it. Dropping the record is the only safe
202
+ // move — inventing a `dependencies` object could undo a deliberate edit.
203
+ clearJournal(dir);
204
+ return { kind: 'none' };
205
+ }
206
+ if (Object.hasOwn(record, journal.name)) {
207
+ clearJournal(dir);
208
+ return { kind: 'settled', name: journal.name };
209
+ }
210
+ record[journal.name] = journal.spec;
211
+ try {
212
+ writeManifest(dir, manifest);
213
+ }
214
+ catch (writeError) {
215
+ return {
216
+ kind: 'failed',
217
+ name: journal.name,
218
+ reason: writeError instanceof Error ? writeError.message : String(writeError),
219
+ };
220
+ }
221
+ clearJournal(dir);
222
+ return { kind: 'restored', name: journal.name, spec: journal.spec };
223
+ }
224
+ /**
225
+ * Forget the pending drop once the entry is visibly back.
226
+ *
227
+ * Called after an install reported success. pnpm is what writes the new version
228
+ * into the manifest, so a success that left no entry means the write did not
229
+ * happen after all — and then the record is the only thing that can repair the
230
+ * profile, so it stays until it can actually be settled.
231
+ *
232
+ * @param dir - the profile directory.
233
+ * @param name - the package whose entry should be present.
234
+ * @returns whether the entry was there, and the record therefore cleared.
235
+ */
236
+ export function confirmDependency(dir, name) {
237
+ const { manifest } = readManifest(dir);
238
+ if (manifest === undefined)
239
+ return false;
240
+ const dependencies = manifest.dependencies;
241
+ if (dependencies === null || typeof dependencies !== 'object' || Array.isArray(dependencies))
242
+ return false;
243
+ if (!Object.hasOwn(dependencies, name))
244
+ return false;
245
+ clearJournal(dir);
246
+ return true;
247
+ }
83
248
  /**
84
249
  * Remove one dependency entry, leaving everything else untouched.
85
250
  *
@@ -98,17 +263,28 @@ export function dropDependency(dir, name) {
98
263
  if (!Object.hasOwn(record, name))
99
264
  return { kind: 'absent' };
100
265
  const previous = record[name];
266
+ const spec = typeof previous === 'string' ? previous : '';
267
+ /*
268
+ * Journal first, then the manifest. The other order leaves a window where the
269
+ * entry is gone and nothing on disk remembers what it was — the exact state
270
+ * that turned a killed install into a missing theme.
271
+ */
272
+ if (!writeJournal(dir, { name, spec, at: Date.now() })) {
273
+ return { kind: 'unavailable', reason: 'could not record the pending drop' };
274
+ }
101
275
  delete record[name];
102
276
  try {
103
277
  writeManifest(dir, manifest);
104
278
  }
105
279
  catch (writeError) {
280
+ // The manifest still has the entry, so the record is stale: remove it.
281
+ clearJournal(dir);
106
282
  return {
107
283
  kind: 'unavailable',
108
284
  reason: writeError instanceof Error ? writeError.message : String(writeError),
109
285
  };
110
286
  }
111
- return { kind: 'dropped', dependency: typeof previous === 'string' ? previous : '' };
287
+ return { kind: 'dropped', dependency: spec };
112
288
  }
113
289
  /**
114
290
  * Put a dropped entry back, for when the install did not reach pnpm.
@@ -132,15 +308,19 @@ export function restoreDependency(dir, name, spec) {
132
308
  : undefined;
133
309
  if (record === undefined)
134
310
  return false;
135
- if (Object.hasOwn(record, name))
136
- return true;
137
- record[name] = spec;
138
- try {
139
- writeManifest(dir, manifest);
140
- return true;
141
- }
142
- catch {
143
- return false;
311
+ const present = Object.hasOwn(record, name);
312
+ if (!present) {
313
+ record[name] = spec;
314
+ try {
315
+ writeManifest(dir, manifest);
316
+ }
317
+ catch {
318
+ return false;
319
+ }
144
320
  }
321
+ // The entry is on disk either way, so the pending record has served its
322
+ // purpose: leaving it would make the next load try to restore it again.
323
+ clearJournal(dir);
324
+ return true;
145
325
  }
146
326
  //# sourceMappingURL=manifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,14 @@ export interface OverviewRow {
25
25
  tags: Record<string, string>;
26
26
  totalVersions: number;
27
27
  versionError?: string;
28
+ /**
29
+ * Releases the upstream registry has that the configured one does not.
30
+ *
31
+ * Newest first. Present only when the profile installs from a mirror that is
32
+ * behind: the tab names them so a lagging mirror is visible instead of looking
33
+ * like an up-to-date package.
34
+ */
35
+ mirrorMissing?: string[];
28
36
  }
29
37
  /** The whole overview response body. */
30
38
  export interface Overview {
@@ -1 +1 @@
1
- {"version":3,"file":"overview.d.ts","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"AAWA,OAAO,EAAkD,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7F,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAuC9G,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAA;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAA;IACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,WAAW,EAAE,CAAA;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC/B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,QAAQ,CAAC,CAwHnB"}
1
+ {"version":3,"file":"overview.d.ts","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"AAWA,OAAO,EAAkD,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7F,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAuC9G,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAA;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAA;IACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,WAAW,EAAE,CAAA;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC/B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,QAAQ,CAAC,CAuInB"}
@@ -10,7 +10,7 @@
10
10
  import { compareVersions } from './version.js';
11
11
  import { repoUrlOf } from './repo.js';
12
12
  import { inlineIcon, pickText, registryBase, sourceKind } from './bundle.js';
13
- import { cachedTags, fetchPackument, shapePackument, PACKUMENT_CONCURRENCY, } from './registry.js';
13
+ import { cachedTags, fetchPackument, shapePackument, versionsMissingFromMirror, PACKUMENT_CONCURRENCY, } from './registry.js';
14
14
  /** Inline data-URL icons above this size are dropped from the overview payload. */
15
15
  const INLINE_ICON_LIMIT = 2048;
16
16
  /**
@@ -151,6 +151,16 @@ export async function buildOverview(ctx, cache, tagCache, options) {
151
151
  entry.versionError = shaped.versionError;
152
152
  entry.upgradable =
153
153
  entry.latest !== undefined && compareVersions(entry.latest, bundle.version) > 0;
154
+ /*
155
+ * Ask the upstream registry what this mirror is missing. The mirror's own
156
+ * document cannot answer that — it simply omits the version — so without
157
+ * this the tab looks up to date while npm has a newer release that the
158
+ * profile cannot install. Naming it is the difference between "nothing to do"
159
+ * and "there is a newer version, your mirror has not caught up".
160
+ */
161
+ const missing = await versionsMissingFromMirror(base, bundle.name, bundle.version, cache, options.force === true);
162
+ if (missing.length > 0)
163
+ entry.mirrorMissing = missing;
154
164
  return entry;
155
165
  });
156
166
  rows.sort((left, right) => {
@@ -1 +1 @@
1
- {"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import type { InstallLogChunk, InstallState } from './manager.ts';
14
14
  /** The phase a job reports, including the state before the step starts. */
15
- export type Phase = InstallState['phase'] | 'waiting';
15
+ export type Phase = InstallState['phase'] | 'waiting' | 'verifying';
16
16
  /**
17
17
  * The phase a log chunk puts a job in.
18
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/host/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEjE,2EAA2E;AAC3E,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,SAAS,CAAA;AAErD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,KAAK,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,KAAK,CAOnF"}
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/host/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEjE,2EAA2E;AAC3E,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,WAAW,CAAA;AAWnE;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,KAAK,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,KAAK,CAanF"}
@@ -1,3 +1,11 @@
1
+ /**
2
+ * pnpm's own words for "nothing is downloaded yet, I am checking a lockfile".
3
+ *
4
+ * This is the line that appears first and then sits unchanged for minutes on a
5
+ * healthy profile, which is why the tab looked frozen: the phase stayed on the
6
+ * pre-start state until the install itself printed something.
7
+ */
8
+ const VERIFYING = /verifying lockfile|supply-chain policies/i;
1
9
  /**
2
10
  * The phase a log chunk puts a job in.
3
11
  *
@@ -16,6 +24,13 @@ export function nextPhase(current, chunk) {
16
24
  // A whitespace-only chunk is a keep-alive, not evidence of work.
17
25
  if (typeof chunk.text !== 'string' || chunk.text.trim() === '')
18
26
  return current ?? 'waiting';
27
+ /*
28
+ * Verification is worth naming. It reads as the same frozen phase as the
29
+ * pre-start state, and it is the phase that lasts longest: a cold profile
30
+ * spends minutes here while pnpm asks the registry about every lockfile entry.
31
+ */
32
+ if (VERIFYING.test(chunk.text))
33
+ return 'verifying';
19
34
  return 'installing';
20
35
  }
21
36
  //# sourceMappingURL=progress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/host/progress.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,OAA0B,EAAE,KAAsB;IAC1E,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,iEAAiE;IACjE,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,OAAO,IAAI,SAAS,CAAA;IAC3F,OAAO,YAAY,CAAA;AACrB,CAAC"}
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/host/progress.ts"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,MAAM,SAAS,GAAG,2CAA2C,CAAA;AAE7D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,OAA0B,EAAE,KAAsB;IAC1E,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,iEAAiE;IACjE,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,OAAO,IAAI,SAAS,CAAA;IAC3F;;;;OAIG;IACH,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,WAAW,CAAA;IAClD,OAAO,YAAY,CAAA;AACrB,CAAC"}