dsh-plugin-shop 0.8.4-beta.0 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/client.js +464 -337
- package/lib/index.js +918 -94
- package/lib/typert.host.js +10 -10
- package/lib/typert.remote-client.js +10 -10
- package/lib/types/client/locales.d.ts +2 -0
- package/lib/types/client/present.d.ts +1 -0
- package/lib/types/client/restart-monitor.d.ts +62 -6
- package/lib/types/host/executor.d.ts +50 -3
- package/lib/types/host/index.d.ts +82 -21
- package/lib/types/host/manager-runner.d.ts +51 -0
- package/lib/types/host/plugin-manager.d.ts +100 -0
- package/package.json +1 -1
package/lib/typert.host.js
CHANGED
|
@@ -195,7 +195,7 @@ export const TYPERT = {
|
|
|
195
195
|
schema: dsh_plugin_shop_shop_catalog_result$schema,
|
|
196
196
|
create: () => dsh_plugin_shop_shop_catalog_result$schema,
|
|
197
197
|
},
|
|
198
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
198
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1253,"column":9},
|
|
199
199
|
},
|
|
200
200
|
{
|
|
201
201
|
id: 'dsh-plugin-shop#shop/installed',
|
|
@@ -211,7 +211,7 @@ export const TYPERT = {
|
|
|
211
211
|
schema: dsh_plugin_shop_shop_installed_result$schema,
|
|
212
212
|
create: () => dsh_plugin_shop_shop_installed_result$schema,
|
|
213
213
|
},
|
|
214
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
214
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1720,"column":9},
|
|
215
215
|
},
|
|
216
216
|
{
|
|
217
217
|
id: 'dsh-plugin-shop#shop/installedSpecs',
|
|
@@ -227,7 +227,7 @@ export const TYPERT = {
|
|
|
227
227
|
schema: dsh_plugin_shop_shop_installedSpecs_result$schema,
|
|
228
228
|
create: () => dsh_plugin_shop_shop_installedSpecs_result$schema,
|
|
229
229
|
},
|
|
230
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
230
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1711,"column":9},
|
|
231
231
|
},
|
|
232
232
|
{
|
|
233
233
|
id: 'dsh-plugin-shop#shop/installStart',
|
|
@@ -255,7 +255,7 @@ export const TYPERT = {
|
|
|
255
255
|
schema: dsh_plugin_shop_shop_installStart_result$schema,
|
|
256
256
|
create: () => dsh_plugin_shop_shop_installStart_result$schema,
|
|
257
257
|
},
|
|
258
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
258
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1379,"column":9},
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
id: 'dsh-plugin-shop#shop/installStatus',
|
|
@@ -282,7 +282,7 @@ export const TYPERT = {
|
|
|
282
282
|
schema: dsh_plugin_shop_shop_installStatus_result$schema,
|
|
283
283
|
create: () => dsh_plugin_shop_shop_installStatus_result$schema,
|
|
284
284
|
},
|
|
285
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
285
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1687,"column":3},
|
|
286
286
|
},
|
|
287
287
|
{
|
|
288
288
|
id: 'dsh-plugin-shop#shop/restart',
|
|
@@ -298,7 +298,7 @@ export const TYPERT = {
|
|
|
298
298
|
schema: dsh_plugin_shop_shop_restart_result$schema,
|
|
299
299
|
create: () => dsh_plugin_shop_shop_restart_result$schema,
|
|
300
300
|
},
|
|
301
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
301
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1916,"column":9},
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
id: 'dsh-plugin-shop#shop/setEnabled',
|
|
@@ -325,7 +325,7 @@ export const TYPERT = {
|
|
|
325
325
|
schema: dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
326
326
|
create: () => dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
327
327
|
},
|
|
328
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
328
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":924,"column":9},
|
|
329
329
|
},
|
|
330
330
|
{
|
|
331
331
|
id: 'dsh-plugin-shop#shop/uninstallStart',
|
|
@@ -353,7 +353,7 @@ export const TYPERT = {
|
|
|
353
353
|
schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
|
|
354
354
|
create: () => dsh_plugin_shop_shop_uninstallStart_result$schema,
|
|
355
355
|
},
|
|
356
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
356
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1827,"column":9},
|
|
357
357
|
},
|
|
358
358
|
{
|
|
359
359
|
id: 'dsh-plugin-shop#shop/updateStart',
|
|
@@ -380,7 +380,7 @@ export const TYPERT = {
|
|
|
380
380
|
schema: dsh_plugin_shop_shop_updateStart_result$schema,
|
|
381
381
|
create: () => dsh_plugin_shop_shop_updateStart_result$schema,
|
|
382
382
|
},
|
|
383
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
383
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2020,"column":9},
|
|
384
384
|
},
|
|
385
385
|
{
|
|
386
386
|
id: 'dsh-plugin-shop#shop/version',
|
|
@@ -396,7 +396,7 @@ export const TYPERT = {
|
|
|
396
396
|
schema: dsh_plugin_shop_shop_version_result$schema,
|
|
397
397
|
create: () => dsh_plugin_shop_shop_version_result$schema,
|
|
398
398
|
},
|
|
399
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
399
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1978,"column":9},
|
|
400
400
|
},
|
|
401
401
|
],
|
|
402
402
|
model: {
|
|
@@ -192,7 +192,7 @@ export const TYPERT_REMOTE = {
|
|
|
192
192
|
schema: dsh_plugin_shop_shop_catalog_result$schema,
|
|
193
193
|
create: () => dsh_plugin_shop_shop_catalog_result$schema,
|
|
194
194
|
},
|
|
195
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
195
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1253,"column":9},
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
id: 'dsh-plugin-shop#shop/installed',
|
|
@@ -208,7 +208,7 @@ export const TYPERT_REMOTE = {
|
|
|
208
208
|
schema: dsh_plugin_shop_shop_installed_result$schema,
|
|
209
209
|
create: () => dsh_plugin_shop_shop_installed_result$schema,
|
|
210
210
|
},
|
|
211
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
211
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1720,"column":9},
|
|
212
212
|
},
|
|
213
213
|
{
|
|
214
214
|
id: 'dsh-plugin-shop#shop/installedSpecs',
|
|
@@ -224,7 +224,7 @@ export const TYPERT_REMOTE = {
|
|
|
224
224
|
schema: dsh_plugin_shop_shop_installedSpecs_result$schema,
|
|
225
225
|
create: () => dsh_plugin_shop_shop_installedSpecs_result$schema,
|
|
226
226
|
},
|
|
227
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
227
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1711,"column":9},
|
|
228
228
|
},
|
|
229
229
|
{
|
|
230
230
|
id: 'dsh-plugin-shop#shop/installStart',
|
|
@@ -252,7 +252,7 @@ export const TYPERT_REMOTE = {
|
|
|
252
252
|
schema: dsh_plugin_shop_shop_installStart_result$schema,
|
|
253
253
|
create: () => dsh_plugin_shop_shop_installStart_result$schema,
|
|
254
254
|
},
|
|
255
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
255
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1379,"column":9},
|
|
256
256
|
},
|
|
257
257
|
{
|
|
258
258
|
id: 'dsh-plugin-shop#shop/installStatus',
|
|
@@ -279,7 +279,7 @@ export const TYPERT_REMOTE = {
|
|
|
279
279
|
schema: dsh_plugin_shop_shop_installStatus_result$schema,
|
|
280
280
|
create: () => dsh_plugin_shop_shop_installStatus_result$schema,
|
|
281
281
|
},
|
|
282
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
282
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1687,"column":3},
|
|
283
283
|
},
|
|
284
284
|
{
|
|
285
285
|
id: 'dsh-plugin-shop#shop/restart',
|
|
@@ -295,7 +295,7 @@ export const TYPERT_REMOTE = {
|
|
|
295
295
|
schema: dsh_plugin_shop_shop_restart_result$schema,
|
|
296
296
|
create: () => dsh_plugin_shop_shop_restart_result$schema,
|
|
297
297
|
},
|
|
298
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
298
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1916,"column":9},
|
|
299
299
|
},
|
|
300
300
|
{
|
|
301
301
|
id: 'dsh-plugin-shop#shop/setEnabled',
|
|
@@ -322,7 +322,7 @@ export const TYPERT_REMOTE = {
|
|
|
322
322
|
schema: dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
323
323
|
create: () => dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
324
324
|
},
|
|
325
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
325
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":924,"column":9},
|
|
326
326
|
},
|
|
327
327
|
{
|
|
328
328
|
id: 'dsh-plugin-shop#shop/uninstallStart',
|
|
@@ -350,7 +350,7 @@ export const TYPERT_REMOTE = {
|
|
|
350
350
|
schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
|
|
351
351
|
create: () => dsh_plugin_shop_shop_uninstallStart_result$schema,
|
|
352
352
|
},
|
|
353
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
353
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1827,"column":9},
|
|
354
354
|
},
|
|
355
355
|
{
|
|
356
356
|
id: 'dsh-plugin-shop#shop/updateStart',
|
|
@@ -377,7 +377,7 @@ export const TYPERT_REMOTE = {
|
|
|
377
377
|
schema: dsh_plugin_shop_shop_updateStart_result$schema,
|
|
378
378
|
create: () => dsh_plugin_shop_shop_updateStart_result$schema,
|
|
379
379
|
},
|
|
380
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
380
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2020,"column":9},
|
|
381
381
|
},
|
|
382
382
|
{
|
|
383
383
|
id: 'dsh-plugin-shop#shop/version',
|
|
@@ -393,7 +393,7 @@ export const TYPERT_REMOTE = {
|
|
|
393
393
|
schema: dsh_plugin_shop_shop_version_result$schema,
|
|
394
394
|
create: () => dsh_plugin_shop_shop_version_result$schema,
|
|
395
395
|
},
|
|
396
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
396
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1978,"column":9},
|
|
397
397
|
},
|
|
398
398
|
],
|
|
399
399
|
}
|
|
@@ -146,6 +146,7 @@ export declare const zh: {
|
|
|
146
146
|
enabledSwitch: string;
|
|
147
147
|
toggleFailed: string;
|
|
148
148
|
hotApplyNote: string;
|
|
149
|
+
toggleRestartNote: string;
|
|
149
150
|
};
|
|
150
151
|
/** Shop locale key union. */
|
|
151
152
|
export type ShopLocaleKey = keyof typeof zh;
|
|
@@ -264,4 +265,5 @@ export declare const en: {
|
|
|
264
265
|
enabledSwitch: string;
|
|
265
266
|
toggleFailed: string;
|
|
266
267
|
hotApplyNote: string;
|
|
268
|
+
toggleRestartNote: string;
|
|
267
269
|
};
|
|
@@ -17,17 +17,45 @@
|
|
|
17
17
|
* swapped-in module instance shares with the one it replaced — and the probe
|
|
18
18
|
* loop is plain timers owned by no fiber. Any tab reads the state, so the
|
|
19
19
|
* replacement renders the restart under way instead of offering another.
|
|
20
|
+
*
|
|
21
|
+
* The REQUEST is the page's too, since later the same day. On dsh
|
|
22
|
+
* 0.1.5-rc.3 and 0.1.7-rc.2 alike a unary Remote call is an HTTP POST whose
|
|
23
|
+
* fetch rides the calling mount's abort signal, and an answer that arrives after the mount went inactive is
|
|
24
|
+
* rewritten to "no longer mounted" (dsh-api-gateway's client). A swap landing
|
|
25
|
+
* inside the restart's round trip therefore left the tab that pressed with no
|
|
26
|
+
* answer, whether or not the host had committed: measured with the request
|
|
27
|
+
* held, the host never restarted; with the response held, it did, and the page
|
|
28
|
+
* stayed on the old process showing the old version. So every module instance
|
|
29
|
+
* registers its own path to the host here (the client half's apply), a confirm
|
|
30
|
+
* records the request before anything is awaited, and a request whose path is
|
|
31
|
+
* withdrawn mid-call is asked again through a live one. The host answers a
|
|
32
|
+
* repeat with the restart it already committed.
|
|
20
33
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
34
|
+
import type { ShopRestartResult } from '../host/index.ts';
|
|
35
|
+
/** What this page is doing about a restart: waiting for the host to answer
|
|
36
|
+
* the confirm, waiting for the new server once it committed, or given up on
|
|
37
|
+
* that server. `logFile` is where the host said the new process writes; a
|
|
38
|
+
* host older than that field sends none. */
|
|
24
39
|
export type RestartMonitorState = {
|
|
40
|
+
kind: 'requesting';
|
|
41
|
+
} | {
|
|
25
42
|
kind: 'restarting';
|
|
26
43
|
logFile?: string;
|
|
27
44
|
} | {
|
|
28
45
|
kind: 'failed';
|
|
29
46
|
logFile?: string;
|
|
30
47
|
};
|
|
48
|
+
/** How one press ended, for the panel that made it: the page follows the
|
|
49
|
+
* restart from here, the host refused it, or it never reached a host that
|
|
50
|
+
* could answer. */
|
|
51
|
+
export type RestartRequestOutcome = {
|
|
52
|
+
kind: 'started';
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'refused';
|
|
55
|
+
detail: string;
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'unreachable';
|
|
58
|
+
};
|
|
31
59
|
/** The page's restart, or null when it has committed none. The same object
|
|
32
60
|
* until the state changes, as `useSyncExternalStore` requires. */
|
|
33
61
|
export declare function readRestartMonitor(): RestartMonitorState | null;
|
|
@@ -52,7 +80,35 @@ export declare function startRestartMonitor(options: {
|
|
|
52
80
|
reload: () => void;
|
|
53
81
|
logFile?: string;
|
|
54
82
|
}): void;
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
83
|
+
/**
|
|
84
|
+
* Register one module instance's path to the host; the client half's apply
|
|
85
|
+
* does, with the `restart` it hands the tab. The returned function withdraws
|
|
86
|
+
* it, and has to run BEFORE the mount it rides is disposed: a request still in
|
|
87
|
+
* flight on it is then asked again through the newest live path — at once if
|
|
88
|
+
* one is registered, or as soon as one is — rather than waiting on a call the
|
|
89
|
+
* dispose is about to abort.
|
|
90
|
+
*/
|
|
91
|
+
export declare function registerRestartCarrier(restart: () => Promise<ShopRestartResult>): () => void;
|
|
92
|
+
/**
|
|
93
|
+
* Ask the host to restart, for the page (design §8). The request is the
|
|
94
|
+
* page's from the confirm on, not from the answer: every offer renders it as
|
|
95
|
+
* under way, and a second press joins it rather than asking twice. It rides
|
|
96
|
+
* the newest path a module instance registered, or — where no client half
|
|
97
|
+
* registered one — the pressing tab's own `restart`.
|
|
98
|
+
*
|
|
99
|
+
* Resolves, never rejects, with what the press should show. A commit starts
|
|
100
|
+
* the monitor and is `started`. A refusal and an unreachable host leave
|
|
101
|
+
* nothing under way. A path withdrawn mid-call decides nothing but a commit;
|
|
102
|
+
* the ask on the path that replaced it decides the rest, and that ask
|
|
103
|
+
* finding no host is followed as a restart, since the first ask may have
|
|
104
|
+
* committed and taken its host down with it.
|
|
105
|
+
*/
|
|
106
|
+
export declare function requestRestart(options: {
|
|
107
|
+
reload: () => void;
|
|
108
|
+
restart: () => Promise<ShopRestartResult>;
|
|
109
|
+
}): Promise<RestartRequestOutcome>;
|
|
110
|
+
/** Stop the probe loop and forget the page's restart, its request and every
|
|
111
|
+
* registered path. Nothing in the page calls this — a committed restart ends
|
|
112
|
+
* in a reload or a failure — so its caller is a test isolating one case from
|
|
113
|
+
* the next. */
|
|
58
114
|
export declare function resetRestartMonitor(): void;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* post-exit manifest confirmation. */
|
|
5
5
|
import type { HotRestartReason } from './hot.ts';
|
|
6
6
|
import type { Activation } from './activation.ts';
|
|
7
|
-
import type { Prefetcher } from './prefetch.ts';
|
|
7
|
+
import type { Prefetcher, PrefetchRequest } from './prefetch.ts';
|
|
8
8
|
import { type InstallState } from '../shared/install-state.ts';
|
|
9
9
|
export type { InstallState } from '../shared/install-state.ts';
|
|
10
10
|
export interface InstallStatus {
|
|
@@ -17,11 +17,28 @@ export interface InstallStatus {
|
|
|
17
17
|
restartReason?: HotRestartReason;
|
|
18
18
|
detail?: string;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
/** Bound one dsh command so a stalled install cannot hold the profile queue
|
|
21
|
+
* forever. Tests can pass a shorter value; production stays generous. */
|
|
22
|
+
export declare const INSTALL_TIMEOUT_MS: number;
|
|
23
|
+
export interface RunningInstall {
|
|
21
24
|
installId: string;
|
|
22
25
|
status: () => InstallStatus;
|
|
23
26
|
finished: Promise<InstallStatus>;
|
|
24
27
|
}
|
|
28
|
+
/** Run `task` in `profile`'s queue, after every command already in it: the
|
|
29
|
+
* queue `spawnPluginCli` uses, shared with the plugin manager's runner so the
|
|
30
|
+
* two paths are never concurrent in one profile. `ahead` is how many commands
|
|
31
|
+
* were queued or running when the slot was taken. */
|
|
32
|
+
export declare function inProfileQueue<T>(profile: string, task: () => Promise<T>): {
|
|
33
|
+
ahead: number;
|
|
34
|
+
finished: Promise<T>;
|
|
35
|
+
};
|
|
36
|
+
/** An install record's log: the newest lines within MAX_LOG_LINES and
|
|
37
|
+
* MAX_LOG_BYTES, never dropping the newest one. */
|
|
38
|
+
export declare function createBoundedLog(): {
|
|
39
|
+
push(line: string): void;
|
|
40
|
+
lines(): string[];
|
|
41
|
+
};
|
|
25
42
|
/**
|
|
26
43
|
* Why a zero-exit install left `dsh.profile.bundles` without the entry.
|
|
27
44
|
*
|
|
@@ -71,6 +88,11 @@ export declare function activationFailureDetail(args: {
|
|
|
71
88
|
before: Readonly<Record<string, string>> | null;
|
|
72
89
|
after: Readonly<Record<string, string>>;
|
|
73
90
|
}): string;
|
|
91
|
+
/** The line dsh 0.1.7 opens a refused install with (dsh-plugin-manager's
|
|
92
|
+
* `rejected`), and the exemption command its CLI prints after it, one per
|
|
93
|
+
* refused package (`runPlugin`). The opener is exported for the plugin
|
|
94
|
+
* manager's answer, whose output carries the same block. */
|
|
95
|
+
export declare const REFUSAL_OPENER = "dsh: installation rejected: ";
|
|
74
96
|
/**
|
|
75
97
|
* The one log line worth putting in front of the user, plus the recovery hint.
|
|
76
98
|
*
|
|
@@ -85,7 +107,7 @@ export declare function activationFailureDetail(args: {
|
|
|
85
107
|
* Scanning from the end: a pnpm error code first, then any thrown error, then
|
|
86
108
|
* the last line that is not noise.
|
|
87
109
|
*/
|
|
88
|
-
export declare function installFailureDetail(profile: string, log: readonly string[]): string;
|
|
110
|
+
export declare function installFailureDetail(profile: string, log: readonly string[], hint?: string): string;
|
|
89
111
|
/**
|
|
90
112
|
* Why a spawn of the dsh CLI never started.
|
|
91
113
|
*
|
|
@@ -121,6 +143,19 @@ export interface LineSink {
|
|
|
121
143
|
flush: () => void;
|
|
122
144
|
}
|
|
123
145
|
export declare function lineSink(emit: (line: string) => void): LineSink;
|
|
146
|
+
/**
|
|
147
|
+
* The operand gate, one function for every caller: it refuses, by throwing,
|
|
148
|
+
* an operand the dsh CLI would parse as a flag, and one carrying the shell
|
|
149
|
+
* punctuation `UNSAFE_TARGET` names. A legitimate operand (a catalog name for
|
|
150
|
+
* a removal; a `name@version`, `github:` or tarball spec for an install)
|
|
151
|
+
* never begins with `-`, so the first refusal cannot reject a real install or
|
|
152
|
+
* uninstall, and failing loudly beats letting the CLI reinterpret an operand
|
|
153
|
+
* as an option. `spawnPluginCli` runs it before it spawns anything or takes a
|
|
154
|
+
* queue slot; the gateway's plugin manager path runs it before a spec reaches
|
|
155
|
+
* `installBundle` or the download phase, whose pump relies on it (see
|
|
156
|
+
* `requestDownloadPhase`). Returns the operand, known to be present.
|
|
157
|
+
*/
|
|
158
|
+
export declare function gateOperand(target: string | undefined): string;
|
|
124
159
|
/**
|
|
125
160
|
* The operand as the downstream dsh must receive it for pnpm to see it whole.
|
|
126
161
|
*
|
|
@@ -156,6 +191,18 @@ export declare function lineSink(emit: (line: string) => void): LineSink;
|
|
|
156
191
|
* deepseek-ai/deepseek-harness discussion #5815.
|
|
157
192
|
*/
|
|
158
193
|
export declare function shellSafeTarget(target: string, platform: NodeJS.Platform): string;
|
|
194
|
+
/**
|
|
195
|
+
* Ask the pump to warm `spec` while an operation waits its turn, and say in
|
|
196
|
+
* that operation's log why there is no download phase when there is none.
|
|
197
|
+
* Shared by the CLI executor and the plugin manager runner.
|
|
198
|
+
*/
|
|
199
|
+
export declare function requestDownloadPhase(options: {
|
|
200
|
+
prefetcher: Prefetcher;
|
|
201
|
+
profile: string;
|
|
202
|
+
spec: string;
|
|
203
|
+
env?: NodeJS.ProcessEnv;
|
|
204
|
+
log: (line: string) => void;
|
|
205
|
+
}): PrefetchRequest | null;
|
|
159
206
|
/**
|
|
160
207
|
* Run one `dsh plugin --profile <profile> add <spec>` and track it.
|
|
161
208
|
* When `expectedName` is given, a zero exit is confirmed against the profile
|
|
@@ -39,21 +39,6 @@ export interface LoaderEntryLike {
|
|
|
39
39
|
disabled: boolean | null;
|
|
40
40
|
}, create?: boolean, force?: boolean): Promise<void>;
|
|
41
41
|
}
|
|
42
|
-
/** The slice of dsh 0.1.7's `pluginManager` service this gateway calls,
|
|
43
|
-
* structurally: the build compiles against the 0.1.1-rc.2 harness floor,
|
|
44
|
-
* where the package does not exist. `setBundleEnabled` is what dsh's own
|
|
45
|
-
* Plugins page calls for its bundle switch, and it answers with the saved
|
|
46
|
-
* change and how it applied (design 2026-09-26-plugin-manager-delegation,
|
|
47
|
-
* section 2). */
|
|
48
|
-
export interface BundleSelector {
|
|
49
|
-
setBundleEnabled(name: string, enabled: boolean): Promise<{
|
|
50
|
-
application?: unknown;
|
|
51
|
-
error?: {
|
|
52
|
-
code?: unknown;
|
|
53
|
-
diagnostic?: unknown;
|
|
54
|
-
};
|
|
55
|
-
}>;
|
|
56
|
-
}
|
|
57
42
|
/** Test-only injection points; production callers pass nothing. */
|
|
58
43
|
export interface ShopGatewayOptions {
|
|
59
44
|
catalogUrl?: string;
|
|
@@ -362,6 +347,11 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
362
347
|
private readonly exit;
|
|
363
348
|
private readonly restartExitDelayMs;
|
|
364
349
|
private readonly restartParentPid;
|
|
350
|
+
/** The restart this process committed, once it has: every later
|
|
351
|
+
* `shop/restart` answers with it. A page that lost the first answer to an
|
|
352
|
+
* HMR swap asks again (client/restart-monitor.ts), and inside the exit
|
|
353
|
+
* delay that ask reaches this same process. */
|
|
354
|
+
private committedRestart;
|
|
365
355
|
private readonly latestVersion;
|
|
366
356
|
private readonly pinFs;
|
|
367
357
|
private readonly allowRestart?;
|
|
@@ -380,6 +370,9 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
380
370
|
private readonly prefetcher;
|
|
381
371
|
/** What this process may already have imported (see `importedThisProcess`). */
|
|
382
372
|
private readonly imported;
|
|
373
|
+
/** Routes the output dsh's `pluginManager` streams to the record whose
|
|
374
|
+
* request id it carries (see the constructor). */
|
|
375
|
+
private readonly managerLogs;
|
|
383
376
|
/** The install gate runs against the last loaded snapshot, never a fresh
|
|
384
377
|
* fetch per request (§7.2: the Host's cached snapshot is the truth). */
|
|
385
378
|
/** Finished install records retained, so a poll sees the true terminal
|
|
@@ -404,7 +397,8 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
404
397
|
* promise, so concurrent first calls share one read; `readRunningHarness`
|
|
405
398
|
* never rejects, so there is no failure to retry. */
|
|
406
399
|
private harnessRead;
|
|
407
|
-
/** Install records, running and finished
|
|
400
|
+
/** Install records, running and finished, from the CLI and from dsh's
|
|
401
|
+
* `pluginManager` alike; a poll finds one here or reports not found. */
|
|
408
402
|
private readonly installs;
|
|
409
403
|
/** Every install id in insertion order, oldest first; finished-record eviction walks this from the front. */
|
|
410
404
|
private readonly installOrder;
|
|
@@ -443,11 +437,13 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
443
437
|
* walk of the profile's disk can see (design
|
|
444
438
|
* 2026-09-01-harness-compatibility §11). */
|
|
445
439
|
private harnessPackages;
|
|
446
|
-
/** dsh's `pluginManager` service, when the running harness provides
|
|
447
|
-
* (0.1.7 and later), else null.
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
440
|
+
/** dsh's `pluginManager` service, when the running harness provides all of
|
|
441
|
+
* it (0.1.7 and later), else null. Never cached across calls, like
|
|
442
|
+
* `pluginPackages`, but read once per RPC, at its start, and passed down:
|
|
443
|
+
* read again after an await, a service disposed in between would let a
|
|
444
|
+
* desktop mutation past the desktop gate and onto the CLI path, which dsh
|
|
445
|
+
* refuses for that profile. Design 2026-09-26-plugin-manager-delegation,
|
|
446
|
+
* section 3.1. */
|
|
451
447
|
private pluginManager;
|
|
452
448
|
/** "Does this installation provide `spec`?", asked from `anchor`: the
|
|
453
449
|
* harness's own resolution in front of the walk where the harness has one,
|
|
@@ -505,6 +501,11 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
505
501
|
* refuse a hot mount to a package this process never imported.
|
|
506
502
|
*/
|
|
507
503
|
private installedSpecOf;
|
|
504
|
+
/** Add every dependency the profile manifest holds to the `imported`
|
|
505
|
+
* record (see `importedThisProcess`): each is a package dsh's loader may
|
|
506
|
+
* have loaded in this process, at boot or by an install since. An
|
|
507
|
+
* unreadable manifest adds nothing. */
|
|
508
|
+
private recordDependenciesImported;
|
|
508
509
|
private ownedEntryIdsOrNone;
|
|
509
510
|
/** Whether an installed package declares `dsh.client`. Reads through the
|
|
510
511
|
* `hotFs` option — `HotFs` is `hot.ts`'s type, but this gateway forwards
|
|
@@ -554,6 +555,26 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
554
555
|
* float a registry package to `latest`.
|
|
555
556
|
*/
|
|
556
557
|
private setDeselectedEnabled;
|
|
558
|
+
/**
|
|
559
|
+
* dsh's answer to a switch or a bundle selection, read the one way both
|
|
560
|
+
* callers need it (R32): the change, scrubbed for a desktop reader, and the
|
|
561
|
+
* detail that fails the request, or null when dsh applied it. `act` is what
|
|
562
|
+
* was asked, as "switch <name>", `request` names the request itself, as
|
|
563
|
+
* "the switch for <name>", and `stays` is the state the plugin keeps when
|
|
564
|
+
* the request does not take effect. An application this shop does not know
|
|
565
|
+
* fails rather than reading as applied: a later harness may answer
|
|
566
|
+
* something new.
|
|
567
|
+
*
|
|
568
|
+
* `overridden` fails too (R39). dsh answers it when, after it wrote the row
|
|
569
|
+
* and reloaded, the live entry still differs from the request
|
|
570
|
+
* (dsh-plugin-manager 0.1.7-rc.2, setPluginEnabled), and its README names
|
|
571
|
+
* what outranks the profile's own patch: home and invocation patches keep
|
|
572
|
+
* their higher priority. The change is saved and the plugin runs as it
|
|
573
|
+
* did, so a success would flip the client's switch over a plugin that did
|
|
574
|
+
* not change, and that switch never re-reads the live state.
|
|
575
|
+
* setBundleEnabled never answers it; a selection reads it the same way.
|
|
576
|
+
*/
|
|
577
|
+
private readManagerAnswer;
|
|
557
578
|
private rowConfig;
|
|
558
579
|
/** The user's own registry, read once. The self-update check and catalog
|
|
559
580
|
* race share this preference so neither path repeatedly touches ~/.npmrc. */
|
|
@@ -628,6 +649,46 @@ export declare class ShopGateway extends TypertRemoteService {
|
|
|
628
649
|
* passing request reaches the executor.
|
|
629
650
|
*/
|
|
630
651
|
install(args: InstallArgs): Promise<ShopInstallResult>;
|
|
652
|
+
/**
|
|
653
|
+
* What would stop the profile from starting now that `name`'s files are on
|
|
654
|
+
* disk, or null: an entry id another installed package already declares,
|
|
655
|
+
* or a bundle patch declaration this dsh cannot read. Neither is knowable
|
|
656
|
+
* before the files land. The package stays on disk either way, so each
|
|
657
|
+
* detail ends with `undo`, the sentence that says how to take the install
|
|
658
|
+
* back on the path that made it.
|
|
659
|
+
*/
|
|
660
|
+
private postInstallHazard;
|
|
661
|
+
/** Remember a github entry's pinned commit: the manifest records only
|
|
662
|
+
* `github:owner/slug`, so the pins file is how `installed()` reports
|
|
663
|
+
* outdated honestly. A failed install leaves a pin behind, but the
|
|
664
|
+
* manifest presence gate keeps it invisible. */
|
|
665
|
+
private recordGithubPin;
|
|
666
|
+
/** Forget an uninstalled package's pins: its own, and its identity pin when
|
|
667
|
+
* a catalog row matched the installed spec. Both uninstall paths call this
|
|
668
|
+
* once their operation has started, so a stale pin never outlives the
|
|
669
|
+
* uninstall in the shop's cache either way. The plugin manager path tracks
|
|
670
|
+
* its record first, so a write here that throws cannot hide an operation
|
|
671
|
+
* already queued. */
|
|
672
|
+
private forgetPins;
|
|
673
|
+
/** What `managerOutcome` reads dsh's answer against. The gateway's own
|
|
674
|
+
* facts are set here once, for every operation through the service: the
|
|
675
|
+
* profile, whether it is the desktop one, and the deadline a timeout
|
|
676
|
+
* detail names. */
|
|
677
|
+
private outcomeContext;
|
|
678
|
+
/**
|
|
679
|
+
* One install-shaped operation through dsh's `pluginManager` (design
|
|
680
|
+
* 2026-09-26-plugin-manager-delegation, section 6): `installBundle(spec)`
|
|
681
|
+
* under the record's own id as its request id, so the output dsh streams
|
|
682
|
+
* for it reaches this record, in the profile's queue with the download
|
|
683
|
+
* phase the CLI path has. At the shop's deadline dsh is asked to cancel it;
|
|
684
|
+
* a service that offers no `cancelInstall` gets no deadline, and its record
|
|
685
|
+
* settles when dsh answers. `install` and `updateStart` differ only in the
|
|
686
|
+
* mechanism line and in how they read the answer.
|
|
687
|
+
*/
|
|
688
|
+
private startManagerInstall;
|
|
689
|
+
/** Keep a started record where `installStatus`, the restart gate and
|
|
690
|
+
* eviction find it, then bound the finished ones. */
|
|
691
|
+
private track;
|
|
631
692
|
/** Bound retained finished records at MAX_FINISHED_INSTALLS, evicting the
|
|
632
693
|
* oldest finished ones (insertion order, oldest first). Live records —
|
|
633
694
|
* running AND queued — are never evicted; an id absent from the map reports
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One package operation through dsh's `pluginManager` service, tracked as the
|
|
3
|
+
* same `RunningInstall` the CLI executor produces: design
|
|
4
|
+
* 2026-09-26-plugin-manager-delegation, section 6. It runs in the same
|
|
5
|
+
* per-profile queue as CLI commands, so the two paths are never concurrent in
|
|
6
|
+
* one profile.
|
|
7
|
+
*/
|
|
8
|
+
import { type RunningInstall } from './executor.ts';
|
|
9
|
+
import { type ManagerOutcome } from './plugin-manager.ts';
|
|
10
|
+
import type { Prefetcher } from './prefetch.ts';
|
|
11
|
+
/** The first line of every record this runner writes. The shop's log panel
|
|
12
|
+
* shows it and the 0.1.7 e2e asserts it, so a silent fall back to the CLI
|
|
13
|
+
* fails a case instead of passing it. */
|
|
14
|
+
export declare const MECHANISM_PREFIX = "via dsh's plugin manager:";
|
|
15
|
+
/** Routes the service's `plugin-manager/install-log` chunks to the record
|
|
16
|
+
* whose request id they carry. A chunk for any other id is dropped. dsh
|
|
17
|
+
* tags each chunk with the stream it came from; a non-string stream reads
|
|
18
|
+
* as `stdout`, matching a harness that predates the tag. */
|
|
19
|
+
export declare class ManagerLogs {
|
|
20
|
+
private readonly sinks;
|
|
21
|
+
open(requestId: string, sink: (text: string, stream: string) => void): () => void;
|
|
22
|
+
chunk(requestId: unknown, text: unknown, stream?: unknown): void;
|
|
23
|
+
}
|
|
24
|
+
export interface ManagerOperationOptions {
|
|
25
|
+
profile: string;
|
|
26
|
+
/** The record's id, handed to the service as its request id. */
|
|
27
|
+
requestId: string;
|
|
28
|
+
/** What the mechanism line says after the prefix, e.g. `install dsh-a@1.0.0`. */
|
|
29
|
+
mechanism: string;
|
|
30
|
+
logs: ManagerLogs;
|
|
31
|
+
run: (requestId: string) => Promise<unknown>;
|
|
32
|
+
cancel?: (requestId: string) => Promise<unknown>;
|
|
33
|
+
outcome: (raw: unknown) => ManagerOutcome;
|
|
34
|
+
alsoConfirm?: () => string | null;
|
|
35
|
+
/** The download phase, as on the CLI path: `spec` is what it warms. */
|
|
36
|
+
prefetcher?: Prefetcher;
|
|
37
|
+
spec?: string;
|
|
38
|
+
env?: NodeJS.ProcessEnv;
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
/** The desktop profile, whose readers can run no `dsh plugin` command: a
|
|
41
|
+
* message the service call throws is scrubbed as dsh's answer is. */
|
|
42
|
+
desktop?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** What a thrown value says about itself, and total: describing an error is
|
|
45
|
+
* never itself the reason a settle fails. An `Error` gives its `message`,
|
|
46
|
+
* anything else `String(value)`. A message that is not a string, or a
|
|
47
|
+
* description that throws anywhere, reads as one fixed string: a Proxy whose
|
|
48
|
+
* getPrototypeOf trap throws defeats `instanceof` itself, a `message` getter
|
|
49
|
+
* can throw, and a null-prototype object has no conversion to a string. */
|
|
50
|
+
export declare const messageOf: (error: unknown) => string;
|
|
51
|
+
export declare function startManagerOperation(options: ManagerOperationOptions): RunningInstall;
|