sh3-core 0.6.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/README.md +9 -0
- package/dist/Shell.svelte +283 -0
- package/dist/Shell.svelte.d.ts +5 -0
- package/dist/api.d.ts +28 -0
- package/dist/api.js +50 -0
- package/dist/app/admin/ApiKeysView.svelte +169 -0
- package/dist/app/admin/ApiKeysView.svelte.d.ts +3 -0
- package/dist/app/admin/AuthSettingsView.svelte +105 -0
- package/dist/app/admin/AuthSettingsView.svelte.d.ts +3 -0
- package/dist/app/admin/SystemView.svelte +73 -0
- package/dist/app/admin/SystemView.svelte.d.ts +3 -0
- package/dist/app/admin/UsersView.svelte +188 -0
- package/dist/app/admin/UsersView.svelte.d.ts +3 -0
- package/dist/app/admin/adminApp.d.ts +7 -0
- package/dist/app/admin/adminApp.js +25 -0
- package/dist/app/admin/adminShard.svelte.d.ts +4 -0
- package/dist/app/admin/adminShard.svelte.js +62 -0
- package/dist/app/store/InstalledView.svelte +246 -0
- package/dist/app/store/InstalledView.svelte.d.ts +3 -0
- package/dist/app/store/StoreView.svelte +522 -0
- package/dist/app/store/StoreView.svelte.d.ts +3 -0
- package/dist/app/store/storeApp.d.ts +10 -0
- package/dist/app/store/storeApp.js +26 -0
- package/dist/app/store/storeShard.svelte.d.ts +38 -0
- package/dist/app/store/storeShard.svelte.js +218 -0
- package/dist/apps/lifecycle.d.ts +42 -0
- package/dist/apps/lifecycle.js +184 -0
- package/dist/apps/registry.svelte.d.ts +40 -0
- package/dist/apps/registry.svelte.js +59 -0
- package/dist/apps/terminal/manifest.d.ts +8 -0
- package/dist/apps/terminal/manifest.js +13 -0
- package/dist/apps/terminal/terminal-app.d.ts +7 -0
- package/dist/apps/terminal/terminal-app.js +14 -0
- package/dist/apps/types.d.ts +93 -0
- package/dist/apps/types.js +10 -0
- package/dist/artifact.d.ts +32 -0
- package/dist/artifact.js +1 -0
- package/dist/assets/SH3.png +0 -0
- package/dist/assets/icons.svg +1126 -0
- package/dist/assets.d.ts +13 -0
- package/dist/auth/GuestBanner.svelte +134 -0
- package/dist/auth/GuestBanner.svelte.d.ts +3 -0
- package/dist/auth/SignInWall.svelte +203 -0
- package/dist/auth/SignInWall.svelte.d.ts +7 -0
- package/dist/auth/auth.svelte.d.ts +69 -0
- package/dist/auth/auth.svelte.js +165 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/types.d.ts +41 -0
- package/dist/auth/types.js +6 -0
- package/dist/build.d.ts +49 -0
- package/dist/build.js +236 -0
- package/dist/contract.d.ts +20 -0
- package/dist/contract.js +28 -0
- package/dist/createShell.d.ts +24 -0
- package/dist/createShell.js +131 -0
- package/dist/documents/backends.d.ts +17 -0
- package/dist/documents/backends.js +156 -0
- package/dist/documents/config.d.ts +7 -0
- package/dist/documents/config.js +27 -0
- package/dist/documents/handle.d.ts +6 -0
- package/dist/documents/handle.js +154 -0
- package/dist/documents/http-backend.d.ts +22 -0
- package/dist/documents/http-backend.js +78 -0
- package/dist/documents/index.d.ts +6 -0
- package/dist/documents/index.js +8 -0
- package/dist/documents/notifications.d.ts +9 -0
- package/dist/documents/notifications.js +39 -0
- package/dist/documents/types.d.ts +97 -0
- package/dist/documents/types.js +12 -0
- package/dist/env/client.d.ts +44 -0
- package/dist/env/client.js +106 -0
- package/dist/env/index.d.ts +2 -0
- package/dist/env/index.js +1 -0
- package/dist/env/types.d.ts +12 -0
- package/dist/env/types.js +8 -0
- package/dist/host-entry.d.ts +13 -0
- package/dist/host-entry.js +17 -0
- package/dist/host.d.ts +15 -0
- package/dist/host.js +86 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +14 -0
- package/dist/layout/DragPreview.svelte +63 -0
- package/dist/layout/DragPreview.svelte.d.ts +3 -0
- package/dist/layout/LayoutRenderer.svelte +262 -0
- package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
- package/dist/layout/SlotContainer.svelte +140 -0
- package/dist/layout/SlotContainer.svelte.d.ts +8 -0
- package/dist/layout/SlotDropZone.svelte +122 -0
- package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
- package/dist/layout/drag.svelte.d.ts +45 -0
- package/dist/layout/drag.svelte.js +200 -0
- package/dist/layout/inspection.d.ts +72 -0
- package/dist/layout/inspection.js +209 -0
- package/dist/layout/ops.d.ts +100 -0
- package/dist/layout/ops.js +310 -0
- package/dist/layout/slotHostPool.svelte.d.ts +36 -0
- package/dist/layout/slotHostPool.svelte.js +229 -0
- package/dist/layout/store.svelte.d.ts +39 -0
- package/dist/layout/store.svelte.js +153 -0
- package/dist/layout/tree-walk.d.ts +15 -0
- package/dist/layout/tree-walk.js +33 -0
- package/dist/layout/types.d.ts +108 -0
- package/dist/layout/types.js +25 -0
- package/dist/migrations/shell-rename.d.ts +16 -0
- package/dist/migrations/shell-rename.js +48 -0
- package/dist/overlays/ModalFrame.svelte +87 -0
- package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
- package/dist/overlays/PopupFrame.svelte +85 -0
- package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
- package/dist/overlays/ToastItem.svelte +77 -0
- package/dist/overlays/ToastItem.svelte.d.ts +9 -0
- package/dist/overlays/focusTrap.d.ts +1 -0
- package/dist/overlays/focusTrap.js +64 -0
- package/dist/overlays/modal.d.ts +9 -0
- package/dist/overlays/modal.js +141 -0
- package/dist/overlays/popup.d.ts +9 -0
- package/dist/overlays/popup.js +108 -0
- package/dist/overlays/roots.d.ts +4 -0
- package/dist/overlays/roots.js +31 -0
- package/dist/overlays/toast.d.ts +6 -0
- package/dist/overlays/toast.js +93 -0
- package/dist/overlays/types.d.ts +31 -0
- package/dist/overlays/types.js +15 -0
- package/dist/platform/index.d.ts +10 -0
- package/dist/platform/index.js +33 -0
- package/dist/platform/tauri-backend.d.ts +15 -0
- package/dist/platform/tauri-backend.js +58 -0
- package/dist/primitives/.gitkeep +0 -0
- package/dist/primitives/ResizableSplitter.svelte +333 -0
- package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
- package/dist/primitives/TabbedPanel.svelte +305 -0
- package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
- package/dist/primitives/base.css +42 -0
- package/dist/registry/client.d.ts +74 -0
- package/dist/registry/client.js +117 -0
- package/dist/registry/index.d.ts +13 -0
- package/dist/registry/index.js +14 -0
- package/dist/registry/installer.d.ts +53 -0
- package/dist/registry/installer.js +168 -0
- package/dist/registry/integrity.d.ts +32 -0
- package/dist/registry/integrity.js +92 -0
- package/dist/registry/loader.d.ts +50 -0
- package/dist/registry/loader.js +145 -0
- package/dist/registry/schema.d.ts +47 -0
- package/dist/registry/schema.js +185 -0
- package/dist/registry/storage.d.ts +37 -0
- package/dist/registry/storage.js +101 -0
- package/dist/registry/types.d.ts +262 -0
- package/dist/registry/types.js +14 -0
- package/dist/server-shard/types.d.ts +67 -0
- package/dist/server-shard/types.js +13 -0
- package/dist/sh3core-shard/ShellHome.svelte +192 -0
- package/dist/sh3core-shard/ShellHome.svelte.d.ts +3 -0
- package/dist/sh3core-shard/ShellTitle.svelte +171 -0
- package/dist/sh3core-shard/ShellTitle.svelte.d.ts +3 -0
- package/dist/sh3core-shard/sh3coreShard.svelte.d.ts +2 -0
- package/dist/sh3core-shard/sh3coreShard.svelte.js +53 -0
- package/dist/shards/activate.svelte.d.ts +52 -0
- package/dist/shards/activate.svelte.js +186 -0
- package/dist/shards/registry.d.ts +4 -0
- package/dist/shards/registry.js +28 -0
- package/dist/shards/types.d.ts +207 -0
- package/dist/shards/types.js +20 -0
- package/dist/shell-shard/InputLine.svelte +133 -0
- package/dist/shell-shard/InputLine.svelte.d.ts +11 -0
- package/dist/shell-shard/ScrollbackView.svelte +47 -0
- package/dist/shell-shard/ScrollbackView.svelte.d.ts +7 -0
- package/dist/shell-shard/Terminal.svelte +122 -0
- package/dist/shell-shard/Terminal.svelte.d.ts +8 -0
- package/dist/shell-shard/entries/PromptEntry.svelte +25 -0
- package/dist/shell-shard/entries/PromptEntry.svelte.d.ts +7 -0
- package/dist/shell-shard/entries/RichEntry.svelte +19 -0
- package/dist/shell-shard/entries/RichEntry.svelte.d.ts +8 -0
- package/dist/shell-shard/entries/StatusEntry.svelte +22 -0
- package/dist/shell-shard/entries/StatusEntry.svelte.d.ts +7 -0
- package/dist/shell-shard/entries/TextEntry.svelte +25 -0
- package/dist/shell-shard/entries/TextEntry.svelte.d.ts +7 -0
- package/dist/shell-shard/manifest.d.ts +2 -0
- package/dist/shell-shard/manifest.js +11 -0
- package/dist/shell-shard/protocol.d.ts +90 -0
- package/dist/shell-shard/protocol.js +11 -0
- package/dist/shell-shard/registry.d.ts +69 -0
- package/dist/shell-shard/registry.js +47 -0
- package/dist/shell-shard/rich/AppCard.svelte +25 -0
- package/dist/shell-shard/rich/AppCard.svelte.d.ts +10 -0
- package/dist/shell-shard/rich/AppsTable.svelte +29 -0
- package/dist/shell-shard/rich/AppsTable.svelte.d.ts +12 -0
- package/dist/shell-shard/rich/EnvTable.svelte +27 -0
- package/dist/shell-shard/rich/EnvTable.svelte.d.ts +8 -0
- package/dist/shell-shard/rich/HelpTable.svelte +29 -0
- package/dist/shell-shard/rich/HelpTable.svelte.d.ts +12 -0
- package/dist/shell-shard/rich/HistoryList.svelte +37 -0
- package/dist/shell-shard/rich/HistoryList.svelte.d.ts +9 -0
- package/dist/shell-shard/rich/ShardsTable.svelte +28 -0
- package/dist/shell-shard/rich/ShardsTable.svelte.d.ts +12 -0
- package/dist/shell-shard/rich/ViewsTable.svelte +31 -0
- package/dist/shell-shard/rich/ViewsTable.svelte.d.ts +13 -0
- package/dist/shell-shard/rich/ZoneTree.svelte +19 -0
- package/dist/shell-shard/rich/ZoneTree.svelte.d.ts +8 -0
- package/dist/shell-shard/rich/ZonesTable.svelte +27 -0
- package/dist/shell-shard/rich/ZonesTable.svelte.d.ts +11 -0
- package/dist/shell-shard/scrollback.svelte.d.ts +36 -0
- package/dist/shell-shard/scrollback.svelte.js +43 -0
- package/dist/shell-shard/session-client.svelte.d.ts +23 -0
- package/dist/shell-shard/session-client.svelte.js +120 -0
- package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
- package/dist/shell-shard/shellShard.svelte.js +139 -0
- package/dist/shell-shard/verbs/apps.d.ts +3 -0
- package/dist/shell-shard/verbs/apps.js +50 -0
- package/dist/shell-shard/verbs/clear.d.ts +2 -0
- package/dist/shell-shard/verbs/clear.js +7 -0
- package/dist/shell-shard/verbs/help.d.ts +2 -0
- package/dist/shell-shard/verbs/help.js +21 -0
- package/dist/shell-shard/verbs/history.d.ts +2 -0
- package/dist/shell-shard/verbs/history.js +20 -0
- package/dist/shell-shard/verbs/index.d.ts +2 -0
- package/dist/shell-shard/verbs/index.js +29 -0
- package/dist/shell-shard/verbs/session.d.ts +5 -0
- package/dist/shell-shard/verbs/session.js +65 -0
- package/dist/shell-shard/verbs/shards.d.ts +2 -0
- package/dist/shell-shard/verbs/shards.js +14 -0
- package/dist/shell-shard/verbs/views.d.ts +4 -0
- package/dist/shell-shard/verbs/views.js +90 -0
- package/dist/shell-shard/verbs/zones.d.ts +3 -0
- package/dist/shell-shard/verbs/zones.js +38 -0
- package/dist/shellRuntime.svelte.d.ts +27 -0
- package/dist/shellRuntime.svelte.js +27 -0
- package/dist/state/backends.d.ts +26 -0
- package/dist/state/backends.js +99 -0
- package/dist/state/manage.d.ts +14 -0
- package/dist/state/manage.js +40 -0
- package/dist/state/types.d.ts +55 -0
- package/dist/state/types.js +17 -0
- package/dist/state/zones.svelte.d.ts +53 -0
- package/dist/state/zones.svelte.js +141 -0
- package/dist/theme.d.ts +28 -0
- package/dist/theme.js +92 -0
- package/dist/tokens.css +102 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +60 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* Controller plugged in by a layout-aware parent to turn tab drags
|
|
4
|
+
* into layout mutations. The primitive itself is layout-agnostic:
|
|
5
|
+
* it just calls `onPointerDown` when a tab is grabbed, and asks the
|
|
6
|
+
* controller to hit-test the strip during a drag via `onStripHover`.
|
|
7
|
+
*/
|
|
8
|
+
export interface TabDragController {
|
|
9
|
+
onPointerDown(index: number, event: PointerEvent, element: HTMLElement): void;
|
|
10
|
+
onStripHover(
|
|
11
|
+
stripRect: DOMRect,
|
|
12
|
+
pointerX: number,
|
|
13
|
+
pointerY: number,
|
|
14
|
+
tabRects: DOMRect[],
|
|
15
|
+
): number | null;
|
|
16
|
+
onStripLeave(): void;
|
|
17
|
+
readonly isDragging: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pure helper: given an insert index and the tab button rects,
|
|
22
|
+
* compute the indicator's position in strip-local coordinates.
|
|
23
|
+
*/
|
|
24
|
+
export function computeIndicatorRect(
|
|
25
|
+
insertIndex: number,
|
|
26
|
+
tabEls: (HTMLButtonElement | undefined)[],
|
|
27
|
+
stripEl: HTMLDivElement | undefined,
|
|
28
|
+
): { left: number; top: number; height: number } | null {
|
|
29
|
+
if (!stripEl) return null;
|
|
30
|
+
const stripRect = stripEl.getBoundingClientRect();
|
|
31
|
+
const els = tabEls.filter((el): el is HTMLButtonElement => !!el);
|
|
32
|
+
if (els.length === 0) {
|
|
33
|
+
return { left: 4, top: 2, height: stripRect.height - 4 };
|
|
34
|
+
}
|
|
35
|
+
const clamped = Math.max(0, Math.min(insertIndex, els.length));
|
|
36
|
+
let leftViewport: number;
|
|
37
|
+
if (clamped === els.length) {
|
|
38
|
+
const last = els[els.length - 1].getBoundingClientRect();
|
|
39
|
+
leftViewport = last.right;
|
|
40
|
+
} else {
|
|
41
|
+
const at = els[clamped].getBoundingClientRect();
|
|
42
|
+
leftViewport = at.left;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
left: leftViewport - stripRect.left - 1,
|
|
46
|
+
top: 2,
|
|
47
|
+
height: stripRect.height - 4,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<script lang="ts">
|
|
53
|
+
/*
|
|
54
|
+
* TabbedPanel — a tab strip over a single active body.
|
|
55
|
+
*
|
|
56
|
+
* Scope: render a strip of tab labels, click to switch active tab,
|
|
57
|
+
* render every tab's body (hiding inactive ones via `display: none`).
|
|
58
|
+
* If a `dragController` is provided, tab pointerdown starts a drag
|
|
59
|
+
* and the strip becomes a drop zone with an insertion indicator.
|
|
60
|
+
*
|
|
61
|
+
* All body snippets are rendered concurrently so every tab's
|
|
62
|
+
* SlotContainer stays alive while the tab is inactive. The
|
|
63
|
+
* re-parenting contract relies on this — see slotHostPool.ts.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
import type { Snippet } from 'svelte';
|
|
67
|
+
|
|
68
|
+
let {
|
|
69
|
+
labels,
|
|
70
|
+
icons,
|
|
71
|
+
body,
|
|
72
|
+
activeTab,
|
|
73
|
+
onActiveChange,
|
|
74
|
+
dragController,
|
|
75
|
+
clickGuard,
|
|
76
|
+
closable,
|
|
77
|
+
dirty,
|
|
78
|
+
onClose,
|
|
79
|
+
}: {
|
|
80
|
+
labels: string[];
|
|
81
|
+
icons?: (string | undefined)[];
|
|
82
|
+
/** Snippet invoked once per tab with its index. */
|
|
83
|
+
body: Snippet<[number]>;
|
|
84
|
+
activeTab: number;
|
|
85
|
+
/** Called when the user picks a different tab. The parent is
|
|
86
|
+
* expected to write the new value back into whatever it is
|
|
87
|
+
* storing activeTab in. We use a callback rather than a
|
|
88
|
+
* $bindable prop because the parent's activeTab typically lives
|
|
89
|
+
* inside a larger $state object (a LayoutNode), and `bind:` on a
|
|
90
|
+
* sub-property trips Svelte 5's ownership warning. */
|
|
91
|
+
onActiveChange?: (index: number) => void;
|
|
92
|
+
dragController?: TabDragController;
|
|
93
|
+
/** Optional: called by the tab click handler; if it returns true,
|
|
94
|
+
* the click is ignored. Used to swallow the synthetic click that
|
|
95
|
+
* fires on the source tab after a drag commit. */
|
|
96
|
+
clickGuard?: () => boolean;
|
|
97
|
+
/** Per-tab closability. True if the tab can be closed. */
|
|
98
|
+
closable?: (boolean | undefined)[];
|
|
99
|
+
/** Per-tab dirty state. True if the tab has unsaved changes. */
|
|
100
|
+
dirty?: (boolean | undefined)[];
|
|
101
|
+
/** Called when the user clicks a tab's close button. */
|
|
102
|
+
onClose?: (index: number) => void;
|
|
103
|
+
} = $props();
|
|
104
|
+
|
|
105
|
+
function select(i: number) {
|
|
106
|
+
if (clickGuard?.()) return;
|
|
107
|
+
onActiveChange?.(i);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function handleClose(i: number, e: Event) {
|
|
111
|
+
e.stopPropagation(); // Don't also trigger tab selection.
|
|
112
|
+
onClose?.(i);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let stripEl: HTMLDivElement | undefined = $state();
|
|
116
|
+
const tabEls: (HTMLButtonElement | undefined)[] = $state([]);
|
|
117
|
+
let hoverInsertIndex: number | null = $state(null);
|
|
118
|
+
|
|
119
|
+
function onTabPointerDown(i: number, e: PointerEvent) {
|
|
120
|
+
if (!dragController) return;
|
|
121
|
+
const el = tabEls[i];
|
|
122
|
+
if (!el) return;
|
|
123
|
+
dragController.onPointerDown(i, e, el);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function onStripPointerMove(e: PointerEvent) {
|
|
127
|
+
if (!dragController || !dragController.isDragging || !stripEl) return;
|
|
128
|
+
const stripRect = stripEl.getBoundingClientRect();
|
|
129
|
+
const rects = tabEls
|
|
130
|
+
.filter((el): el is HTMLButtonElement => !!el)
|
|
131
|
+
.map((el) => el.getBoundingClientRect());
|
|
132
|
+
hoverInsertIndex = dragController.onStripHover(stripRect, e.clientX, e.clientY, rects);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function onStripPointerLeave() {
|
|
136
|
+
if (!dragController) return;
|
|
137
|
+
hoverInsertIndex = null;
|
|
138
|
+
dragController.onStripLeave();
|
|
139
|
+
}
|
|
140
|
+
</script>
|
|
141
|
+
|
|
142
|
+
<div class="tabbed-panel">
|
|
143
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
144
|
+
<div
|
|
145
|
+
class="tab-strip"
|
|
146
|
+
role="tablist"
|
|
147
|
+
tabindex="-1"
|
|
148
|
+
bind:this={stripEl}
|
|
149
|
+
onpointermove={onStripPointerMove}
|
|
150
|
+
onpointerleave={onStripPointerLeave}
|
|
151
|
+
>
|
|
152
|
+
{#each labels as label, i (i)}
|
|
153
|
+
<button
|
|
154
|
+
type="button"
|
|
155
|
+
class="tab"
|
|
156
|
+
class:active={activeTab === i}
|
|
157
|
+
role="tab"
|
|
158
|
+
aria-selected={activeTab === i}
|
|
159
|
+
bind:this={tabEls[i]}
|
|
160
|
+
onclick={() => select(i)}
|
|
161
|
+
onpointerdown={(e) => onTabPointerDown(i, e)}
|
|
162
|
+
onauxclick={(e) => { if (e.button === 1 && closable?.[i]) handleClose(i, e); }}
|
|
163
|
+
>
|
|
164
|
+
{#if dirty?.[i]}
|
|
165
|
+
<span class="tab-dirty" title="Unsaved changes"></span>
|
|
166
|
+
{/if}
|
|
167
|
+
{#if icons?.[i]}<span class="tab-icon">{icons[i]}</span>{/if}
|
|
168
|
+
<span class="tab-label">{label}</span>
|
|
169
|
+
{#if closable?.[i]}
|
|
170
|
+
<span
|
|
171
|
+
class="tab-close"
|
|
172
|
+
role="button"
|
|
173
|
+
tabindex="-1"
|
|
174
|
+
title="Close"
|
|
175
|
+
onclick={(e) => handleClose(i, e)}
|
|
176
|
+
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleClose(i, e); }}
|
|
177
|
+
>✕</span>
|
|
178
|
+
{/if}
|
|
179
|
+
</button>
|
|
180
|
+
{/each}
|
|
181
|
+
{#if hoverInsertIndex !== null && dragController?.isDragging}
|
|
182
|
+
{@const rect = computeIndicatorRect(hoverInsertIndex, tabEls, stripEl)}
|
|
183
|
+
{#if rect}
|
|
184
|
+
<div
|
|
185
|
+
class="drop-indicator"
|
|
186
|
+
style="left: {rect.left}px; height: {rect.height}px; top: {rect.top}px;"
|
|
187
|
+
></div>
|
|
188
|
+
{/if}
|
|
189
|
+
{/if}
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div class="tab-body" role="tabpanel">
|
|
193
|
+
{#each labels as _label, i (i)}
|
|
194
|
+
<div class="tab-body-pane" class:active={activeTab === i}>
|
|
195
|
+
{@render body(i)}
|
|
196
|
+
</div>
|
|
197
|
+
{/each}
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<style>
|
|
202
|
+
.tabbed-panel {
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
width: 100%;
|
|
206
|
+
height: 100%;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
min-height: 0;
|
|
209
|
+
background: var(--shell-grad-bg, var(--shell-bg));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.tab-strip {
|
|
213
|
+
position: relative;
|
|
214
|
+
flex: 0 0 auto;
|
|
215
|
+
display: flex;
|
|
216
|
+
gap: 1px;
|
|
217
|
+
background: var(--shell-grad-bg-sunken, var(--shell-bg-sunken));
|
|
218
|
+
border-bottom: 1px solid var(--shell-border);
|
|
219
|
+
padding: 0 var(--shell-pad-sm);
|
|
220
|
+
user-select: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.tab {
|
|
224
|
+
appearance: none;
|
|
225
|
+
background: transparent;
|
|
226
|
+
border: none;
|
|
227
|
+
color: var(--shell-fg-muted);
|
|
228
|
+
font: inherit;
|
|
229
|
+
font-size: 12px;
|
|
230
|
+
padding: var(--shell-pad-sm) var(--shell-pad-md);
|
|
231
|
+
margin-top: 2px;
|
|
232
|
+
display: inline-flex;
|
|
233
|
+
align-items: center;
|
|
234
|
+
gap: var(--shell-pad-sm);
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
border-top: 2px solid transparent;
|
|
237
|
+
border-radius: 2px 2px 0 0;
|
|
238
|
+
/* While dragging we still need pointerdown on tabs, but we want
|
|
239
|
+
the browser's native drag image suppressed — PointerEvent path
|
|
240
|
+
doesn't start an HTML5 drag, but preventing text selection here
|
|
241
|
+
avoids spurious selection rectangles during a drag. */
|
|
242
|
+
touch-action: none;
|
|
243
|
+
}
|
|
244
|
+
.tab:hover {
|
|
245
|
+
color: var(--shell-fg);
|
|
246
|
+
background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
|
|
247
|
+
}
|
|
248
|
+
.tab.active {
|
|
249
|
+
color: var(--shell-fg);
|
|
250
|
+
background: var(--shell-grad-bg, var(--shell-bg));
|
|
251
|
+
border-top-color: var(--shell-accent);
|
|
252
|
+
}
|
|
253
|
+
.tab-icon { font-size: 11px; }
|
|
254
|
+
.tab-label { white-space: nowrap; }
|
|
255
|
+
|
|
256
|
+
.tab-dirty {
|
|
257
|
+
width: 8px;
|
|
258
|
+
height: 8px;
|
|
259
|
+
border-radius: 50%;
|
|
260
|
+
background: var(--shell-accent);
|
|
261
|
+
flex-shrink: 0;
|
|
262
|
+
}
|
|
263
|
+
.tab-close {
|
|
264
|
+
display: inline-flex;
|
|
265
|
+
font-size: 10px;
|
|
266
|
+
line-height: 1;
|
|
267
|
+
padding: 2px;
|
|
268
|
+
border-radius: var(--shell-radius-sm);
|
|
269
|
+
color: var(--shell-fg-muted);
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
flex-shrink: 0;
|
|
272
|
+
margin-left: auto;
|
|
273
|
+
}
|
|
274
|
+
.tab-close:hover {
|
|
275
|
+
color: var(--shell-fg);
|
|
276
|
+
background: var(--shell-bg-sunken);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.drop-indicator {
|
|
280
|
+
position: absolute;
|
|
281
|
+
width: 2px;
|
|
282
|
+
background: var(--shell-accent);
|
|
283
|
+
box-shadow: 0 0 6px var(--shell-accent);
|
|
284
|
+
pointer-events: none;
|
|
285
|
+
border-radius: 1px;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.tab-body {
|
|
289
|
+
flex: 1 1 auto;
|
|
290
|
+
position: relative;
|
|
291
|
+
min-width: 0;
|
|
292
|
+
min-height: 0;
|
|
293
|
+
overflow: hidden;
|
|
294
|
+
}
|
|
295
|
+
.tab-body-pane {
|
|
296
|
+
position: absolute;
|
|
297
|
+
inset: 0;
|
|
298
|
+
min-width: 0;
|
|
299
|
+
min-height: 0;
|
|
300
|
+
display: none;
|
|
301
|
+
}
|
|
302
|
+
.tab-body-pane.active {
|
|
303
|
+
display: block;
|
|
304
|
+
}
|
|
305
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controller plugged in by a layout-aware parent to turn tab drags
|
|
3
|
+
* into layout mutations. The primitive itself is layout-agnostic:
|
|
4
|
+
* it just calls `onPointerDown` when a tab is grabbed, and asks the
|
|
5
|
+
* controller to hit-test the strip during a drag via `onStripHover`.
|
|
6
|
+
*/
|
|
7
|
+
export interface TabDragController {
|
|
8
|
+
onPointerDown(index: number, event: PointerEvent, element: HTMLElement): void;
|
|
9
|
+
onStripHover(stripRect: DOMRect, pointerX: number, pointerY: number, tabRects: DOMRect[]): number | null;
|
|
10
|
+
onStripLeave(): void;
|
|
11
|
+
readonly isDragging: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pure helper: given an insert index and the tab button rects,
|
|
15
|
+
* compute the indicator's position in strip-local coordinates.
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeIndicatorRect(insertIndex: number, tabEls: (HTMLButtonElement | undefined)[], stripEl: HTMLDivElement | undefined): {
|
|
18
|
+
left: number;
|
|
19
|
+
top: number;
|
|
20
|
+
height: number;
|
|
21
|
+
} | null;
|
|
22
|
+
import type { Snippet } from 'svelte';
|
|
23
|
+
type $$ComponentProps = {
|
|
24
|
+
labels: string[];
|
|
25
|
+
icons?: (string | undefined)[];
|
|
26
|
+
/** Snippet invoked once per tab with its index. */
|
|
27
|
+
body: Snippet<[number]>;
|
|
28
|
+
activeTab: number;
|
|
29
|
+
/** Called when the user picks a different tab. The parent is
|
|
30
|
+
* expected to write the new value back into whatever it is
|
|
31
|
+
* storing activeTab in. We use a callback rather than a
|
|
32
|
+
* $bindable prop because the parent's activeTab typically lives
|
|
33
|
+
* inside a larger $state object (a LayoutNode), and `bind:` on a
|
|
34
|
+
* sub-property trips Svelte 5's ownership warning. */
|
|
35
|
+
onActiveChange?: (index: number) => void;
|
|
36
|
+
dragController?: TabDragController;
|
|
37
|
+
/** Optional: called by the tab click handler; if it returns true,
|
|
38
|
+
* the click is ignored. Used to swallow the synthetic click that
|
|
39
|
+
* fires on the source tab after a drag commit. */
|
|
40
|
+
clickGuard?: () => boolean;
|
|
41
|
+
/** Per-tab closability. True if the tab can be closed. */
|
|
42
|
+
closable?: (boolean | undefined)[];
|
|
43
|
+
/** Per-tab dirty state. True if the tab has unsaved changes. */
|
|
44
|
+
dirty?: (boolean | undefined)[];
|
|
45
|
+
/** Called when the user clicks a tab's close button. */
|
|
46
|
+
onClose?: (index: number) => void;
|
|
47
|
+
};
|
|
48
|
+
declare const TabbedPanel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
49
|
+
type TabbedPanel = ReturnType<typeof TabbedPanel>;
|
|
50
|
+
export default TabbedPanel;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SH3 base component styles.
|
|
3
|
+
*
|
|
4
|
+
* Shared affordances that sit between tokens (raw values) and components
|
|
5
|
+
* (full UI). These apply to native elements and the .shell-base-* utility
|
|
6
|
+
* classes so shards and apps get a consistent look without duplicating
|
|
7
|
+
* button/input recipes in every component.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ── Buttons ─────────────────────────────────────────────────────────── */
|
|
11
|
+
|
|
12
|
+
button,
|
|
13
|
+
input[type="button"],
|
|
14
|
+
input[type="submit"],
|
|
15
|
+
input[type="reset"],
|
|
16
|
+
.shell-base-button {
|
|
17
|
+
padding: 6px 14px;
|
|
18
|
+
background: var(--shell-accent, #6ea8fe);
|
|
19
|
+
color: #fff;
|
|
20
|
+
border: none;
|
|
21
|
+
border-radius: var(--shell-radius);
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
font-family: inherit;
|
|
24
|
+
font-size: 0.875rem;
|
|
25
|
+
line-height: var(--shell-line);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
button:hover,
|
|
29
|
+
input[type="button"]:hover,
|
|
30
|
+
input[type="submit"]:hover,
|
|
31
|
+
input[type="reset"]:hover,
|
|
32
|
+
.shell-base-button:hover {
|
|
33
|
+
filter: brightness(1.12);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
button:active,
|
|
37
|
+
input[type="button"]:active,
|
|
38
|
+
input[type="submit"]:active,
|
|
39
|
+
input[type="reset"]:active,
|
|
40
|
+
.shell-base-button:active {
|
|
41
|
+
filter: brightness(0.92);
|
|
42
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry client -- fetches and merges registry indices, resolves
|
|
3
|
+
* packages, and downloads bundles with integrity verification.
|
|
4
|
+
*
|
|
5
|
+
* Typical usage:
|
|
6
|
+
* ```ts
|
|
7
|
+
* const packages = await fetchRegistries(['https://example.com/registry.json']);
|
|
8
|
+
* const pkg = packages.find(p => p.entry.id === 'my-shard');
|
|
9
|
+
* if (pkg) {
|
|
10
|
+
* const data = await fetchBundle(pkg.latest);
|
|
11
|
+
* const meta = buildPackageMeta(pkg, pkg.latest);
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import type { PackageEntry, PackageVersion, PackageMeta } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* A `PackageEntry` annotated with its source registry URL and resolved latest version.
|
|
18
|
+
*
|
|
19
|
+
* Returned by `fetchRegistries` so callers can display package cards and
|
|
20
|
+
* initiate installs without needing to re-parse the raw index document.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResolvedPackage {
|
|
23
|
+
/** The raw package entry from the registry index. */
|
|
24
|
+
entry: PackageEntry;
|
|
25
|
+
/**
|
|
26
|
+
* The latest version of this package.
|
|
27
|
+
* By convention this is `entry.versions[0]` — registries publish newest-first.
|
|
28
|
+
*/
|
|
29
|
+
latest: PackageVersion;
|
|
30
|
+
/** URL of the registry index this package was found in. */
|
|
31
|
+
sourceRegistry: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Fetch and merge multiple registry indices into a single package catalog.
|
|
35
|
+
*
|
|
36
|
+
* Registries are fetched in order. If the same package id appears in more
|
|
37
|
+
* than one registry, the first registry wins (left-to-right priority).
|
|
38
|
+
* Fetch or validation failures for individual registries are logged as
|
|
39
|
+
* warnings and skipped — the function always returns the packages that
|
|
40
|
+
* could be resolved successfully.
|
|
41
|
+
*
|
|
42
|
+
* @param urls - Ordered list of `registry.json` URLs to fetch.
|
|
43
|
+
* @returns Merged list of resolved packages, deduplicated by package id.
|
|
44
|
+
*/
|
|
45
|
+
export declare function fetchRegistries(urls: string[]): Promise<ResolvedPackage[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Download a bundle and verify its SRI integrity hash.
|
|
48
|
+
*
|
|
49
|
+
* Fetches `version.bundleUrl`, reads the response as an `ArrayBuffer`, then
|
|
50
|
+
* calls `verifyIntegrity` before returning. Throws on any network error,
|
|
51
|
+
* non-OK HTTP status, or integrity mismatch — the caller must not execute
|
|
52
|
+
* a bundle for which this function threw.
|
|
53
|
+
*
|
|
54
|
+
* If `bundleUrl` is relative (starts with `/`), it is resolved against
|
|
55
|
+
* `sourceRegistry` so cross-origin installs hit the correct server.
|
|
56
|
+
*
|
|
57
|
+
* @param version - The `PackageVersion` describing the bundle to download.
|
|
58
|
+
* @param sourceRegistry - The registry URL this package came from (used to resolve relative bundle paths).
|
|
59
|
+
* @returns Raw bundle bytes, verified against `version.integrity`.
|
|
60
|
+
* @throws If the fetch fails, the server returns a non-OK status, or the integrity check fails.
|
|
61
|
+
*/
|
|
62
|
+
export declare function fetchBundle(version: PackageVersion, sourceRegistry?: string): Promise<ArrayBuffer>;
|
|
63
|
+
/**
|
|
64
|
+
* Build a `PackageMeta` record from a resolved package and a chosen version.
|
|
65
|
+
*
|
|
66
|
+
* Combines identity fields from the `PackageEntry` with provenance and
|
|
67
|
+
* integrity fields from the selected `PackageVersion`. The result is passed
|
|
68
|
+
* to the framework install API alongside the raw bundle bytes.
|
|
69
|
+
*
|
|
70
|
+
* @param resolved - The resolved package, as returned by `fetchRegistries`.
|
|
71
|
+
* @param version - The specific version to install (e.g. `resolved.latest`).
|
|
72
|
+
* @returns A `PackageMeta` ready to be handed to the install API.
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildPackageMeta(resolved: ResolvedPackage, version: PackageVersion): PackageMeta;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry client -- fetches and merges registry indices, resolves
|
|
3
|
+
* packages, and downloads bundles with integrity verification.
|
|
4
|
+
*
|
|
5
|
+
* Typical usage:
|
|
6
|
+
* ```ts
|
|
7
|
+
* const packages = await fetchRegistries(['https://example.com/registry.json']);
|
|
8
|
+
* const pkg = packages.find(p => p.entry.id === 'my-shard');
|
|
9
|
+
* if (pkg) {
|
|
10
|
+
* const data = await fetchBundle(pkg.latest);
|
|
11
|
+
* const meta = buildPackageMeta(pkg, pkg.latest);
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { validateRegistryIndex } from './schema.js';
|
|
16
|
+
import { verifyIntegrity } from './integrity.js';
|
|
17
|
+
/**
|
|
18
|
+
* Fetch and merge multiple registry indices into a single package catalog.
|
|
19
|
+
*
|
|
20
|
+
* Registries are fetched in order. If the same package id appears in more
|
|
21
|
+
* than one registry, the first registry wins (left-to-right priority).
|
|
22
|
+
* Fetch or validation failures for individual registries are logged as
|
|
23
|
+
* warnings and skipped — the function always returns the packages that
|
|
24
|
+
* could be resolved successfully.
|
|
25
|
+
*
|
|
26
|
+
* @param urls - Ordered list of `registry.json` URLs to fetch.
|
|
27
|
+
* @returns Merged list of resolved packages, deduplicated by package id.
|
|
28
|
+
*/
|
|
29
|
+
export async function fetchRegistries(urls) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const results = [];
|
|
32
|
+
for (const url of urls) {
|
|
33
|
+
let raw;
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(url);
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
console.warn(`[sh3] Registry fetch failed for ${url}: HTTP ${response.status}`);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
raw = await response.json();
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.warn(`[sh3] Registry ${url}: ${err instanceof Error ? err.message : String(err)}`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
let index;
|
|
47
|
+
try {
|
|
48
|
+
index = validateRegistryIndex(raw);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.warn(`[sh3] Registry ${url} failed validation: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const entry of index.packages) {
|
|
55
|
+
if (seen.has(entry.id))
|
|
56
|
+
continue;
|
|
57
|
+
seen.add(entry.id);
|
|
58
|
+
results.push({
|
|
59
|
+
entry,
|
|
60
|
+
latest: entry.versions[0],
|
|
61
|
+
sourceRegistry: url,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return results;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Download a bundle and verify its SRI integrity hash.
|
|
69
|
+
*
|
|
70
|
+
* Fetches `version.bundleUrl`, reads the response as an `ArrayBuffer`, then
|
|
71
|
+
* calls `verifyIntegrity` before returning. Throws on any network error,
|
|
72
|
+
* non-OK HTTP status, or integrity mismatch — the caller must not execute
|
|
73
|
+
* a bundle for which this function threw.
|
|
74
|
+
*
|
|
75
|
+
* If `bundleUrl` is relative (starts with `/`), it is resolved against
|
|
76
|
+
* `sourceRegistry` so cross-origin installs hit the correct server.
|
|
77
|
+
*
|
|
78
|
+
* @param version - The `PackageVersion` describing the bundle to download.
|
|
79
|
+
* @param sourceRegistry - The registry URL this package came from (used to resolve relative bundle paths).
|
|
80
|
+
* @returns Raw bundle bytes, verified against `version.integrity`.
|
|
81
|
+
* @throws If the fetch fails, the server returns a non-OK status, or the integrity check fails.
|
|
82
|
+
*/
|
|
83
|
+
export async function fetchBundle(version, sourceRegistry) {
|
|
84
|
+
let url = version.bundleUrl;
|
|
85
|
+
if (sourceRegistry && !/^https?:\/\//i.test(url)) {
|
|
86
|
+
url = new URL(url, sourceRegistry).href;
|
|
87
|
+
}
|
|
88
|
+
const response = await fetch(url);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new Error(`Bundle fetch failed: HTTP ${response.status} ${response.statusText} from ${url}`);
|
|
91
|
+
}
|
|
92
|
+
const data = await response.arrayBuffer();
|
|
93
|
+
await verifyIntegrity(data, version.integrity);
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build a `PackageMeta` record from a resolved package and a chosen version.
|
|
98
|
+
*
|
|
99
|
+
* Combines identity fields from the `PackageEntry` with provenance and
|
|
100
|
+
* integrity fields from the selected `PackageVersion`. The result is passed
|
|
101
|
+
* to the framework install API alongside the raw bundle bytes.
|
|
102
|
+
*
|
|
103
|
+
* @param resolved - The resolved package, as returned by `fetchRegistries`.
|
|
104
|
+
* @param version - The specific version to install (e.g. `resolved.latest`).
|
|
105
|
+
* @returns A `PackageMeta` ready to be handed to the install API.
|
|
106
|
+
*/
|
|
107
|
+
export function buildPackageMeta(resolved, version) {
|
|
108
|
+
return {
|
|
109
|
+
id: resolved.entry.id,
|
|
110
|
+
type: resolved.entry.type,
|
|
111
|
+
version: version.version,
|
|
112
|
+
contractVersion: version.contractVersion,
|
|
113
|
+
sourceRegistry: resolved.sourceRegistry,
|
|
114
|
+
integrity: version.integrity,
|
|
115
|
+
requires: version.requires,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry module barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the public surface of the registry subsystem: protocol types,
|
|
5
|
+
* schema validation, integrity verification, client functions, and the
|
|
6
|
+
* install API.
|
|
7
|
+
*/
|
|
8
|
+
export type { RegistryIndex, PackageEntry, PackageVersion, RequiredDependency, InstalledPackage, InstallResult, PackageMeta, } from './types';
|
|
9
|
+
export { RegistryValidationError, validateRegistryIndex } from './schema';
|
|
10
|
+
export { verifyIntegrity, computeIntegrity } from './integrity';
|
|
11
|
+
export type { ResolvedPackage } from './client';
|
|
12
|
+
export { fetchRegistries, fetchBundle, buildPackageMeta } from './client';
|
|
13
|
+
export { installPackage, uninstallPackage, listInstalledPackages, loadInstalledPackages, } from './installer';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry module barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the public surface of the registry subsystem: protocol types,
|
|
5
|
+
* schema validation, integrity verification, client functions, and the
|
|
6
|
+
* install API.
|
|
7
|
+
*/
|
|
8
|
+
// Schema validation.
|
|
9
|
+
export { RegistryValidationError, validateRegistryIndex } from './schema';
|
|
10
|
+
// Integrity verification.
|
|
11
|
+
export { verifyIntegrity, computeIntegrity } from './integrity';
|
|
12
|
+
export { fetchRegistries, fetchBundle, buildPackageMeta } from './client';
|
|
13
|
+
// Install API.
|
|
14
|
+
export { installPackage, uninstallPackage, listInstalledPackages, loadInstalledPackages, } from './installer';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package installer -- coordinates storing, loading, and registering packages.
|
|
3
|
+
*
|
|
4
|
+
* This is the bridge between the store shard (which fetches and verifies
|
|
5
|
+
* bundles) and the framework (which registers shards/apps). The install API
|
|
6
|
+
* is host-only; shards and apps must not import from here.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. `installPackage(bundle, meta)` -- load module from bytes, verify
|
|
10
|
+
* declared type matches actual type, persist to IndexedDB, register
|
|
11
|
+
* with framework.
|
|
12
|
+
* 2. `uninstallPackage(id)` -- deactivate if active, remove from storage.
|
|
13
|
+
* 3. `loadInstalledPackages()` -- called at boot, re-loads all installed
|
|
14
|
+
* packages from IndexedDB and registers them.
|
|
15
|
+
*/
|
|
16
|
+
import type { InstalledPackage, InstallResult, PackageMeta } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* Install a package from raw bundle bytes and metadata.
|
|
19
|
+
*
|
|
20
|
+
* Loads the ESM module, verifies the declared type matches the actual module
|
|
21
|
+
* shape, persists to IndexedDB, and registers with the framework. If
|
|
22
|
+
* registration fails (e.g. duplicate id from a shard that was already
|
|
23
|
+
* glob-discovered), the package is still persisted but `hotLoaded` is false.
|
|
24
|
+
*
|
|
25
|
+
* @param bundle - Raw verified ESM bundle bytes.
|
|
26
|
+
* @param meta - Provenance metadata for the install record.
|
|
27
|
+
* @returns Result object indicating success/failure and hot-load status.
|
|
28
|
+
*/
|
|
29
|
+
export declare function installPackage(bundle: ArrayBuffer, meta: PackageMeta): Promise<InstallResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Uninstall a package by id.
|
|
32
|
+
*
|
|
33
|
+
* If the package is a shard and currently active, deactivates it first.
|
|
34
|
+
* Removes both the bundle and metadata from IndexedDB.
|
|
35
|
+
*
|
|
36
|
+
* @param id - The package id to uninstall.
|
|
37
|
+
*/
|
|
38
|
+
export declare function uninstallPackage(id: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* List all installed packages.
|
|
41
|
+
*
|
|
42
|
+
* Delegates directly to the storage layer. Returns metadata records only,
|
|
43
|
+
* not the bundle bytes.
|
|
44
|
+
*/
|
|
45
|
+
export declare function listInstalledPackages(): Promise<InstalledPackage[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Load all installed packages from IndexedDB and register them.
|
|
48
|
+
*
|
|
49
|
+
* Called once at boot by `bootstrap()`, before any glob-discovered shards
|
|
50
|
+
* or the shell shard are registered. Individual package failures are logged
|
|
51
|
+
* as warnings but do not prevent the shell from booting.
|
|
52
|
+
*/
|
|
53
|
+
export declare function loadInstalledPackages(): Promise<void>;
|