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,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation for registry index JSON.
|
|
3
|
+
*
|
|
4
|
+
* No external schema library — plain runtime checks. The registry index
|
|
5
|
+
* is fetched from untrusted URLs so all fields are validated before any
|
|
6
|
+
* typed access occurs. Validation errors carry a JSON-path string so the
|
|
7
|
+
* caller can surface actionable diagnostics in the store UI.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* const raw = await response.json();
|
|
12
|
+
* const index = validateRegistryIndex(raw); // throws RegistryValidationError on bad input
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when a registry index document fails validation.
|
|
17
|
+
*
|
|
18
|
+
* The `path` property is a JSON-path string pointing to the field that
|
|
19
|
+
* caused the failure (e.g. `"$.packages[2].versions[0].integrity"`).
|
|
20
|
+
* Consumers may display this directly in diagnostic/error UI.
|
|
21
|
+
*/
|
|
22
|
+
export class RegistryValidationError extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* @param path - JSON-path string of the failing field.
|
|
25
|
+
* @param message - Human-readable description of why validation failed.
|
|
26
|
+
*/
|
|
27
|
+
constructor(path, message) {
|
|
28
|
+
super(`Registry validation error at ${path}: ${message}`);
|
|
29
|
+
this.name = 'RegistryValidationError';
|
|
30
|
+
this.path = path;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate an unknown value as a `RegistryIndex`.
|
|
35
|
+
*
|
|
36
|
+
* Performs a full deep validation of all required fields and their types.
|
|
37
|
+
* Returns a correctly typed `RegistryIndex` on success.
|
|
38
|
+
* Throws `RegistryValidationError` on the first validation failure.
|
|
39
|
+
*
|
|
40
|
+
* Call this immediately after `response.json()` before touching any field.
|
|
41
|
+
*
|
|
42
|
+
* @param data - The raw parsed JSON value from a registry fetch.
|
|
43
|
+
* @returns A fully validated `RegistryIndex`.
|
|
44
|
+
* @throws `RegistryValidationError` if any field is missing or has the wrong type.
|
|
45
|
+
*/
|
|
46
|
+
export function validateRegistryIndex(data) {
|
|
47
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
48
|
+
throw new RegistryValidationError('$', 'expected an object');
|
|
49
|
+
}
|
|
50
|
+
const obj = data;
|
|
51
|
+
if (obj['version'] !== 1) {
|
|
52
|
+
throw new RegistryValidationError('$.version', `expected 1, got ${JSON.stringify(obj['version'])}`);
|
|
53
|
+
}
|
|
54
|
+
if (!Array.isArray(obj['packages'])) {
|
|
55
|
+
throw new RegistryValidationError('$.packages', 'expected an array');
|
|
56
|
+
}
|
|
57
|
+
const packages = obj['packages'].map((p, i) => validatePackageEntry(p, `$.packages[${i}]`));
|
|
58
|
+
return { version: 1, packages };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate a single package entry object.
|
|
62
|
+
*
|
|
63
|
+
* @param data - Raw value from the `packages` array.
|
|
64
|
+
* @param path - JSON-path prefix used in error messages.
|
|
65
|
+
* @returns Validated `PackageEntry`.
|
|
66
|
+
* @throws `RegistryValidationError` on any field failure.
|
|
67
|
+
*/
|
|
68
|
+
function validatePackageEntry(data, path) {
|
|
69
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
70
|
+
throw new RegistryValidationError(path, 'expected an object');
|
|
71
|
+
}
|
|
72
|
+
const obj = data;
|
|
73
|
+
requireString(obj, 'id', path);
|
|
74
|
+
requireOneOf(obj, 'type', ['shard', 'app', 'combo'], path);
|
|
75
|
+
requireString(obj, 'label', path);
|
|
76
|
+
requireString(obj, 'description', path);
|
|
77
|
+
// author: { name: string }
|
|
78
|
+
const authorPath = `${path}.author`;
|
|
79
|
+
if (!obj['author'] || typeof obj['author'] !== 'object' || Array.isArray(obj['author'])) {
|
|
80
|
+
throw new RegistryValidationError(authorPath, 'expected an object');
|
|
81
|
+
}
|
|
82
|
+
const author = obj['author'];
|
|
83
|
+
if (typeof author['name'] !== 'string' || author['name'].length === 0) {
|
|
84
|
+
throw new RegistryValidationError(`${authorPath}.name`, 'expected a non-empty string');
|
|
85
|
+
}
|
|
86
|
+
// versions: non-empty array
|
|
87
|
+
if (!Array.isArray(obj['versions']) || obj['versions'].length === 0) {
|
|
88
|
+
throw new RegistryValidationError(`${path}.versions`, 'expected a non-empty array');
|
|
89
|
+
}
|
|
90
|
+
const versions = obj['versions'].map((v, i) => validatePackageVersion(v, `${path}.versions[${i}]`));
|
|
91
|
+
return {
|
|
92
|
+
id: obj['id'],
|
|
93
|
+
type: obj['type'],
|
|
94
|
+
label: obj['label'],
|
|
95
|
+
description: obj['description'],
|
|
96
|
+
author: { name: author['name'] },
|
|
97
|
+
icon: typeof obj['icon'] === 'string' ? obj['icon'] : undefined,
|
|
98
|
+
versions,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validate a single package version object.
|
|
103
|
+
*
|
|
104
|
+
* @param data - Raw value from a `versions` array.
|
|
105
|
+
* @param path - JSON-path prefix used in error messages.
|
|
106
|
+
* @returns Validated `PackageVersion`.
|
|
107
|
+
* @throws `RegistryValidationError` on any field failure.
|
|
108
|
+
*/
|
|
109
|
+
function validatePackageVersion(data, path) {
|
|
110
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
111
|
+
throw new RegistryValidationError(path, 'expected an object');
|
|
112
|
+
}
|
|
113
|
+
const obj = data;
|
|
114
|
+
requireString(obj, 'version', path);
|
|
115
|
+
requireString(obj, 'contractVersion', path);
|
|
116
|
+
requireString(obj, 'bundleUrl', path);
|
|
117
|
+
requireString(obj, 'integrity', path);
|
|
118
|
+
// Optional server bundle URL
|
|
119
|
+
if ('serverBundleUrl' in obj && obj.serverBundleUrl !== undefined) {
|
|
120
|
+
requireString(obj, 'serverBundleUrl', path);
|
|
121
|
+
}
|
|
122
|
+
let requires;
|
|
123
|
+
if (obj['requires'] !== undefined) {
|
|
124
|
+
if (!Array.isArray(obj['requires'])) {
|
|
125
|
+
throw new RegistryValidationError(`${path}.requires`, 'expected an array');
|
|
126
|
+
}
|
|
127
|
+
requires = obj['requires'].map((r, i) => validateRequiredDependency(r, `${path}.requires[${i}]`));
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
version: obj['version'],
|
|
131
|
+
contractVersion: obj['contractVersion'],
|
|
132
|
+
bundleUrl: obj['bundleUrl'],
|
|
133
|
+
integrity: obj['integrity'],
|
|
134
|
+
serverBundleUrl: typeof obj['serverBundleUrl'] === 'string' ? obj['serverBundleUrl'] : undefined,
|
|
135
|
+
requires,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Validate a single dependency entry in a `requires` array.
|
|
140
|
+
*
|
|
141
|
+
* @param data - Raw value from a `requires` array.
|
|
142
|
+
* @param path - JSON-path prefix used in error messages.
|
|
143
|
+
* @returns Validated `RequiredDependency`.
|
|
144
|
+
* @throws `RegistryValidationError` on any field failure.
|
|
145
|
+
*/
|
|
146
|
+
function validateRequiredDependency(data, path) {
|
|
147
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
148
|
+
throw new RegistryValidationError(path, 'expected an object');
|
|
149
|
+
}
|
|
150
|
+
const obj = data;
|
|
151
|
+
requireString(obj, 'id', path);
|
|
152
|
+
requireString(obj, 'versionRange', path);
|
|
153
|
+
return {
|
|
154
|
+
id: obj['id'],
|
|
155
|
+
versionRange: obj['versionRange'],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Assert that `obj[field]` is a non-empty string.
|
|
160
|
+
*
|
|
161
|
+
* @param obj - Parent object being validated.
|
|
162
|
+
* @param field - Field name to check.
|
|
163
|
+
* @param path - JSON-path of the parent object (field name is appended on error).
|
|
164
|
+
* @throws `RegistryValidationError` if the field is missing, not a string, or empty.
|
|
165
|
+
*/
|
|
166
|
+
function requireString(obj, field, path) {
|
|
167
|
+
const value = obj[field];
|
|
168
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
169
|
+
throw new RegistryValidationError(`${path}.${field}`, 'expected a non-empty string');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Assert that `obj[field]` is one of the allowed string values.
|
|
174
|
+
*
|
|
175
|
+
* @param obj - Parent object being validated.
|
|
176
|
+
* @param field - Field name to check.
|
|
177
|
+
* @param values - Allowed values.
|
|
178
|
+
* @param path - JSON-path of the parent object (field name is appended on error).
|
|
179
|
+
* @throws `RegistryValidationError` if the field value is not in `values`.
|
|
180
|
+
*/
|
|
181
|
+
function requireOneOf(obj, field, values, path) {
|
|
182
|
+
if (!values.includes(obj[field])) {
|
|
183
|
+
throw new RegistryValidationError(`${path}.${field}`, `expected one of: ${values.join(', ')}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package storage -- persists installed bundles and metadata.
|
|
3
|
+
*
|
|
4
|
+
* Uses IndexedDB, available in all target environments (browser, Tauri
|
|
5
|
+
* WebView, Android WebView). Two object stores:
|
|
6
|
+
* - "bundles" -- raw ArrayBuffer keyed by package id
|
|
7
|
+
* - "meta" -- InstalledPackage records keyed by package id
|
|
8
|
+
*
|
|
9
|
+
* Designed to be swappable: a Tauri target could later substitute a
|
|
10
|
+
* filesystem-backed implementation behind the same interface.
|
|
11
|
+
*/
|
|
12
|
+
import type { InstalledPackage } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Persist a package bundle and its metadata.
|
|
15
|
+
* Overwrites any existing record for the same `id`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function savePackage(id: string, bundle: ArrayBuffer, meta: InstalledPackage): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Load the raw bundle bytes for an installed package.
|
|
20
|
+
* Returns `null` if no bundle is stored for `id`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadBundle(id: string): Promise<ArrayBuffer | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Load the metadata record for an installed package.
|
|
25
|
+
* Returns `null` if no metadata is stored for `id`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadMeta(id: string): Promise<InstalledPackage | null>;
|
|
28
|
+
/**
|
|
29
|
+
* List metadata for all installed packages.
|
|
30
|
+
* Returns an empty array when nothing has been installed yet.
|
|
31
|
+
*/
|
|
32
|
+
export declare function listInstalled(): Promise<InstalledPackage[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Remove a package's bundle and metadata from storage.
|
|
35
|
+
* No-ops silently if the package was not installed.
|
|
36
|
+
*/
|
|
37
|
+
export declare function removePackage(id: string): Promise<void>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package storage -- persists installed bundles and metadata.
|
|
3
|
+
*
|
|
4
|
+
* Uses IndexedDB, available in all target environments (browser, Tauri
|
|
5
|
+
* WebView, Android WebView). Two object stores:
|
|
6
|
+
* - "bundles" -- raw ArrayBuffer keyed by package id
|
|
7
|
+
* - "meta" -- InstalledPackage records keyed by package id
|
|
8
|
+
*
|
|
9
|
+
* Designed to be swappable: a Tauri target could later substitute a
|
|
10
|
+
* filesystem-backed implementation behind the same interface.
|
|
11
|
+
*/
|
|
12
|
+
const DB_NAME = 'sh3-packages';
|
|
13
|
+
const DB_VERSION = 1;
|
|
14
|
+
const BUNDLES_STORE = 'bundles';
|
|
15
|
+
const META_STORE = 'meta';
|
|
16
|
+
/**
|
|
17
|
+
* Opens (or creates) the sh3-packages IndexedDB database.
|
|
18
|
+
* Called internally before every storage operation.
|
|
19
|
+
*/
|
|
20
|
+
function openDb() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
23
|
+
request.onupgradeneeded = () => {
|
|
24
|
+
const db = request.result;
|
|
25
|
+
if (!db.objectStoreNames.contains(BUNDLES_STORE)) {
|
|
26
|
+
db.createObjectStore(BUNDLES_STORE);
|
|
27
|
+
}
|
|
28
|
+
if (!db.objectStoreNames.contains(META_STORE)) {
|
|
29
|
+
db.createObjectStore(META_STORE);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
request.onsuccess = () => resolve(request.result);
|
|
33
|
+
request.onerror = () => reject(request.error);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Wraps a single IDBObjectStore operation in a promise.
|
|
38
|
+
* Opens a transaction on `store`, calls `fn` with the object store, and
|
|
39
|
+
* resolves with the request result or rejects on error.
|
|
40
|
+
*/
|
|
41
|
+
function tx(db, store, mode, fn) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const transaction = db.transaction(store, mode);
|
|
44
|
+
const objectStore = transaction.objectStore(store);
|
|
45
|
+
const request = fn(objectStore);
|
|
46
|
+
request.onsuccess = () => resolve(request.result);
|
|
47
|
+
request.onerror = () => reject(request.error);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Persist a package bundle and its metadata.
|
|
52
|
+
* Overwrites any existing record for the same `id`.
|
|
53
|
+
*/
|
|
54
|
+
export async function savePackage(id, bundle, meta) {
|
|
55
|
+
const db = await openDb();
|
|
56
|
+
await tx(db, BUNDLES_STORE, 'readwrite', (s) => s.put(bundle, id));
|
|
57
|
+
await tx(db, META_STORE, 'readwrite', (s) => s.put(meta, id));
|
|
58
|
+
db.close();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Load the raw bundle bytes for an installed package.
|
|
62
|
+
* Returns `null` if no bundle is stored for `id`.
|
|
63
|
+
*/
|
|
64
|
+
export async function loadBundle(id) {
|
|
65
|
+
const db = await openDb();
|
|
66
|
+
const result = await tx(db, BUNDLES_STORE, 'readonly', (s) => s.get(id));
|
|
67
|
+
db.close();
|
|
68
|
+
return result !== null && result !== void 0 ? result : null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Load the metadata record for an installed package.
|
|
72
|
+
* Returns `null` if no metadata is stored for `id`.
|
|
73
|
+
*/
|
|
74
|
+
export async function loadMeta(id) {
|
|
75
|
+
var _a;
|
|
76
|
+
const db = await openDb();
|
|
77
|
+
const result = await tx(db, META_STORE, 'readonly', (s) => s.get(id));
|
|
78
|
+
db.close();
|
|
79
|
+
return (_a = result) !== null && _a !== void 0 ? _a : null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* List metadata for all installed packages.
|
|
83
|
+
* Returns an empty array when nothing has been installed yet.
|
|
84
|
+
*/
|
|
85
|
+
export async function listInstalled() {
|
|
86
|
+
var _a;
|
|
87
|
+
const db = await openDb();
|
|
88
|
+
const result = await tx(db, META_STORE, 'readonly', (s) => s.getAll());
|
|
89
|
+
db.close();
|
|
90
|
+
return (_a = result) !== null && _a !== void 0 ? _a : [];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Remove a package's bundle and metadata from storage.
|
|
94
|
+
* No-ops silently if the package was not installed.
|
|
95
|
+
*/
|
|
96
|
+
export async function removePackage(id) {
|
|
97
|
+
const db = await openDb();
|
|
98
|
+
await tx(db, BUNDLES_STORE, 'readwrite', (s) => s.delete(id));
|
|
99
|
+
await tx(db, META_STORE, 'readwrite', (s) => s.delete(id));
|
|
100
|
+
db.close();
|
|
101
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry protocol types.
|
|
3
|
+
*
|
|
4
|
+
* A registry is any static HTTP endpoint serving a `registry.json` index
|
|
5
|
+
* and pre-built ESM bundle files. These types define the wire format for
|
|
6
|
+
* the index document and the local metadata stored after installation.
|
|
7
|
+
*
|
|
8
|
+
* Registry flow:
|
|
9
|
+
* 1. Client fetches `<registryUrl>/registry.json` → `RegistryIndex`
|
|
10
|
+
* 2. User picks a `PackageEntry` and a `PackageVersion`
|
|
11
|
+
* 3. Client downloads `bundleUrl`, verifies `integrity`, hot-loads the ESM bundle
|
|
12
|
+
* 4. On success the client writes an `InstalledPackage` record to local storage
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Top-level registry index document.
|
|
16
|
+
*
|
|
17
|
+
* Served as static JSON at the root of any SH3 registry endpoint.
|
|
18
|
+
* The `version` field gates forward compatibility — clients that do not
|
|
19
|
+
* recognise the version must refuse to load the index.
|
|
20
|
+
*/
|
|
21
|
+
export interface RegistryIndex {
|
|
22
|
+
/**
|
|
23
|
+
* Protocol version discriminator. Currently always `1`.
|
|
24
|
+
* Future breaking changes increment this number.
|
|
25
|
+
*/
|
|
26
|
+
version: 1;
|
|
27
|
+
/**
|
|
28
|
+
* All packages published to this registry.
|
|
29
|
+
* Order is not defined by the protocol; store UI should sort as needed.
|
|
30
|
+
*/
|
|
31
|
+
packages: PackageEntry[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A single package (shard or app) listed in the registry.
|
|
35
|
+
*
|
|
36
|
+
* A package has a stable `id` and may publish multiple `versions`. The
|
|
37
|
+
* store UI displays `label`, `description`, `author`, and optional `icon`.
|
|
38
|
+
*/
|
|
39
|
+
export interface PackageEntry {
|
|
40
|
+
/**
|
|
41
|
+
* Unique, stable identifier for this package.
|
|
42
|
+
* Convention: `@author/package-name` or `plain-name`.
|
|
43
|
+
* Must not change across versions.
|
|
44
|
+
*/
|
|
45
|
+
id: string;
|
|
46
|
+
/**
|
|
47
|
+
* Whether this package is a shard (module that contributes views/commands)
|
|
48
|
+
* or an app (composition document that wires shards into a layout).
|
|
49
|
+
*/
|
|
50
|
+
type: 'shard' | 'app' | 'combo';
|
|
51
|
+
/**
|
|
52
|
+
* Human-readable display name shown in the store UI.
|
|
53
|
+
* Should be short (under 40 characters).
|
|
54
|
+
*/
|
|
55
|
+
label: string;
|
|
56
|
+
/**
|
|
57
|
+
* Short description shown in the store UI.
|
|
58
|
+
* Should be one or two sentences, plain text.
|
|
59
|
+
*/
|
|
60
|
+
description: string;
|
|
61
|
+
/**
|
|
62
|
+
* Author information. Extended fields (email, url) may be added
|
|
63
|
+
* in future protocol versions.
|
|
64
|
+
*/
|
|
65
|
+
author: {
|
|
66
|
+
/** Human-readable author name. */
|
|
67
|
+
name: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Optional URL to a square icon image (PNG or SVG recommended).
|
|
71
|
+
* Displayed in the store package card. If omitted the store shows
|
|
72
|
+
* a generic placeholder.
|
|
73
|
+
*/
|
|
74
|
+
icon?: string;
|
|
75
|
+
/**
|
|
76
|
+
* All published versions of this package, newest-first by convention.
|
|
77
|
+
* Must contain at least one entry.
|
|
78
|
+
*/
|
|
79
|
+
versions: PackageVersion[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A specific published version of a package.
|
|
83
|
+
*
|
|
84
|
+
* Each version ships a self-contained pre-built ESM bundle at `bundleUrl`.
|
|
85
|
+
* The `integrity` field is an SRI hash (sha384 recommended) used to verify
|
|
86
|
+
* the download before execution.
|
|
87
|
+
*/
|
|
88
|
+
export interface PackageVersion {
|
|
89
|
+
/**
|
|
90
|
+
* Semver version string (e.g. `"1.2.3"`).
|
|
91
|
+
* Must be unique within a `PackageEntry.versions` array.
|
|
92
|
+
*/
|
|
93
|
+
version: string;
|
|
94
|
+
/**
|
|
95
|
+
* The `sh3-core` contract version this bundle was built against
|
|
96
|
+
* (e.g. `"0.1.0"`). The install API checks this against the running
|
|
97
|
+
* framework version and may warn or block on mismatch.
|
|
98
|
+
*/
|
|
99
|
+
contractVersion: string;
|
|
100
|
+
/**
|
|
101
|
+
* Absolute or registry-relative URL to the pre-built ESM bundle.
|
|
102
|
+
* The client fetches this URL and verifies the download against `integrity`
|
|
103
|
+
* before executing.
|
|
104
|
+
*/
|
|
105
|
+
bundleUrl: string;
|
|
106
|
+
/**
|
|
107
|
+
* SRI integrity hash for the bundle file.
|
|
108
|
+
* Format: `"<algorithm>-<base64digest>"` (e.g. `"sha384-abc123..."`).
|
|
109
|
+
* Algorithms: sha256, sha384 (recommended), sha512.
|
|
110
|
+
* See: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
|
111
|
+
*/
|
|
112
|
+
integrity: string;
|
|
113
|
+
/**
|
|
114
|
+
* Optional URL to the server-side bundle for shards that have a backend
|
|
115
|
+
* component. Same resolution rules as `bundleUrl` (absolute or registry-
|
|
116
|
+
* relative). Only present when the shard declares `serverBundle` in its
|
|
117
|
+
* manifest.
|
|
118
|
+
*/
|
|
119
|
+
serverBundleUrl?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Other shards that must be installed and active before this package
|
|
122
|
+
* can be loaded. Optional — omit if the package has no dependencies.
|
|
123
|
+
*
|
|
124
|
+
* For apps: lists the shards the app's layout references.
|
|
125
|
+
* For shards: lists shards this shard imports from at runtime.
|
|
126
|
+
* Version ranges follow semver (e.g. `"^2.0.0"`, `">=1.0.0 <2.0.0"`).
|
|
127
|
+
*/
|
|
128
|
+
requires?: RequiredDependency[];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A declared dependency on another shard with a semver version range.
|
|
132
|
+
*
|
|
133
|
+
* The install API resolves and validates all dependencies before loading
|
|
134
|
+
* the bundle, refusing to install if a dependency is missing or incompatible.
|
|
135
|
+
*/
|
|
136
|
+
export interface RequiredDependency {
|
|
137
|
+
/**
|
|
138
|
+
* The shard id that must be present.
|
|
139
|
+
* Must match a `PackageEntry.id` in some available registry.
|
|
140
|
+
*/
|
|
141
|
+
id: string;
|
|
142
|
+
/**
|
|
143
|
+
* Semver range the installed shard version must satisfy.
|
|
144
|
+
* Examples: `"^1.0.0"`, `">=2.0.0 <3.0.0"`, `"1.2.x"`.
|
|
145
|
+
* Uses standard semver range notation.
|
|
146
|
+
*/
|
|
147
|
+
versionRange: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Metadata for an installed package, persisted in local storage.
|
|
151
|
+
*
|
|
152
|
+
* Written by the install API on successful installation. Used to show
|
|
153
|
+
* installed/update-available status in the store UI, and to reconstruct
|
|
154
|
+
* the package registry after a page reload without re-fetching remote indices.
|
|
155
|
+
*/
|
|
156
|
+
export interface InstalledPackage {
|
|
157
|
+
/**
|
|
158
|
+
* Package id. Matches the `PackageEntry.id` from the registry.
|
|
159
|
+
*/
|
|
160
|
+
id: string;
|
|
161
|
+
/**
|
|
162
|
+
* Whether this is a shard or an app.
|
|
163
|
+
*/
|
|
164
|
+
type: 'shard' | 'app' | 'combo';
|
|
165
|
+
/**
|
|
166
|
+
* The version that was installed.
|
|
167
|
+
*/
|
|
168
|
+
version: string;
|
|
169
|
+
/**
|
|
170
|
+
* URL of the registry this package was fetched from.
|
|
171
|
+
* Stored so the store UI can check for updates from the same source.
|
|
172
|
+
*/
|
|
173
|
+
sourceRegistry: string;
|
|
174
|
+
/**
|
|
175
|
+
* The `sh3-core` contract version the installed bundle was built
|
|
176
|
+
* against. Used to detect contract version mismatches after framework
|
|
177
|
+
* upgrades.
|
|
178
|
+
*/
|
|
179
|
+
contractVersion: string;
|
|
180
|
+
/**
|
|
181
|
+
* ISO 8601 timestamp of when the package was installed.
|
|
182
|
+
* Example: `"2026-04-06T12:34:56.789Z"`.
|
|
183
|
+
*/
|
|
184
|
+
installedAt: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Result of an install operation.
|
|
188
|
+
*
|
|
189
|
+
* Returned by the framework install API after attempting to download,
|
|
190
|
+
* verify, and hot-load a package bundle.
|
|
191
|
+
*/
|
|
192
|
+
export interface InstallResult {
|
|
193
|
+
/**
|
|
194
|
+
* Whether the installation succeeded.
|
|
195
|
+
* On `false`, inspect `error` for the reason.
|
|
196
|
+
*/
|
|
197
|
+
success: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* The `InstalledPackage` record written to local storage on success.
|
|
200
|
+
* Undefined on failure.
|
|
201
|
+
*/
|
|
202
|
+
package?: InstalledPackage;
|
|
203
|
+
/**
|
|
204
|
+
* Whether the package was activated in the current session without
|
|
205
|
+
* requiring a page reload. `false` means the user must reload before
|
|
206
|
+
* the package is usable.
|
|
207
|
+
*/
|
|
208
|
+
hotLoaded: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Human-readable error message on failure.
|
|
211
|
+
* Undefined on success.
|
|
212
|
+
*/
|
|
213
|
+
error?: string;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Metadata passed to the install API alongside the raw bundle bytes.
|
|
217
|
+
*
|
|
218
|
+
* Carries the provenance information needed to write an `InstalledPackage`
|
|
219
|
+
* record and to verify the download's integrity before execution.
|
|
220
|
+
*/
|
|
221
|
+
export interface PackageMeta {
|
|
222
|
+
/**
|
|
223
|
+
* Package id. Matches `PackageEntry.id`.
|
|
224
|
+
*/
|
|
225
|
+
id: string;
|
|
226
|
+
/**
|
|
227
|
+
* Whether this is a shard or an app.
|
|
228
|
+
*/
|
|
229
|
+
type: 'shard' | 'app' | 'combo';
|
|
230
|
+
/**
|
|
231
|
+
* The version being installed. Matches `PackageVersion.version`.
|
|
232
|
+
*/
|
|
233
|
+
version: string;
|
|
234
|
+
/**
|
|
235
|
+
* The `sh3-core` contract version the bundle was built against.
|
|
236
|
+
*/
|
|
237
|
+
contractVersion: string;
|
|
238
|
+
/**
|
|
239
|
+
* URL of the registry this package was fetched from.
|
|
240
|
+
*/
|
|
241
|
+
sourceRegistry: string;
|
|
242
|
+
/**
|
|
243
|
+
* SRI hash to verify the downloaded bundle against before executing.
|
|
244
|
+
* Must match `PackageVersion.integrity`.
|
|
245
|
+
*/
|
|
246
|
+
integrity: string;
|
|
247
|
+
/**
|
|
248
|
+
* Declared shard dependencies. Mirrors `PackageVersion.requires`.
|
|
249
|
+
* Undefined if no dependencies.
|
|
250
|
+
*/
|
|
251
|
+
requires?: RequiredDependency[];
|
|
252
|
+
/**
|
|
253
|
+
* SRI hash for the server bundle. Only present when the package has a
|
|
254
|
+
* server component.
|
|
255
|
+
*/
|
|
256
|
+
serverIntegrity?: string;
|
|
257
|
+
/**
|
|
258
|
+
* Whether this package includes a server bundle that needs to be pushed
|
|
259
|
+
* to the server after client-side installation.
|
|
260
|
+
*/
|
|
261
|
+
hasServerBundle?: boolean;
|
|
262
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry protocol types.
|
|
3
|
+
*
|
|
4
|
+
* A registry is any static HTTP endpoint serving a `registry.json` index
|
|
5
|
+
* and pre-built ESM bundle files. These types define the wire format for
|
|
6
|
+
* the index document and the local metadata stored after installation.
|
|
7
|
+
*
|
|
8
|
+
* Registry flow:
|
|
9
|
+
* 1. Client fetches `<registryUrl>/registry.json` → `RegistryIndex`
|
|
10
|
+
* 2. User picks a `PackageEntry` and a `PackageVersion`
|
|
11
|
+
* 3. Client downloads `bundleUrl`, verifies `integrity`, hot-loads the ESM bundle
|
|
12
|
+
* 4. On success the client writes an `InstalledPackage` record to local storage
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side shard contract.
|
|
3
|
+
*
|
|
4
|
+
* A server shard is the optional backend counterpart to a client shard.
|
|
5
|
+
* It runs in Node inside sh3-server and declares routes that are mounted
|
|
6
|
+
* under `/api/<shard-id>/`. Server shards have full Node access — filesystem,
|
|
7
|
+
* child_process, network, etc. — and are trusted by the admin who installed
|
|
8
|
+
* them.
|
|
9
|
+
*
|
|
10
|
+
* The server bundle is a separate ESM file whose default export conforms
|
|
11
|
+
* to the `ServerShard` interface.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Context provided by sh3-server when mounting a server shard's routes.
|
|
15
|
+
*/
|
|
16
|
+
export interface ServerShardContext {
|
|
17
|
+
/** The shard id this server bundle belongs to. */
|
|
18
|
+
shardId: string;
|
|
19
|
+
/**
|
|
20
|
+
* Scoped filesystem directory for this shard's persistent data.
|
|
21
|
+
* Created automatically before `routes()` is called.
|
|
22
|
+
* Path: `<dataDir>/shards/<shard-id>/`
|
|
23
|
+
*/
|
|
24
|
+
dataDir: string;
|
|
25
|
+
/**
|
|
26
|
+
* Hono middleware that rejects non-admin callers.
|
|
27
|
+
* Apply per-route to protect mutation endpoints. Public read routes
|
|
28
|
+
* should not use this.
|
|
29
|
+
*
|
|
30
|
+
* Usage: `router.post('/publish', ctx.adminOnly, handler)`
|
|
31
|
+
*/
|
|
32
|
+
adminOnly: MiddlewareHandler;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The interface a server shard bundle must default-export.
|
|
36
|
+
*/
|
|
37
|
+
export interface ServerShard {
|
|
38
|
+
/** Must match the client shard's `manifest.id`. */
|
|
39
|
+
id: string;
|
|
40
|
+
/**
|
|
41
|
+
* Called once at mount time. Register Hono routes on the provided router.
|
|
42
|
+
* Routes are relative to `/api/<shard-id>/` — e.g. `router.get('/data', ...)`
|
|
43
|
+
* becomes `GET /api/<shard-id>/data`.
|
|
44
|
+
*
|
|
45
|
+
* May be async if the shard needs to initialise resources before serving.
|
|
46
|
+
*/
|
|
47
|
+
routes: (router: HonoLike, context: ServerShardContext) => void | Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Hono MiddlewareHandler type — duplicated here to avoid importing hono
|
|
51
|
+
* in the framework package (which is browser-targeted). The actual
|
|
52
|
+
* implementation is provided by sh3-server at runtime.
|
|
53
|
+
*/
|
|
54
|
+
type MiddlewareHandler = (c: unknown, next: () => Promise<void>) => Promise<void | Response>;
|
|
55
|
+
/**
|
|
56
|
+
* Hono app type — simplified stand-in. The actual Hono instance is
|
|
57
|
+
* provided by sh3-server.
|
|
58
|
+
*/
|
|
59
|
+
type HonoLike = {
|
|
60
|
+
get(path: string, ...handlers: unknown[]): unknown;
|
|
61
|
+
post(path: string, ...handlers: unknown[]): unknown;
|
|
62
|
+
put(path: string, ...handlers: unknown[]): unknown;
|
|
63
|
+
patch(path: string, ...handlers: unknown[]): unknown;
|
|
64
|
+
delete(path: string, ...handlers: unknown[]): unknown;
|
|
65
|
+
use(path: string, ...handlers: unknown[]): unknown;
|
|
66
|
+
};
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side shard contract.
|
|
3
|
+
*
|
|
4
|
+
* A server shard is the optional backend counterpart to a client shard.
|
|
5
|
+
* It runs in Node inside sh3-server and declares routes that are mounted
|
|
6
|
+
* under `/api/<shard-id>/`. Server shards have full Node access — filesystem,
|
|
7
|
+
* child_process, network, etc. — and are trusted by the admin who installed
|
|
8
|
+
* them.
|
|
9
|
+
*
|
|
10
|
+
* The server bundle is a separate ESM file whose default export conforms
|
|
11
|
+
* to the `ServerShard` interface.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|