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.
- package/CHANGELOG.md +94 -0
- package/lib/client.js +96 -3
- package/lib/host/install.d.ts +0 -9
- package/lib/host/install.d.ts.map +1 -1
- package/lib/host/install.js +37 -5
- package/lib/host/install.js.map +1 -1
- package/lib/host/lock.d.ts +68 -0
- package/lib/host/lock.d.ts.map +1 -0
- package/lib/host/lock.js +127 -0
- package/lib/host/lock.js.map +1 -0
- package/lib/host/manifest.d.ts +84 -0
- package/lib/host/manifest.d.ts.map +1 -1
- package/lib/host/manifest.js +191 -11
- package/lib/host/manifest.js.map +1 -1
- package/lib/host/overview.d.ts +8 -0
- package/lib/host/overview.d.ts.map +1 -1
- package/lib/host/overview.js +11 -1
- package/lib/host/overview.js.map +1 -1
- package/lib/host/progress.d.ts +1 -1
- package/lib/host/progress.d.ts.map +1 -1
- package/lib/host/progress.js +15 -0
- package/lib/host/progress.js.map +1 -1
- package/lib/host/registry.d.ts +36 -0
- package/lib/host/registry.d.ts.map +1 -1
- package/lib/host/registry.js +45 -0
- package/lib/host/registry.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +50 -0
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/host/lock.js
ADDED
|
@@ -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"}
|
package/lib/host/manifest.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/lib/host/manifest.js
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
package/lib/host/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/host/manifest.ts"],"names":[],"mappings":"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"}
|
package/lib/host/overview.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/lib/host/overview.js
CHANGED
|
@@ -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) => {
|
package/lib/host/overview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAsB,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAA;AAC7F,OAAO,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,qBAAqB,GAKtB,MAAM,eAAe,CAAA;AAGtB,mFAAmF;AACnF,MAAM,iBAAiB,GAAG,IAAI,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,UAAU,CACvB,KAAmB,EACnB,KAAa,EACb,IAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAA;IAC1C,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC5F,SAAS,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,CAAA;YAClB,IAAI,IAAI,CAAC,CAAA;YACT,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;YACzB,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAM;YAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,OAAO,OAAO,CAAA;AAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/host/overview.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAsB,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAA;AAC7F,OAAO,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,yBAAyB,EACzB,qBAAqB,GAKtB,MAAM,eAAe,CAAA;AAGtB,mFAAmF;AACnF,MAAM,iBAAiB,GAAG,IAAI,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,UAAU,CACvB,KAAmB,EACnB,KAAa,EACb,IAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAA;IAC1C,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC5F,SAAS,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,CAAA;YAClB,IAAI,IAAI,CAAC,CAAA;YACT,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;YACzB,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAM;YAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,OAAO,OAAO,CAAA;AAChB,CAAC;AAmDD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAgB,EAChB,KAAkC,EAClC,QAA+B,EAC/B,OAAwB;IAExB,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,CAGjC,CAAA;IACb,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9C,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAC/E,CAAC;IACD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;IAC9F,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAA;IACvE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAwB,EAAE;QACrG,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACtC,yEAAyE;QACzE,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,CAAA;QAC9E,MAAM,KAAK,GAAgB;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI;YAClC,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI;YACpC,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI;YAChC,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI;YACpC,OAAO;YACP,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,IAAI;YACJ,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI;YAC1D,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC;YAC7E,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,iBAAiB,CAAC;YACtD,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;YAC3B,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,SAAS;YAClB,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,EAAE;YACR,aAAa,EAAE,CAAC;YAChB,YAAY,EAAE,SAAS;SACxB,CAAA;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,+BAA+B,CAAA;YAClF,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,KAAK,CAAC,YAAY,GAAG,+BAA+B,CAAA;YACpD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB;;;;;;;eAOG;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAA;YACvF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,KAAK,CAAC,YAAY,GAAG,wDAAwD,CAAA;gBAC7E,OAAO,KAAK,CAAA;YACd,CAAC;YACD;;;;;eAKG;YACH,MAAM,MAAM,GAAG,cAAc,CAAC,IAAqB,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;YAC/E,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;YAC5B,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;YAC9B,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAA;YAChC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;YACxB,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAA;YACpE,KAAK,CAAC,YAAY,GAAG,4EAA4E,CAAA;YACjG,sEAAsE;YACtE,+DAA+D;YAC/D,KAAK,CAAC,UAAU,GAAG,KAAK,CAAA;YACxB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9C,KAAK,CAAC,YAAY,GAAG,GAAG,IAAI,8BAA8B,CAAA;YAC1D,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAA;QAC9F,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9C,KAAK,CAAC,YAAY,GAAG,KAAK,IAAI,wBAAwB,CAAA;YACtD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAqB,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG,OAAO,KAAK,SAAS;YACpC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAA;QAC/D,MAAM,MAAM,GAAG,cAAc,CAAC,IAAqB,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC9E,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QAC5B,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC9B,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAA;QAChC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QACxB,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAA;QACpE,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAA;QACxC,KAAK,CAAC,UAAU;YACd,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACjF;;;;;;WAMG;QACH,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAC7C,IAAI,EACJ,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,OAAO,EACd,KAAK,EACL,OAAO,CAAC,KAAK,KAAK,IAAI,CACvB,CAAA;QACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAAA;QACrD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACxB,IAAI,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAChE,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAC5C,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;QACvB,QAAQ,EAAE,IAAI;QACd,UAAU;QACV,cAAc,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC5D,OAAO,EAAE,IAAI;KACd,CAAA;AACH,CAAC"}
|
package/lib/host/progress.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/lib/host/progress.js
CHANGED
|
@@ -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
|
package/lib/host/progress.js.map
CHANGED
|
@@ -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"}
|