dsh-plugin-update 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +483 -255
- package/dist/batch-run.d.ts +80 -0
- package/dist/batch-run.js +86 -0
- package/dist/batch.d.ts +111 -0
- package/dist/batch.js +183 -0
- package/dist/changelog-io.d.ts +56 -0
- package/dist/changelog-io.js +258 -0
- package/dist/changelog.d.ts +96 -0
- package/dist/changelog.js +287 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.js +75 -1
- package/dist/commands.d.ts +59 -0
- package/dist/commands.js +60 -4
- package/dist/config.d.ts +48 -0
- package/dist/config.js +9 -1
- package/dist/diag.d.ts +125 -0
- package/dist/diag.js +243 -0
- package/dist/entry.d.ts +60 -0
- package/dist/entry.js +305 -0
- package/dist/gate.d.ts +35 -0
- package/dist/host-batch.d.ts +113 -0
- package/dist/host-batch.js +778 -0
- package/dist/host.d.ts +129 -0
- package/dist/host.js +506 -52
- package/dist/panel-batch.d.ts +151 -0
- package/dist/panel-batch.js +927 -0
- package/dist/panel.d.ts +256 -0
- package/dist/panel.js +1300 -0
- package/dist/ports.d.ts +208 -0
- package/dist/queue.d.ts +109 -0
- package/dist/queue.js +182 -0
- package/dist/reader.d.ts +84 -0
- package/dist/reader.js +65 -6
- package/dist/redaction.d.ts +120 -0
- package/dist/redaction.js +205 -0
- package/dist/service.d.ts +72 -0
- package/dist/service.js +100 -6
- package/dist/store.d.ts +229 -0
- package/dist/store.js +251 -12
- package/package.json +27 -2
package/dist/host.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/host.ts
|
|
2
2
|
import { realpath } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import {
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { sep } from "node:path";
|
|
6
5
|
import {
|
|
7
6
|
DEFAULT_CONFIRMATION_TTL_MS,
|
|
8
7
|
DEFAULT_CHECK_TIMEOUT_MS,
|
|
@@ -11,13 +10,126 @@ import {
|
|
|
11
10
|
resolveUpdateConfig
|
|
12
11
|
} from "./config.js";
|
|
13
12
|
import { manualCommand } from "./commands.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
13
|
+
import { buildDiag } from "./diag.js";
|
|
14
|
+
import { isVersionAllowedInChannel, validRequestId } from "./service.js";
|
|
15
|
+
import { createUpdateDiskPorts, createUpdateExecutor, createUpdateQueuePorts } from "./store.js";
|
|
16
|
+
import { createUpdateReader, defaultHomeDir, resolveProfileName, resolveTargetPackage } from "./reader.js";
|
|
17
|
+
import {
|
|
18
|
+
QUEUE_INTENT_TTL_MS,
|
|
19
|
+
cancelEnqueuedInQueue,
|
|
20
|
+
emptyQueueState,
|
|
21
|
+
enqueueInQueue,
|
|
22
|
+
isHeadOfQueue,
|
|
23
|
+
normalizeQueueState,
|
|
24
|
+
pruneExpiredIntents,
|
|
25
|
+
queuePositionOf,
|
|
26
|
+
releaseOwnerInQueue,
|
|
27
|
+
setOwnerIfFree,
|
|
28
|
+
visibleQueueFor
|
|
29
|
+
} from "./queue.js";
|
|
17
30
|
import { buildPhoneName, buildPhoneNames as buildPhoneNames2, resolveUpdateConfig as resolveUpdateConfig2 } from "./config.js";
|
|
18
31
|
import { parseEventListManifest, checkEventFields, checkEventCounts } from "./gate.js";
|
|
19
|
-
import { containingPackage
|
|
32
|
+
import { containingPackage, defaultHomeDir as defaultHomeDir2, profileNameValid, registrySpec, resolveTargetPackage as resolveTargetPackage2 } from "./reader.js";
|
|
33
|
+
import {
|
|
34
|
+
COPY_BUDGET_CHARS,
|
|
35
|
+
DETAIL_MAX_CHARS,
|
|
36
|
+
DIAG_DROP_ORDER,
|
|
37
|
+
DIAG_INLINE_BUDGET_BYTES,
|
|
38
|
+
DIAG_NEVER_DROP_KEYS,
|
|
39
|
+
ENDORSED_REGISTRY_HOSTS,
|
|
40
|
+
KNOWN_GAP_FILE_URL_PREFIX,
|
|
41
|
+
REDACTED_PATH,
|
|
42
|
+
REDACTED_SECRET,
|
|
43
|
+
REDACTION_RULE_NAMES,
|
|
44
|
+
diagByteLength,
|
|
45
|
+
enforceDiagBudget,
|
|
46
|
+
resolveRegistryHost,
|
|
47
|
+
sanitizeDetail,
|
|
48
|
+
sanitizeForCopy,
|
|
49
|
+
truncateToWordBoundary
|
|
50
|
+
} from "./redaction.js";
|
|
51
|
+
import {
|
|
52
|
+
DIAG_ACTIONS,
|
|
53
|
+
DIAG_KEYS,
|
|
54
|
+
DIAG_KNOWN_TYPES,
|
|
55
|
+
DIAG_STAGE_EXPECT,
|
|
56
|
+
DIAG_STAGES,
|
|
57
|
+
DIAG_VERSION,
|
|
58
|
+
buildDiag as buildDiag2,
|
|
59
|
+
deriveAction,
|
|
60
|
+
deriveRouteMethod,
|
|
61
|
+
deriveStage,
|
|
62
|
+
enforceBudget
|
|
63
|
+
} from "./diag.js";
|
|
64
|
+
import {
|
|
65
|
+
CHANGELOG_ALL_CATEGORIES,
|
|
66
|
+
CHANGELOG_FILENAME,
|
|
67
|
+
CHANGELOG_FOLDED,
|
|
68
|
+
CHANGELOG_MAX_BULLETS_PER_SECTION,
|
|
69
|
+
CHANGELOG_MAX_BULLET_CHARS,
|
|
70
|
+
CHANGELOG_MAX_CHARS,
|
|
71
|
+
CHANGELOG_MAX_ENTRIES,
|
|
72
|
+
CHANGELOG_MUST_SHOW,
|
|
73
|
+
CHANGELOG_NEUTRAL_HINT,
|
|
74
|
+
CHANGELOG_NEUTRAL_LINE,
|
|
75
|
+
changelogForUpdate,
|
|
76
|
+
hasVisibleSections,
|
|
77
|
+
isUnreleasedVersion,
|
|
78
|
+
parseChangelog,
|
|
79
|
+
renderChangelogHTML,
|
|
80
|
+
renderChangelogNeutral,
|
|
81
|
+
renderChangelogSection,
|
|
82
|
+
selectChangelogEntries
|
|
83
|
+
} from "./changelog.js";
|
|
84
|
+
import {
|
|
85
|
+
CHANGELOG_DEFAULT_REGISTRY,
|
|
86
|
+
CHANGELOG_FETCH_MAX_BYTES,
|
|
87
|
+
CHANGELOG_TAR_MAX_BYTES,
|
|
88
|
+
CHANGELOG_TARBALL_MAX_BYTES,
|
|
89
|
+
extractChangelogFromTar,
|
|
90
|
+
fetchReleaseChangelogText,
|
|
91
|
+
readInstalledChangelogText
|
|
92
|
+
} from "./changelog-io.js";
|
|
20
93
|
import { createUpdateDiskPorts as createUpdateDiskPorts2, createUpdateExecutor as createUpdateExecutor2, pathsForUpdate, resolveCliEntry } from "./store.js";
|
|
94
|
+
import { SKIPPED_FILE } from "./config.js";
|
|
95
|
+
import {
|
|
96
|
+
addSkipped,
|
|
97
|
+
clearSkipped,
|
|
98
|
+
createSkipDiskPorts,
|
|
99
|
+
isVersionSkipped,
|
|
100
|
+
MAX_SKIPPED_ENTRIES,
|
|
101
|
+
normalizeSkipped,
|
|
102
|
+
skipKey
|
|
103
|
+
} from "./store.js";
|
|
104
|
+
import {
|
|
105
|
+
compareReleaseVersions,
|
|
106
|
+
isPrereleaseVersion,
|
|
107
|
+
isVersionAllowedInChannel as isVersionAllowedInChannel2,
|
|
108
|
+
validReleaseVersion,
|
|
109
|
+
validVersion,
|
|
110
|
+
compareVersions
|
|
111
|
+
} from "./service.js";
|
|
112
|
+
import {
|
|
113
|
+
createUpdateQueuePorts as createUpdateQueuePorts2,
|
|
114
|
+
queuePathsForUpdate,
|
|
115
|
+
QUEUE_DIR_SEGMENT,
|
|
116
|
+
QUEUE_FILE,
|
|
117
|
+
QUEUE_LOCK_FILE,
|
|
118
|
+
QUEUE_LOCK_STALE_MS
|
|
119
|
+
} from "./store.js";
|
|
120
|
+
import {
|
|
121
|
+
QUEUE_INTENT_TTL_MS as QUEUE_INTENT_TTL_MS2,
|
|
122
|
+
cancelEnqueuedInQueue as cancelEnqueuedInQueue2,
|
|
123
|
+
emptyQueueState as emptyQueueState2,
|
|
124
|
+
enqueueInQueue as enqueueInQueue2,
|
|
125
|
+
isHeadOfQueue as isHeadOfQueue2,
|
|
126
|
+
normalizeQueueState as normalizeQueueState2,
|
|
127
|
+
pruneExpiredIntents as pruneExpiredIntents2,
|
|
128
|
+
queuePositionOf as queuePositionOf2,
|
|
129
|
+
releaseOwnerInQueue as releaseOwnerInQueue2,
|
|
130
|
+
setOwnerIfFree as setOwnerIfFree2,
|
|
131
|
+
visibleQueueFor as visibleQueueFor2
|
|
132
|
+
} from "./queue.js";
|
|
21
133
|
let sharedReader = null;
|
|
22
134
|
let sharedReaderKey = "";
|
|
23
135
|
let sharedDesktopPnpm = null;
|
|
@@ -71,10 +183,11 @@ function hash8(s) {
|
|
|
71
183
|
return "00000000";
|
|
72
184
|
}
|
|
73
185
|
}
|
|
74
|
-
async function
|
|
186
|
+
async function tryInferProfileDir(targetDir, targetPackageName) {
|
|
75
187
|
try {
|
|
76
|
-
const dir =
|
|
77
|
-
|
|
188
|
+
const dir = String(targetDir || "");
|
|
189
|
+
if (!dir) return null;
|
|
190
|
+
const marker = `${sep}node_modules${sep}${String(targetPackageName || "").split("/").join(sep)}`;
|
|
78
191
|
const at = dir.lastIndexOf(marker);
|
|
79
192
|
if (at > 0) {
|
|
80
193
|
const candidate = dir.slice(0, at);
|
|
@@ -86,26 +199,148 @@ async function inferProfileDir(loaded, homeDirDefault, targetPackageName) {
|
|
|
86
199
|
}
|
|
87
200
|
} catch {
|
|
88
201
|
}
|
|
89
|
-
return
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
function unknownProfile() {
|
|
205
|
+
return Object.assign(new Error("unknown-profile"), { code: "unknown-profile" });
|
|
90
206
|
}
|
|
91
207
|
async function getSharedReader(pluginId, config, overrides = {}) {
|
|
92
208
|
const env = overrides.env ?? process.env;
|
|
93
209
|
const osHome = overrides.osHome ?? homedir();
|
|
94
210
|
const homeDirDefault = defaultHomeDir(env, osHome);
|
|
95
211
|
const targetPackageName = overrides.targetPackageName ?? config.targetPackageName;
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
212
|
+
const releaseChannel = overrides.releaseChannel ?? config.releaseChannel ?? "stable";
|
|
213
|
+
const explicitTargetDir = typeof overrides.targetPackageDir === "string" && overrides.targetPackageDir ? String(overrides.targetPackageDir) : "";
|
|
214
|
+
const loaded = await resolveTargetPackage(targetPackageName, explicitTargetDir ? { targetPackageDir: explicitTargetDir } : {}).catch(
|
|
215
|
+
() => null
|
|
216
|
+
);
|
|
217
|
+
const runningVersion = overrides.runningVersion ?? (loaded && isVersionAllowedInChannel(loaded.manifest.version, releaseChannel) ? String(loaded.manifest.version) : null);
|
|
218
|
+
if (!runningVersion) throw unknownProfile();
|
|
219
|
+
let profileDirInput;
|
|
220
|
+
if (overrides.profileDir) {
|
|
221
|
+
profileDirInput = String(overrides.profileDir);
|
|
222
|
+
} else {
|
|
223
|
+
const anchorDir = (loaded && loaded.directory ? String(loaded.directory) : "") || explicitTargetDir;
|
|
224
|
+
const inferred = anchorDir ? await tryInferProfileDir(anchorDir, targetPackageName) : null;
|
|
225
|
+
if (!inferred) throw unknownProfile();
|
|
226
|
+
profileDirInput = inferred;
|
|
227
|
+
}
|
|
100
228
|
const homeDirInput = overrides.homeDir ?? config.homeDir ?? homeDirDefault;
|
|
101
229
|
const environmentKind = overrides.environmentKind ?? detectEnvironmentKind(overrides.ctx, resolveProfileName(overrides.profileName, profileDirInput));
|
|
102
230
|
const checkTimeoutMs = overrides.checkTimeoutMs ?? config.checkTimeoutMs;
|
|
103
231
|
const confirmationTtlMs = overrides.confirmationTtlMs ?? config.confirmationTtlMs;
|
|
104
232
|
const installTimeoutMs = overrides.installTimeoutMs ?? config.installTimeoutMs;
|
|
105
233
|
const registryUrl = overrides.registryUrl ?? config.registryUrl;
|
|
106
|
-
const key = `${pluginId}\0${config.prefix}\0${runningVersion}\0${profileDirInput}\0${overrides.profileName ?? ""}\0${homeDirInput}\0${overrides.runInstall ? "exec" : ""}\0${environmentKind}\0${targetPackageName}`;
|
|
234
|
+
const key = `${pluginId}\0${config.prefix}\0${runningVersion}\0${profileDirInput}\0${overrides.profileName ?? ""}\0${homeDirInput}\0${overrides.runInstall ? "exec" : ""}\0${environmentKind}\0${targetPackageName}\0${explicitTargetDir}\0${releaseChannel}`;
|
|
107
235
|
if (sharedReader && sharedReaderKey === key) return sharedReader;
|
|
108
236
|
const disk = overrides.readJob && overrides.writeJob ? null : createUpdateDiskPorts(homeDirInput, pluginId, profileDirInput);
|
|
237
|
+
const queueTtlMs = typeof overrides.queueTtlMs === "number" && Number.isFinite(overrides.queueTtlMs) && overrides.queueTtlMs > 0 ? overrides.queueTtlMs : QUEUE_INTENT_TTL_MS;
|
|
238
|
+
const queueDisk = overrides.readQueue && overrides.writeQueue ? null : disk ? createUpdateQueuePorts(homeDirInput, profileDirInput) : null;
|
|
239
|
+
const queueNow = overrides.now ?? Date.now;
|
|
240
|
+
async function readQueueBestEffort() {
|
|
241
|
+
try {
|
|
242
|
+
if (overrides.readQueue) return normalizeQueueState(await overrides.readQueue());
|
|
243
|
+
if (queueDisk) return normalizeQueueState(await queueDisk.readQueue());
|
|
244
|
+
} catch {
|
|
245
|
+
}
|
|
246
|
+
return emptyQueueState();
|
|
247
|
+
}
|
|
248
|
+
async function writeQueueBestEffort(state) {
|
|
249
|
+
try {
|
|
250
|
+
if (overrides.writeQueue) await overrides.writeQueue(normalizeQueueState(state));
|
|
251
|
+
else if (queueDisk) await queueDisk.writeQueue(state);
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function loadQueuePruned() {
|
|
256
|
+
const raw = await readQueueBestEffort();
|
|
257
|
+
const pruned = pruneExpiredIntents(raw, queueNow(), queueTtlMs);
|
|
258
|
+
if (pruned !== raw) await writeQueueBestEffort(pruned);
|
|
259
|
+
return pruned;
|
|
260
|
+
}
|
|
261
|
+
const baseTryAcquire = overrides.tryAcquireLock ?? disk?.tryAcquireLock;
|
|
262
|
+
const baseRelease = overrides.releaseLock ?? disk?.releaseLock;
|
|
263
|
+
const globalTryAcquire = overrides.tryAcquireGlobalLock ? (lockId) => overrides.tryAcquireGlobalLock(lockId, pluginId, { timeoutMs: installTimeoutMs }) : queueDisk ? (lockId) => queueDisk.tryAcquireGlobalLock(lockId, pluginId, { timeoutMs: installTimeoutMs }) : void 0;
|
|
264
|
+
const globalRelease = overrides.releaseGlobalLock ?? queueDisk?.releaseGlobalLock;
|
|
265
|
+
async function combinedTryAcquire(lockId) {
|
|
266
|
+
try {
|
|
267
|
+
if (globalTryAcquire && !await globalTryAcquire(lockId)) return false;
|
|
268
|
+
if (baseTryAcquire && !await baseTryAcquire(lockId)) {
|
|
269
|
+
if (globalRelease) {
|
|
270
|
+
try {
|
|
271
|
+
await globalRelease(lockId);
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return true;
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async function combinedRelease(lockId) {
|
|
283
|
+
try {
|
|
284
|
+
if (baseRelease) await baseRelease(lockId);
|
|
285
|
+
} catch {
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
if (globalRelease) await globalRelease(lockId);
|
|
289
|
+
} catch {
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const current = await readQueueBestEffort();
|
|
293
|
+
const next = releaseOwnerInQueue(current, pluginId, lockId);
|
|
294
|
+
if (next.released) await writeQueueBestEffort(next.state);
|
|
295
|
+
} catch {
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
let memJobFallback = null;
|
|
299
|
+
async function mirroredWriteJob(job) {
|
|
300
|
+
if (overrides.writeJob) await overrides.writeJob(job);
|
|
301
|
+
else memJobFallback = job;
|
|
302
|
+
try {
|
|
303
|
+
if (!job) return;
|
|
304
|
+
const current = await readQueueBestEffort();
|
|
305
|
+
const pruned = pruneExpiredIntents(current, queueNow(), queueTtlMs);
|
|
306
|
+
if (job.state === "installing" || job.state === "verifying") {
|
|
307
|
+
let next = pruned;
|
|
308
|
+
if (next.owner && next.owner.jobId === job.id) {
|
|
309
|
+
next = {
|
|
310
|
+
version: 1,
|
|
311
|
+
owner: {
|
|
312
|
+
...next.owner,
|
|
313
|
+
requestId: job.requestId ?? next.owner.requestId,
|
|
314
|
+
targetVersion: job.targetVersion ?? next.owner.targetVersion
|
|
315
|
+
},
|
|
316
|
+
waiting: next.waiting.filter((e) => !(e.pluginId === pluginId && (e.requestId ?? null) === (job.requestId ?? null)))
|
|
317
|
+
};
|
|
318
|
+
} else {
|
|
319
|
+
let base = next;
|
|
320
|
+
const age = queueNow() - (typeof base.owner?.startedAt === "number" ? base.owner.startedAt : 0);
|
|
321
|
+
if (base.owner && age > installTimeoutMs) base = { version: 1, owner: null, waiting: base.waiting };
|
|
322
|
+
next = setOwnerIfFree(base, {
|
|
323
|
+
pluginId,
|
|
324
|
+
jobId: job.id,
|
|
325
|
+
requestId: job.requestId,
|
|
326
|
+
targetVersion: job.targetVersion,
|
|
327
|
+
startedAt: queueNow()
|
|
328
|
+
}).state;
|
|
329
|
+
}
|
|
330
|
+
if (next !== pruned) await writeQueueBestEffort(next);
|
|
331
|
+
else if (pruned !== current) await writeQueueBestEffort(pruned);
|
|
332
|
+
} else {
|
|
333
|
+
const released = releaseOwnerInQueue(pruned, pluginId, job.id);
|
|
334
|
+
const out = released.released ? released.state : pruned;
|
|
335
|
+
if (out !== current) await writeQueueBestEffort(out);
|
|
336
|
+
}
|
|
337
|
+
} catch {
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function mirroredReadJob() {
|
|
341
|
+
if (overrides.readJob) return await overrides.readJob() ?? null;
|
|
342
|
+
return memJobFallback;
|
|
343
|
+
}
|
|
109
344
|
const defaultRun = createUpdateExecutor({
|
|
110
345
|
profileName: overrides.profileName ?? null,
|
|
111
346
|
environmentKind,
|
|
@@ -123,31 +358,37 @@ async function getSharedReader(pluginId, config, overrides = {}) {
|
|
|
123
358
|
pluginId,
|
|
124
359
|
log: emitInstallLog
|
|
125
360
|
});
|
|
126
|
-
sharedReader =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
361
|
+
sharedReader = Object.assign(
|
|
362
|
+
createUpdateReader({
|
|
363
|
+
runningVersion,
|
|
364
|
+
profileDir: profileDirInput,
|
|
365
|
+
pluginId,
|
|
366
|
+
profileName: overrides.profileName ?? void 0,
|
|
367
|
+
homeDir: overrides.homeDir,
|
|
368
|
+
targetPackageDir: explicitTargetDir || void 0,
|
|
369
|
+
env,
|
|
370
|
+
osHome,
|
|
371
|
+
fetchImpl: overrides.fetchImpl,
|
|
372
|
+
now: overrides.now,
|
|
373
|
+
randomId: overrides.randomId,
|
|
374
|
+
nodeVersion: overrides.nodeVersion,
|
|
375
|
+
environmentKind,
|
|
376
|
+
targetPackageName,
|
|
377
|
+
registryUrl,
|
|
378
|
+
checkTimeoutMs,
|
|
379
|
+
confirmationTtlMs,
|
|
380
|
+
releaseChannel,
|
|
381
|
+
readInstalled: overrides.readInstalled,
|
|
382
|
+
readJob: mirroredReadJob,
|
|
383
|
+
writeJob: mirroredWriteJob,
|
|
384
|
+
tryAcquireLock: combinedTryAcquire,
|
|
385
|
+
releaseLock: combinedRelease,
|
|
386
|
+
backupJob: overrides.backupJob ?? disk?.backupJob,
|
|
387
|
+
runInstall: overrides.runInstall ?? defaultRun
|
|
388
|
+
}),
|
|
389
|
+
// 跨插件队列的面板侧读写口(#15):与本次解析出的使用范围绑定,面板经电话可选参数消费。
|
|
390
|
+
{ readQueuePruned: loadQueuePruned, writeQueueState: writeQueueBestEffort, queueTtlMs, queueNow }
|
|
391
|
+
);
|
|
151
392
|
sharedReaderKey = key;
|
|
152
393
|
return sharedReader;
|
|
153
394
|
}
|
|
@@ -195,6 +436,22 @@ async function snapWithManual(reader, snapshot, config) {
|
|
|
195
436
|
return { snapshot, manual: null };
|
|
196
437
|
}
|
|
197
438
|
}
|
|
439
|
+
async function readEnvForPanel(reader) {
|
|
440
|
+
try {
|
|
441
|
+
if (typeof reader.readEnv !== "function") return null;
|
|
442
|
+
const env = await reader.readEnv();
|
|
443
|
+
if (!env || typeof env !== "object") return null;
|
|
444
|
+
return {
|
|
445
|
+
profileName: typeof env.profileName === "string" && env.profileName ? env.profileName : null,
|
|
446
|
+
environmentKind: typeof env.environmentKind === "string" && env.environmentKind ? env.environmentKind : null
|
|
447
|
+
};
|
|
448
|
+
} catch {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function wantsEnv(args) {
|
|
453
|
+
return !!args && args["includeEnv"] === true;
|
|
454
|
+
}
|
|
198
455
|
let phoneLogCtx = null;
|
|
199
456
|
function emitInstallLog(level, event, fields) {
|
|
200
457
|
try {
|
|
@@ -202,7 +459,19 @@ function emitInstallLog(level, event, fields) {
|
|
|
202
459
|
} catch {
|
|
203
460
|
}
|
|
204
461
|
}
|
|
205
|
-
function
|
|
462
|
+
function queueArgsOf(args) {
|
|
463
|
+
return {
|
|
464
|
+
includeQueue: !!args && args["includeQueue"] === true,
|
|
465
|
+
showOthers: !!args && args["showOthers"] === true
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function checkExpiredError() {
|
|
469
|
+
return Object.assign(new Error("check-expired"), { code: "check-expired" });
|
|
470
|
+
}
|
|
471
|
+
function updateBusyError() {
|
|
472
|
+
return Object.assign(new Error("update-busy"), { code: "update-busy" });
|
|
473
|
+
}
|
|
474
|
+
function loggedPhone(method, kind, pluginId, fn, diagCtx) {
|
|
206
475
|
return async function(args) {
|
|
207
476
|
const t0 = Date.now();
|
|
208
477
|
const emit = (level, event, fields) => {
|
|
@@ -211,15 +480,47 @@ function loggedPhone(method, kind, pluginId, fn) {
|
|
|
211
480
|
} catch {
|
|
212
481
|
}
|
|
213
482
|
};
|
|
483
|
+
const safeArgs = args && typeof args === "object" ? args : {};
|
|
214
484
|
try {
|
|
215
|
-
const out = await fn(
|
|
485
|
+
const out = await fn(safeArgs);
|
|
216
486
|
const snapshot = out && out.snapshot ? out.snapshot : out;
|
|
217
487
|
emit("info", "host.call", { method, latencyMs: Date.now() - t0, ok: true, kind, pluginId });
|
|
218
|
-
return {
|
|
488
|
+
return {
|
|
489
|
+
ok: true,
|
|
490
|
+
snapshot,
|
|
491
|
+
manual: out && out.snapshot ? out.manual ?? null : null,
|
|
492
|
+
receipt: out && out.receipt ? out.receipt : null,
|
|
493
|
+
// 新增选填(#15):调用方没要时不带该键,老调用形状不变。
|
|
494
|
+
...out && out.queue ? { queue: out.queue } : {},
|
|
495
|
+
// 新增选填:使用范围一栏(只有调用方传了 includeEnv 才带,老调用形状不变)。
|
|
496
|
+
...out && out.env ? { env: out.env } : {}
|
|
497
|
+
};
|
|
219
498
|
} catch (error) {
|
|
220
499
|
const payload = toUpdateErrorPayload(error);
|
|
221
500
|
emit("warn", "host.call.fail", { method, kind, errorHash: hash8(String(error?.message || payload.error)), pluginId });
|
|
222
|
-
|
|
501
|
+
let diag;
|
|
502
|
+
try {
|
|
503
|
+
const cfg = diagCtx?.config;
|
|
504
|
+
const overrides = diagCtx?.readerOverrides ?? {};
|
|
505
|
+
const envRaw = overrides?.environmentKind;
|
|
506
|
+
const runningRaw = overrides?.runningVersion;
|
|
507
|
+
const built = buildDiag({
|
|
508
|
+
errorCode: payload.error,
|
|
509
|
+
phoneKind: kind,
|
|
510
|
+
error,
|
|
511
|
+
args: safeArgs,
|
|
512
|
+
targetPackageName: cfg?.targetPackageName,
|
|
513
|
+
registryUrl: cfg?.registryUrl,
|
|
514
|
+
runningVersion: typeof runningRaw === "string" ? runningRaw : void 0,
|
|
515
|
+
latestVersion: void 0,
|
|
516
|
+
environmentKind: typeof envRaw === "string" ? envRaw : void 0,
|
|
517
|
+
latencyMs: Date.now() - t0
|
|
518
|
+
});
|
|
519
|
+
if (built && typeof built === "object") diag = built;
|
|
520
|
+
} catch {
|
|
521
|
+
diag = void 0;
|
|
522
|
+
}
|
|
523
|
+
return { ok: false, ...payload, ...diag ? { diag } : {} };
|
|
223
524
|
}
|
|
224
525
|
};
|
|
225
526
|
}
|
|
@@ -237,7 +538,12 @@ function createHostUpdate(deps = {}, configInput) {
|
|
|
237
538
|
...readerOverrides,
|
|
238
539
|
profileDir: args && args.profileDir ? String(args.profileDir) : readerOverrides.profileDir
|
|
239
540
|
});
|
|
240
|
-
|
|
541
|
+
const out = await snapWithManual(reader, await reader.status(), config);
|
|
542
|
+
const env = wantsEnv(args) ? { env: await readEnvForPanel(reader) } : {};
|
|
543
|
+
const { includeQueue, showOthers } = queueArgsOf(args);
|
|
544
|
+
if (!includeQueue) return { ...out, ...env };
|
|
545
|
+
const requestId = args && typeof args.requestId === "string" ? args.requestId : void 0;
|
|
546
|
+
return { ...out, ...env, queue: visibleQueueFor(await reader.readQueuePruned(), pluginId, showOthers, requestId) };
|
|
241
547
|
}
|
|
242
548
|
async function readCheck(args) {
|
|
243
549
|
const reader = await getSharedReader(pluginId, config, {
|
|
@@ -246,21 +552,85 @@ function createHostUpdate(deps = {}, configInput) {
|
|
|
246
552
|
});
|
|
247
553
|
const result = await reader.check();
|
|
248
554
|
const withManual = await snapWithManual(reader, result.snapshot, config);
|
|
249
|
-
|
|
555
|
+
const env = wantsEnv(args) ? { env: await readEnvForPanel(reader) } : {};
|
|
556
|
+
const { includeQueue, showOthers } = queueArgsOf(args);
|
|
557
|
+
if (!includeQueue) return { snapshot: withManual.snapshot, manual: withManual.manual, receipt: result.receipt ?? null, ...env };
|
|
558
|
+
const requestId = args && typeof args.requestId === "string" ? args.requestId : void 0;
|
|
559
|
+
return {
|
|
560
|
+
snapshot: withManual.snapshot,
|
|
561
|
+
manual: withManual.manual,
|
|
562
|
+
receipt: result.receipt ?? null,
|
|
563
|
+
...env,
|
|
564
|
+
queue: visibleQueueFor(await reader.readQueuePruned(), pluginId, showOthers, requestId)
|
|
565
|
+
};
|
|
250
566
|
}
|
|
251
567
|
async function runInstall(args) {
|
|
252
568
|
const checkId = args && typeof args.checkId === "string" ? args.checkId : "";
|
|
253
569
|
const requestId = args && typeof args.requestId === "string" ? args.requestId : "";
|
|
570
|
+
const { includeQueue, showOthers } = queueArgsOf(args);
|
|
571
|
+
const enqueueOnly = !!args && args["enqueueOnly"] === true;
|
|
572
|
+
const cancelQueued = !!args && args["cancelQueued"] === true;
|
|
254
573
|
const reader = await getSharedReader(pluginId, config, {
|
|
255
574
|
...readerOverrides,
|
|
256
575
|
profileDir: args && args.profileDir ? String(args.profileDir) : readerOverrides.profileDir
|
|
257
576
|
});
|
|
258
|
-
|
|
577
|
+
const envPatch = wantsEnv(args) ? { env: await readEnvForPanel(reader) } : {};
|
|
578
|
+
if (cancelQueued) {
|
|
579
|
+
if (!validRequestId(requestId)) throw checkExpiredError();
|
|
580
|
+
const current = await reader.readQueuePruned();
|
|
581
|
+
const next = cancelEnqueuedInQueue(current, pluginId, requestId);
|
|
582
|
+
if (next.removed) await reader.writeQueueState(next.state);
|
|
583
|
+
const out = await snapWithManual(reader, await reader.status(), config);
|
|
584
|
+
return { ...out, ...envPatch, queue: visibleQueueFor(next.state, pluginId, showOthers, requestId) };
|
|
585
|
+
}
|
|
586
|
+
if (enqueueOnly) {
|
|
587
|
+
if (!validRequestId(requestId)) throw checkExpiredError();
|
|
588
|
+
const current = await reader.readQueuePruned();
|
|
589
|
+
const placed2 = enqueueInQueue(current, { pluginId, requestId, targetVersion: null, enqueuedAt: reader.queueNow() });
|
|
590
|
+
if (placed2.state !== current) await reader.writeQueueState(placed2.state);
|
|
591
|
+
const out = await snapWithManual(reader, await reader.status(), config);
|
|
592
|
+
return { ...out, ...envPatch, queue: visibleQueueFor(placed2.state, pluginId, showOthers, requestId) };
|
|
593
|
+
}
|
|
594
|
+
if (!checkId || !validRequestId(requestId)) {
|
|
595
|
+
const out = await snapWithManual(reader, await reader.install({ checkId, requestId }), config);
|
|
596
|
+
if (!includeQueue) return { ...out, ...envPatch };
|
|
597
|
+
return { ...out, ...envPatch, queue: visibleQueueFor(await reader.readQueuePruned(), pluginId, showOthers, requestId) };
|
|
598
|
+
}
|
|
599
|
+
const before = await reader.readQueuePruned();
|
|
600
|
+
const placed = enqueueInQueue(before, { pluginId, requestId, targetVersion: null, enqueuedAt: reader.queueNow() });
|
|
601
|
+
if (placed.state !== before) await reader.writeQueueState(placed.state);
|
|
602
|
+
if (queuePositionOf(placed.state, pluginId, requestId) !== 0 && !isHeadOfQueue(placed.state, pluginId, requestId)) {
|
|
603
|
+
throw updateBusyError();
|
|
604
|
+
}
|
|
605
|
+
try {
|
|
606
|
+
const out = await snapWithManual(reader, await reader.install({ checkId, requestId }), config);
|
|
607
|
+
if (!includeQueue) return { ...out, ...envPatch };
|
|
608
|
+
return { ...out, ...envPatch, queue: visibleQueueFor(await reader.readQueuePruned(), pluginId, showOthers, requestId) };
|
|
609
|
+
} catch (error) {
|
|
610
|
+
if (error?.code !== "update-busy") {
|
|
611
|
+
try {
|
|
612
|
+
const current = await reader.readQueuePruned();
|
|
613
|
+
const next = cancelEnqueuedInQueue(current, pluginId, requestId);
|
|
614
|
+
if (next.removed) await reader.writeQueueState(next.state);
|
|
615
|
+
} catch {
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
throw error;
|
|
619
|
+
}
|
|
259
620
|
}
|
|
260
621
|
const handlers = {
|
|
261
|
-
[phoneNames.updateStatus]: loggedPhone(phoneNames.updateStatus, "update-status", pluginId, readStatus
|
|
262
|
-
|
|
263
|
-
|
|
622
|
+
[phoneNames.updateStatus]: loggedPhone(phoneNames.updateStatus, "update-status", pluginId, readStatus, {
|
|
623
|
+
config,
|
|
624
|
+
readerOverrides
|
|
625
|
+
}),
|
|
626
|
+
[phoneNames.updateCheck]: loggedPhone(phoneNames.updateCheck, "update-check", pluginId, readCheck, {
|
|
627
|
+
config,
|
|
628
|
+
readerOverrides
|
|
629
|
+
}),
|
|
630
|
+
[phoneNames.updateInstall]: loggedPhone(phoneNames.updateInstall, "update-install", pluginId, runInstall, {
|
|
631
|
+
config,
|
|
632
|
+
readerOverrides
|
|
633
|
+
})
|
|
264
634
|
};
|
|
265
635
|
return { phoneNames, handlers };
|
|
266
636
|
}
|
|
@@ -273,21 +643,105 @@ function __resetSharedUpdateReaderForTests() {
|
|
|
273
643
|
sharedDesktopPnpm = null;
|
|
274
644
|
}
|
|
275
645
|
export {
|
|
646
|
+
CHANGELOG_ALL_CATEGORIES,
|
|
647
|
+
CHANGELOG_DEFAULT_REGISTRY,
|
|
648
|
+
CHANGELOG_FETCH_MAX_BYTES,
|
|
649
|
+
CHANGELOG_FILENAME,
|
|
650
|
+
CHANGELOG_FOLDED,
|
|
651
|
+
CHANGELOG_MAX_BULLETS_PER_SECTION,
|
|
652
|
+
CHANGELOG_MAX_BULLET_CHARS,
|
|
653
|
+
CHANGELOG_MAX_CHARS,
|
|
654
|
+
CHANGELOG_MAX_ENTRIES,
|
|
655
|
+
CHANGELOG_MUST_SHOW,
|
|
656
|
+
CHANGELOG_NEUTRAL_HINT,
|
|
657
|
+
CHANGELOG_NEUTRAL_LINE,
|
|
658
|
+
CHANGELOG_TARBALL_MAX_BYTES,
|
|
659
|
+
CHANGELOG_TAR_MAX_BYTES,
|
|
660
|
+
COPY_BUDGET_CHARS,
|
|
661
|
+
DETAIL_MAX_CHARS,
|
|
662
|
+
DIAG_ACTIONS,
|
|
663
|
+
DIAG_DROP_ORDER,
|
|
664
|
+
DIAG_INLINE_BUDGET_BYTES,
|
|
665
|
+
DIAG_KEYS,
|
|
666
|
+
DIAG_KNOWN_TYPES,
|
|
667
|
+
DIAG_NEVER_DROP_KEYS,
|
|
668
|
+
DIAG_STAGES,
|
|
669
|
+
DIAG_STAGE_EXPECT,
|
|
670
|
+
DIAG_VERSION,
|
|
671
|
+
ENDORSED_REGISTRY_HOSTS,
|
|
672
|
+
KNOWN_GAP_FILE_URL_PREFIX,
|
|
673
|
+
MAX_SKIPPED_ENTRIES,
|
|
674
|
+
QUEUE_DIR_SEGMENT,
|
|
675
|
+
QUEUE_FILE,
|
|
676
|
+
QUEUE_INTENT_TTL_MS2 as QUEUE_INTENT_TTL_MS,
|
|
677
|
+
QUEUE_LOCK_FILE,
|
|
678
|
+
QUEUE_LOCK_STALE_MS,
|
|
679
|
+
REDACTED_PATH,
|
|
680
|
+
REDACTED_SECRET,
|
|
681
|
+
REDACTION_RULE_NAMES,
|
|
682
|
+
SKIPPED_FILE,
|
|
276
683
|
__resetSharedUpdateReaderForTests,
|
|
684
|
+
addSkipped,
|
|
685
|
+
buildDiag2 as buildDiag,
|
|
277
686
|
buildPhoneName,
|
|
278
687
|
buildPhoneNames2 as buildPhoneNames,
|
|
688
|
+
cancelEnqueuedInQueue2 as cancelEnqueuedInQueue,
|
|
689
|
+
changelogForUpdate,
|
|
279
690
|
checkEventCounts,
|
|
280
691
|
checkEventFields,
|
|
281
|
-
|
|
692
|
+
clearSkipped,
|
|
693
|
+
compareReleaseVersions,
|
|
694
|
+
compareVersions,
|
|
695
|
+
containingPackage,
|
|
282
696
|
createHostUpdate,
|
|
697
|
+
createSkipDiskPorts,
|
|
283
698
|
createUpdateDiskPorts2 as createUpdateDiskPorts,
|
|
284
699
|
createUpdateExecutor2 as createUpdateExecutor,
|
|
700
|
+
createUpdateQueuePorts2 as createUpdateQueuePorts,
|
|
285
701
|
defaultHomeDir2 as defaultHomeDir,
|
|
702
|
+
deriveAction,
|
|
703
|
+
deriveRouteMethod,
|
|
704
|
+
deriveStage,
|
|
286
705
|
detectEnvironmentKind,
|
|
706
|
+
diagByteLength,
|
|
707
|
+
emptyQueueState2 as emptyQueueState,
|
|
708
|
+
enforceDiagBudget,
|
|
709
|
+
enforceBudget as enforceDiagBudgetForPhone,
|
|
710
|
+
enqueueInQueue2 as enqueueInQueue,
|
|
711
|
+
extractChangelogFromTar,
|
|
712
|
+
fetchReleaseChangelogText,
|
|
713
|
+
hasVisibleSections,
|
|
714
|
+
isHeadOfQueue2 as isHeadOfQueue,
|
|
715
|
+
isPrereleaseVersion,
|
|
716
|
+
isUnreleasedVersion,
|
|
717
|
+
isVersionAllowedInChannel2 as isVersionAllowedInChannel,
|
|
718
|
+
isVersionSkipped,
|
|
719
|
+
normalizeQueueState2 as normalizeQueueState,
|
|
720
|
+
normalizeSkipped,
|
|
721
|
+
parseChangelog,
|
|
287
722
|
parseEventListManifest,
|
|
288
723
|
pathsForUpdate,
|
|
289
724
|
profileNameValid,
|
|
725
|
+
pruneExpiredIntents2 as pruneExpiredIntents,
|
|
726
|
+
queuePathsForUpdate,
|
|
727
|
+
queuePositionOf2 as queuePositionOf,
|
|
728
|
+
readInstalledChangelogText,
|
|
290
729
|
registrySpec,
|
|
730
|
+
releaseOwnerInQueue2 as releaseOwnerInQueue,
|
|
731
|
+
renderChangelogHTML,
|
|
732
|
+
renderChangelogNeutral,
|
|
733
|
+
renderChangelogSection,
|
|
291
734
|
resolveCliEntry,
|
|
292
|
-
|
|
735
|
+
resolveRegistryHost,
|
|
736
|
+
resolveTargetPackage2 as resolveTargetPackage,
|
|
737
|
+
resolveUpdateConfig2 as resolveUpdateConfig,
|
|
738
|
+
sanitizeDetail,
|
|
739
|
+
sanitizeForCopy,
|
|
740
|
+
selectChangelogEntries,
|
|
741
|
+
setOwnerIfFree2 as setOwnerIfFree,
|
|
742
|
+
skipKey,
|
|
743
|
+
truncateToWordBoundary,
|
|
744
|
+
validReleaseVersion,
|
|
745
|
+
validVersion,
|
|
746
|
+
visibleQueueFor2 as visibleQueueFor
|
|
293
747
|
};
|