dsh-plugin-shop 0.8.7 → 0.9.0-beta.1
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/lib/client.js +1529 -744
- package/lib/types/client/ShopDetailAction.d.ts +46 -0
- package/lib/types/client/ShopGlyph.d.ts +12 -0
- package/lib/types/client/ShopPage.d.ts +27 -0
- package/lib/types/client/ShopTab.d.ts +27 -10
- package/lib/types/client/flow-registry.d.ts +89 -0
- package/lib/types/client/index.d.ts +52 -7
- package/lib/types/client/listeners.d.ts +27 -0
- package/lib/types/client/locales.d.ts +15 -5
- package/lib/types/client/page-store.d.ts +255 -0
- package/lib/types/client/present.d.ts +26 -6
- package/lib/types/client/restart-monitor.d.ts +11 -0
- package/lib/types/client/useFlows.d.ts +34 -26
- package/lib/types/client/useUpdateSelf.d.ts +19 -16
- package/package.json +1 -1
- package/lib/types/client/ShopSection.d.ts +0 -10
- package/lib/types/client/useInstall.d.ts +0 -31
- package/lib/types/client/useUninstall.d.ts +0 -28
|
@@ -233,8 +233,9 @@ export interface InstallStatusShape {
|
|
|
233
233
|
/** The install view state machine (§7.2). `phase` distinguishes the download
|
|
234
234
|
* that runs ahead of the per-profile mutex from the install that holds it.
|
|
235
235
|
* It rides the `running` kind rather than adding a kind of its own: every
|
|
236
|
-
* `view.kind === 'running'` site —
|
|
237
|
-
* them — must keep treating a downloading install
|
|
236
|
+
* `view.kind === 'running'` site — the flow registry's poll collection
|
|
237
|
+
* (flow-registry.ts) among them — must keep treating a downloading install
|
|
238
|
+
* as live. */
|
|
238
239
|
export type InstallView = {
|
|
239
240
|
kind: 'idle';
|
|
240
241
|
} | {
|
|
@@ -328,12 +329,23 @@ export declare function restartMonitorVerdict(input: {
|
|
|
328
329
|
* a host older than the field, the one that matters most.
|
|
329
330
|
*/
|
|
330
331
|
export declare function answeredByAnotherProcess(previous: ShopVersionResult, next: ShopVersionResult): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* Whether an update of the shop has landed and waits for a restart: the
|
|
334
|
+
* profile holds a version other than the one running. A host older than the
|
|
335
|
+
* field sends none, and that reads as waiting: a client newer than its host
|
|
336
|
+
* exists only because the disk holds a newer shop than the process running
|
|
337
|
+
* (design §7.3, 2026-09-27 amendment). The tab's restart offer and the
|
|
338
|
+
* hand-over after a hot swap (design 2026-10-16-shop-sidebar-page §6) read
|
|
339
|
+
* it alike.
|
|
340
|
+
*/
|
|
341
|
+
export declare function updateAwaitsRestart(version: ShopVersionResult): boolean;
|
|
331
342
|
/**
|
|
332
343
|
* Whether dsh restarting under the page settles this receipt: a change that
|
|
333
|
-
* landed and was waiting for exactly that. The
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* running settles by
|
|
344
|
+
* landed and was waiting for exactly that. The page store clears these
|
|
345
|
+
* (page-store.ts, `noteRestarted`) once the answers come from another
|
|
346
|
+
* process, and nothing else — a reload is still owed by a page nobody
|
|
347
|
+
* reloaded, a failure still happened, and a flow still running settles by
|
|
348
|
+
* its own poll.
|
|
337
349
|
*/
|
|
338
350
|
export declare function settledByRestart(view: InstallView): boolean;
|
|
339
351
|
/** How long the check-update button reports "up to date" after a re-check
|
|
@@ -456,6 +468,14 @@ export declare function npmPageUrl(entry: CatalogEntry): string | null;
|
|
|
456
468
|
* This mirrors the registry's identity verbatim; the two must not drift.
|
|
457
469
|
*/
|
|
458
470
|
export declare function entryKey(entry: CatalogEntry): string;
|
|
471
|
+
/**
|
|
472
|
+
* Whether the shelf lists `entry`: a name the catalog's `notAShop` clears,
|
|
473
|
+
* or one whose name and repository `isShopLike` leaves alone. One rule for
|
|
474
|
+
* the shelf and for the Plugins page's "View in Plugin shop" (design
|
|
475
|
+
* 2026-10-16-shop-sidebar-page §7), so that button never sends a reader to a
|
|
476
|
+
* shelf that hides the plugin.
|
|
477
|
+
*/
|
|
478
|
+
export declare function listedOnShelf(entry: CatalogEntry, cleared: ReadonlySet<string>): boolean;
|
|
459
479
|
/**
|
|
460
480
|
* One entry's star count from the sidecar, or undefined when it has none.
|
|
461
481
|
*
|
|
@@ -72,6 +72,17 @@ export type RestartRequestOutcome = {
|
|
|
72
72
|
} | {
|
|
73
73
|
kind: 'unreachable';
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Whether a shop instance on this page has registered its restart path:
|
|
77
|
+
* every `apply` since 0.8.4 does so before anything can ask for a restart.
|
|
78
|
+
* Read before this instance's own `apply` registers one, a store here names
|
|
79
|
+
* a predecessor — a 0.8.x shop when no page store sits beside it
|
|
80
|
+
* (page-store.ts `readPredecessor`; design 2026-10-16-shop-sidebar-page §6).
|
|
81
|
+
* The store outlives a carrier's withdrawal: a predecessor's teardown
|
|
82
|
+
* withdraws its carrier and leaves the store, and the store is what names it.
|
|
83
|
+
* Only a read: unlike `monitorStore`, it never creates the store.
|
|
84
|
+
*/
|
|
85
|
+
export declare function hasRestartMonitorStore(): boolean;
|
|
75
86
|
/** The page's restart, or null when it has committed none. The same object
|
|
76
87
|
* until the state changes, as `useSyncExternalStore` requires. */
|
|
77
88
|
export declare function readRestartMonitor(): RestartMonitorState | null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* React's view of a keyed registry of install-shaped flows (flow-registry.ts):
|
|
3
|
+
* start, poll to terminal, reset.
|
|
3
4
|
*
|
|
4
5
|
* Install and uninstall are the same machine. Both fold a
|
|
5
6
|
* `ShopInstallStatusResult` through `reduceInstall` into an `InstallView`,
|
|
@@ -12,16 +13,22 @@
|
|
|
12
13
|
* install refusal is a `rejected` view carrying the gate's code; an uninstall
|
|
13
14
|
* refusal is a `failed` view carrying the host's published detail, because
|
|
14
15
|
* `ShopUninstallResult`'s failure variant has no code to populate and those
|
|
15
|
-
* codes belong to the install gate. That difference is the
|
|
16
|
-
* and it is the whole of it.
|
|
16
|
+
* codes belong to the install gate. That difference is the registry's
|
|
17
|
+
* `begin`, and it is the whole of it.
|
|
17
18
|
*
|
|
18
19
|
* The two used to be hand-synced copies — 71 of 84 lines identical. The cost
|
|
19
20
|
* was not theoretical: a single review round had to make the same edit twice
|
|
20
21
|
* (the settle signature, and its call), and the `pending` set below was added
|
|
21
22
|
* to one of them and not the other before this module existed.
|
|
23
|
+
*
|
|
24
|
+
* Since 2026-10-16 the registry is its own module, framework-free, and the
|
|
25
|
+
* polling belongs to it: a component's effect stopped the moment the shop left
|
|
26
|
+
* the screen (design 2026-10-16-shop-sidebar-page §5). This module only
|
|
27
|
+
* renders one, through `useRegistryFlows`.
|
|
22
28
|
*/
|
|
23
|
-
import type {
|
|
24
|
-
import { type
|
|
29
|
+
import type { InstallArgs } from '../host/index.ts';
|
|
30
|
+
import { type FlowRegistry } from './flow-registry.ts';
|
|
31
|
+
import type { InstallView } from './present.ts';
|
|
25
32
|
/** One identity's flow, as the tab hands it to a panel. */
|
|
26
33
|
export interface KeyedFlow<TArgs> {
|
|
27
34
|
view: InstallView;
|
|
@@ -39,16 +46,13 @@ export interface UseKeyedFlows<TArgs> {
|
|
|
39
46
|
* moves. The accessor's identity still tracks `views`; the result's does
|
|
40
47
|
* not, and the result is what a card should be given. */
|
|
41
48
|
flowFor: (key: string) => KeyedFlow<TArgs>;
|
|
42
|
-
/** Return one identity to `idle` without building a flow for it. Stable
|
|
43
|
-
* across renders (unlike `flowFor`, whose identity tracks `views`), so one
|
|
44
|
-
* registry's settle callback can supersede the other's receipt for the same
|
|
45
|
-
* key without taking a dependency on that registry's output. */
|
|
46
|
-
resetFlow: (key: string) => void;
|
|
47
49
|
/** Return every identity whose view `predicate` selects to `idle`, and
|
|
48
|
-
* nothing else. Stable across renders
|
|
50
|
+
* nothing else. Stable across renders, unlike `flowFor`; a call selecting
|
|
49
51
|
* nothing leaves the registry — and so every flow and `pending` — exactly
|
|
50
|
-
* as it was. The
|
|
51
|
-
*
|
|
52
|
+
* as it was. The receipts dsh restarting under the page settled are
|
|
53
|
+
* cleared the same way at the store, through each registry's own
|
|
54
|
+
* `resetWhere` (page-store.ts `noteRestarted`; design §8, 2026-10-06
|
|
55
|
+
* amendment). */
|
|
52
56
|
resetWhere: (predicate: (view: InstallView) => boolean) => void;
|
|
53
57
|
/**
|
|
54
58
|
* The identities whose flow is not `idle` — asked by the shelf, which has
|
|
@@ -65,16 +69,20 @@ export interface UseKeyedFlows<TArgs> {
|
|
|
65
69
|
*/
|
|
66
70
|
pending: ReadonlySet<string>;
|
|
67
71
|
}
|
|
68
|
-
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*/
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
}
|
|
72
|
+
/** One entry's install flow, as the tab hands it to a panel: the page
|
|
73
|
+
* store's install registry (page-store.ts), begun through flow-registry.ts's
|
|
74
|
+
* `beginInstall`. */
|
|
75
|
+
export type InstallFlow = KeyedFlow<InstallArgs>;
|
|
76
|
+
/** One entry's uninstall flow, as the tab hands it to a panel: the page
|
|
77
|
+
* store's uninstall registry, begun through `beginUninstall`. */
|
|
78
|
+
export type UninstallFlow = KeyedFlow<{
|
|
79
|
+
name: string;
|
|
80
|
+
}>;
|
|
81
|
+
/** The uninstall flows as the tab hands them to the shadowed rows. */
|
|
82
|
+
export type UseUninstallFlows = UseKeyedFlows<{
|
|
83
|
+
name: string;
|
|
84
|
+
}>;
|
|
85
|
+
/** The keyed-flow face over any registry: one of the page store's, which
|
|
86
|
+
* outlives the component, or one of the store a tab builds for itself when
|
|
87
|
+
* none is handed over (ShopTab). */
|
|
88
|
+
export declare function useRegistryFlows<TArgs>(registry: FlowRegistry<TArgs>): UseKeyedFlows<TArgs>;
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
import {
|
|
1
|
+
/** The shop's own update as the tab renders it: the face over the registry
|
|
2
|
+
* that holds it, a page store's `self` (page-store.ts). It shares the install
|
|
3
|
+
* view machine and the registry's polling; its start mapping is
|
|
4
|
+
* flow-registry.ts's `beginUpdate`, which shares the uninstall's refusal
|
|
5
|
+
* rule — a business refusal (a non-semver version) lands in the `failed`
|
|
6
|
+
* view with the host's detail, never in the install `rejected` codes. */
|
|
7
|
+
import type { FlowRegistry } from './flow-registry.ts';
|
|
8
|
+
import type { InstallView } from './present.ts';
|
|
8
9
|
export interface UseUpdateSelfResult {
|
|
9
10
|
view: InstallView;
|
|
10
11
|
start: (args: {
|
|
11
12
|
version: string;
|
|
12
13
|
}) => Promise<void>;
|
|
13
14
|
/** Return the view to `idle` when `predicate` selects it; stable across
|
|
14
|
-
* renders. The
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* renders. The failed panel's Dismiss uses it, so the version row decides
|
|
16
|
+
* again; an update waiting for a restart is settled at the store instead,
|
|
17
|
+
* when dsh restarts under the page (page-store.ts `noteRestarted`; design
|
|
18
|
+
* §8, 2026-10-06 amendment). */
|
|
17
19
|
resetWhere: (predicate: (view: InstallView) => boolean) => void;
|
|
18
20
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
/** The one key the self-update registry holds: the shop has one update. */
|
|
22
|
+
export declare const SELF_UPDATE_KEY = "self";
|
|
23
|
+
/** The self-update face over a registry: the keyed-flow face
|
|
24
|
+
* (`useRegistryFlows`) at its one key, so the subscription and the flow's
|
|
25
|
+
* identity are that hook's and nothing here can drift from it. */
|
|
26
|
+
export declare function useRegistrySelf(registry: FlowRegistry<{
|
|
22
27
|
version: string;
|
|
23
|
-
})
|
|
24
|
-
installId: string;
|
|
25
|
-
}) => Promise<ShopInstallStatusResult>): UseUpdateSelfResult;
|
|
28
|
+
}>): UseUpdateSelfResult;
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The shop's Settings section (design §5.1, amended 2026-10-15): its own
|
|
3
|
-
* entry in the Settings nav, directly after Built-in plugins, where it used
|
|
4
|
-
* to be a tab inside that section. The page carries the title and the one
|
|
5
|
-
* intro line the built-in Models and Built-in plugins pages carry, above the
|
|
6
|
-
* shop body, which is `ShopTab` unchanged.
|
|
7
|
-
*/
|
|
8
|
-
import type { ReactNode } from 'react';
|
|
9
|
-
import { type ShopTabProps } from './ShopTab.tsx';
|
|
10
|
-
export declare function ShopSection(props: ShopTabProps): ReactNode;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** Install driving hooks: the shared poll loop, and the tab's keyed registry. */
|
|
2
|
-
import { type Dispatch, type SetStateAction } from 'react';
|
|
3
|
-
import { type InstallView } from './present.ts';
|
|
4
|
-
import { type KeyedFlow, type UseKeyedFlows } from './useFlows.ts';
|
|
5
|
-
import type { InstallArgs, ShopInstallResult, ShopInstallStatusResult } from '../host/index.ts';
|
|
6
|
-
/** The single-view poll loop: while the view is `running`, poll once per
|
|
7
|
-
* second and fold each status through the reducer. A poll failure is
|
|
8
|
-
* transient — the host retains the record, so the next tick finds it. The
|
|
9
|
-
* rejection handler must be present: an unhandled rejection here would
|
|
10
|
-
* escape the poll loop.
|
|
11
|
-
*
|
|
12
|
-
* Kept for the self-update (`useUpdateSelf`), which drives ONE flow with no
|
|
13
|
-
* identity to key it by. Everything per-plugin goes through `useKeyedFlows`,
|
|
14
|
-
* whose own loop polls every running identity from one interval. */
|
|
15
|
-
export declare function usePollStatus(view: InstallView, setView: Dispatch<SetStateAction<InstallView>>, installStatus: (args: {
|
|
16
|
-
installId: string;
|
|
17
|
-
}) => Promise<ShopInstallStatusResult>): void;
|
|
18
|
-
/** One entry's install flow, as the tab hands it to a panel. */
|
|
19
|
-
export type InstallFlow = KeyedFlow<InstallArgs>;
|
|
20
|
-
export type UseInstallFlows = UseKeyedFlows<InstallArgs>;
|
|
21
|
-
/**
|
|
22
|
-
* Install flows owned by the tab and keyed by install identity. Keeping the
|
|
23
|
-
* state above individual cards preserves a running operation when filtering
|
|
24
|
-
* unmounts its card, and makes the shelf and Outdated panels agree.
|
|
25
|
-
*
|
|
26
|
-
* The registry itself is `useKeyedFlows`; this supplies the one thing that is
|
|
27
|
-
* install-specific — what the starting RPC's answer means.
|
|
28
|
-
*/
|
|
29
|
-
export declare function useInstallFlows(install: (args: InstallArgs) => Promise<ShopInstallResult>, installStatus: (args: {
|
|
30
|
-
installId: string;
|
|
31
|
-
}) => Promise<ShopInstallStatusResult>, onSettled?: (key: string, outcome: 'done' | 'failed') => void): UseInstallFlows;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/** Uninstall driving hook: the tab's keyed registry, one start mapping. */
|
|
2
|
-
import type { ShopInstallStatusResult, ShopUninstallResult } from '../host/index.ts';
|
|
3
|
-
import { type KeyedFlow, type UseKeyedFlows } from './useFlows.ts';
|
|
4
|
-
/** One entry's uninstall flow, as the tab hands it to a panel. */
|
|
5
|
-
export type UninstallFlow = KeyedFlow<{
|
|
6
|
-
name: string;
|
|
7
|
-
}>;
|
|
8
|
-
export type UseUninstallFlows = UseKeyedFlows<{
|
|
9
|
-
name: string;
|
|
10
|
-
}>;
|
|
11
|
-
/**
|
|
12
|
-
* Uninstall flows owned by the tab and keyed by install identity. Lifting the
|
|
13
|
-
* state above individual cards is what lets a completed uninstall's outcome
|
|
14
|
-
* survive the installed-projection refresh that follows it — the row backing
|
|
15
|
-
* the card disappears, but the flow keyed by identity does not.
|
|
16
|
-
*
|
|
17
|
-
* The registry itself is `useKeyedFlows`; this supplies the one thing that is
|
|
18
|
-
* uninstall-specific — what the starting RPC's answer means. An uninstall
|
|
19
|
-
* business failure (not in the catalog / not installed) lands in the `failed`
|
|
20
|
-
* view with the host's published detail, never in the install `rejected`
|
|
21
|
-
* codes: those belong to the install gate, and `ShopUninstallResult`'s
|
|
22
|
-
* failure variant has no `code` field to populate.
|
|
23
|
-
*/
|
|
24
|
-
export declare function useUninstallFlows(uninstall: (args: {
|
|
25
|
-
name: string;
|
|
26
|
-
}) => Promise<ShopUninstallResult>, installStatus: (args: {
|
|
27
|
-
installId: string;
|
|
28
|
-
}) => Promise<ShopInstallStatusResult>, onSettled?: (key: string, outcome: 'done' | 'failed') => void): UseUninstallFlows;
|