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.
Files changed (242) hide show
  1. package/README.md +9 -0
  2. package/dist/Shell.svelte +283 -0
  3. package/dist/Shell.svelte.d.ts +5 -0
  4. package/dist/api.d.ts +28 -0
  5. package/dist/api.js +50 -0
  6. package/dist/app/admin/ApiKeysView.svelte +169 -0
  7. package/dist/app/admin/ApiKeysView.svelte.d.ts +3 -0
  8. package/dist/app/admin/AuthSettingsView.svelte +105 -0
  9. package/dist/app/admin/AuthSettingsView.svelte.d.ts +3 -0
  10. package/dist/app/admin/SystemView.svelte +73 -0
  11. package/dist/app/admin/SystemView.svelte.d.ts +3 -0
  12. package/dist/app/admin/UsersView.svelte +188 -0
  13. package/dist/app/admin/UsersView.svelte.d.ts +3 -0
  14. package/dist/app/admin/adminApp.d.ts +7 -0
  15. package/dist/app/admin/adminApp.js +25 -0
  16. package/dist/app/admin/adminShard.svelte.d.ts +4 -0
  17. package/dist/app/admin/adminShard.svelte.js +62 -0
  18. package/dist/app/store/InstalledView.svelte +246 -0
  19. package/dist/app/store/InstalledView.svelte.d.ts +3 -0
  20. package/dist/app/store/StoreView.svelte +522 -0
  21. package/dist/app/store/StoreView.svelte.d.ts +3 -0
  22. package/dist/app/store/storeApp.d.ts +10 -0
  23. package/dist/app/store/storeApp.js +26 -0
  24. package/dist/app/store/storeShard.svelte.d.ts +38 -0
  25. package/dist/app/store/storeShard.svelte.js +218 -0
  26. package/dist/apps/lifecycle.d.ts +42 -0
  27. package/dist/apps/lifecycle.js +184 -0
  28. package/dist/apps/registry.svelte.d.ts +40 -0
  29. package/dist/apps/registry.svelte.js +59 -0
  30. package/dist/apps/terminal/manifest.d.ts +8 -0
  31. package/dist/apps/terminal/manifest.js +13 -0
  32. package/dist/apps/terminal/terminal-app.d.ts +7 -0
  33. package/dist/apps/terminal/terminal-app.js +14 -0
  34. package/dist/apps/types.d.ts +93 -0
  35. package/dist/apps/types.js +10 -0
  36. package/dist/artifact.d.ts +32 -0
  37. package/dist/artifact.js +1 -0
  38. package/dist/assets/SH3.png +0 -0
  39. package/dist/assets/icons.svg +1126 -0
  40. package/dist/assets.d.ts +13 -0
  41. package/dist/auth/GuestBanner.svelte +134 -0
  42. package/dist/auth/GuestBanner.svelte.d.ts +3 -0
  43. package/dist/auth/SignInWall.svelte +203 -0
  44. package/dist/auth/SignInWall.svelte.d.ts +7 -0
  45. package/dist/auth/auth.svelte.d.ts +69 -0
  46. package/dist/auth/auth.svelte.js +165 -0
  47. package/dist/auth/index.d.ts +2 -0
  48. package/dist/auth/index.js +1 -0
  49. package/dist/auth/types.d.ts +41 -0
  50. package/dist/auth/types.js +6 -0
  51. package/dist/build.d.ts +49 -0
  52. package/dist/build.js +236 -0
  53. package/dist/contract.d.ts +20 -0
  54. package/dist/contract.js +28 -0
  55. package/dist/createShell.d.ts +24 -0
  56. package/dist/createShell.js +131 -0
  57. package/dist/documents/backends.d.ts +17 -0
  58. package/dist/documents/backends.js +156 -0
  59. package/dist/documents/config.d.ts +7 -0
  60. package/dist/documents/config.js +27 -0
  61. package/dist/documents/handle.d.ts +6 -0
  62. package/dist/documents/handle.js +154 -0
  63. package/dist/documents/http-backend.d.ts +22 -0
  64. package/dist/documents/http-backend.js +78 -0
  65. package/dist/documents/index.d.ts +6 -0
  66. package/dist/documents/index.js +8 -0
  67. package/dist/documents/notifications.d.ts +9 -0
  68. package/dist/documents/notifications.js +39 -0
  69. package/dist/documents/types.d.ts +97 -0
  70. package/dist/documents/types.js +12 -0
  71. package/dist/env/client.d.ts +44 -0
  72. package/dist/env/client.js +106 -0
  73. package/dist/env/index.d.ts +2 -0
  74. package/dist/env/index.js +1 -0
  75. package/dist/env/types.d.ts +12 -0
  76. package/dist/env/types.js +8 -0
  77. package/dist/host-entry.d.ts +13 -0
  78. package/dist/host-entry.js +17 -0
  79. package/dist/host.d.ts +15 -0
  80. package/dist/host.js +86 -0
  81. package/dist/index.d.ts +4 -0
  82. package/dist/index.js +14 -0
  83. package/dist/layout/DragPreview.svelte +63 -0
  84. package/dist/layout/DragPreview.svelte.d.ts +3 -0
  85. package/dist/layout/LayoutRenderer.svelte +262 -0
  86. package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
  87. package/dist/layout/SlotContainer.svelte +140 -0
  88. package/dist/layout/SlotContainer.svelte.d.ts +8 -0
  89. package/dist/layout/SlotDropZone.svelte +122 -0
  90. package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
  91. package/dist/layout/drag.svelte.d.ts +45 -0
  92. package/dist/layout/drag.svelte.js +200 -0
  93. package/dist/layout/inspection.d.ts +72 -0
  94. package/dist/layout/inspection.js +209 -0
  95. package/dist/layout/ops.d.ts +100 -0
  96. package/dist/layout/ops.js +310 -0
  97. package/dist/layout/slotHostPool.svelte.d.ts +36 -0
  98. package/dist/layout/slotHostPool.svelte.js +229 -0
  99. package/dist/layout/store.svelte.d.ts +39 -0
  100. package/dist/layout/store.svelte.js +153 -0
  101. package/dist/layout/tree-walk.d.ts +15 -0
  102. package/dist/layout/tree-walk.js +33 -0
  103. package/dist/layout/types.d.ts +108 -0
  104. package/dist/layout/types.js +25 -0
  105. package/dist/migrations/shell-rename.d.ts +16 -0
  106. package/dist/migrations/shell-rename.js +48 -0
  107. package/dist/overlays/ModalFrame.svelte +87 -0
  108. package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
  109. package/dist/overlays/PopupFrame.svelte +85 -0
  110. package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
  111. package/dist/overlays/ToastItem.svelte +77 -0
  112. package/dist/overlays/ToastItem.svelte.d.ts +9 -0
  113. package/dist/overlays/focusTrap.d.ts +1 -0
  114. package/dist/overlays/focusTrap.js +64 -0
  115. package/dist/overlays/modal.d.ts +9 -0
  116. package/dist/overlays/modal.js +141 -0
  117. package/dist/overlays/popup.d.ts +9 -0
  118. package/dist/overlays/popup.js +108 -0
  119. package/dist/overlays/roots.d.ts +4 -0
  120. package/dist/overlays/roots.js +31 -0
  121. package/dist/overlays/toast.d.ts +6 -0
  122. package/dist/overlays/toast.js +93 -0
  123. package/dist/overlays/types.d.ts +31 -0
  124. package/dist/overlays/types.js +15 -0
  125. package/dist/platform/index.d.ts +10 -0
  126. package/dist/platform/index.js +33 -0
  127. package/dist/platform/tauri-backend.d.ts +15 -0
  128. package/dist/platform/tauri-backend.js +58 -0
  129. package/dist/primitives/.gitkeep +0 -0
  130. package/dist/primitives/ResizableSplitter.svelte +333 -0
  131. package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
  132. package/dist/primitives/TabbedPanel.svelte +305 -0
  133. package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
  134. package/dist/primitives/base.css +42 -0
  135. package/dist/registry/client.d.ts +74 -0
  136. package/dist/registry/client.js +117 -0
  137. package/dist/registry/index.d.ts +13 -0
  138. package/dist/registry/index.js +14 -0
  139. package/dist/registry/installer.d.ts +53 -0
  140. package/dist/registry/installer.js +168 -0
  141. package/dist/registry/integrity.d.ts +32 -0
  142. package/dist/registry/integrity.js +92 -0
  143. package/dist/registry/loader.d.ts +50 -0
  144. package/dist/registry/loader.js +145 -0
  145. package/dist/registry/schema.d.ts +47 -0
  146. package/dist/registry/schema.js +185 -0
  147. package/dist/registry/storage.d.ts +37 -0
  148. package/dist/registry/storage.js +101 -0
  149. package/dist/registry/types.d.ts +262 -0
  150. package/dist/registry/types.js +14 -0
  151. package/dist/server-shard/types.d.ts +67 -0
  152. package/dist/server-shard/types.js +13 -0
  153. package/dist/sh3core-shard/ShellHome.svelte +192 -0
  154. package/dist/sh3core-shard/ShellHome.svelte.d.ts +3 -0
  155. package/dist/sh3core-shard/ShellTitle.svelte +171 -0
  156. package/dist/sh3core-shard/ShellTitle.svelte.d.ts +3 -0
  157. package/dist/sh3core-shard/sh3coreShard.svelte.d.ts +2 -0
  158. package/dist/sh3core-shard/sh3coreShard.svelte.js +53 -0
  159. package/dist/shards/activate.svelte.d.ts +52 -0
  160. package/dist/shards/activate.svelte.js +186 -0
  161. package/dist/shards/registry.d.ts +4 -0
  162. package/dist/shards/registry.js +28 -0
  163. package/dist/shards/types.d.ts +207 -0
  164. package/dist/shards/types.js +20 -0
  165. package/dist/shell-shard/InputLine.svelte +133 -0
  166. package/dist/shell-shard/InputLine.svelte.d.ts +11 -0
  167. package/dist/shell-shard/ScrollbackView.svelte +47 -0
  168. package/dist/shell-shard/ScrollbackView.svelte.d.ts +7 -0
  169. package/dist/shell-shard/Terminal.svelte +122 -0
  170. package/dist/shell-shard/Terminal.svelte.d.ts +8 -0
  171. package/dist/shell-shard/entries/PromptEntry.svelte +25 -0
  172. package/dist/shell-shard/entries/PromptEntry.svelte.d.ts +7 -0
  173. package/dist/shell-shard/entries/RichEntry.svelte +19 -0
  174. package/dist/shell-shard/entries/RichEntry.svelte.d.ts +8 -0
  175. package/dist/shell-shard/entries/StatusEntry.svelte +22 -0
  176. package/dist/shell-shard/entries/StatusEntry.svelte.d.ts +7 -0
  177. package/dist/shell-shard/entries/TextEntry.svelte +25 -0
  178. package/dist/shell-shard/entries/TextEntry.svelte.d.ts +7 -0
  179. package/dist/shell-shard/manifest.d.ts +2 -0
  180. package/dist/shell-shard/manifest.js +11 -0
  181. package/dist/shell-shard/protocol.d.ts +90 -0
  182. package/dist/shell-shard/protocol.js +11 -0
  183. package/dist/shell-shard/registry.d.ts +69 -0
  184. package/dist/shell-shard/registry.js +47 -0
  185. package/dist/shell-shard/rich/AppCard.svelte +25 -0
  186. package/dist/shell-shard/rich/AppCard.svelte.d.ts +10 -0
  187. package/dist/shell-shard/rich/AppsTable.svelte +29 -0
  188. package/dist/shell-shard/rich/AppsTable.svelte.d.ts +12 -0
  189. package/dist/shell-shard/rich/EnvTable.svelte +27 -0
  190. package/dist/shell-shard/rich/EnvTable.svelte.d.ts +8 -0
  191. package/dist/shell-shard/rich/HelpTable.svelte +29 -0
  192. package/dist/shell-shard/rich/HelpTable.svelte.d.ts +12 -0
  193. package/dist/shell-shard/rich/HistoryList.svelte +37 -0
  194. package/dist/shell-shard/rich/HistoryList.svelte.d.ts +9 -0
  195. package/dist/shell-shard/rich/ShardsTable.svelte +28 -0
  196. package/dist/shell-shard/rich/ShardsTable.svelte.d.ts +12 -0
  197. package/dist/shell-shard/rich/ViewsTable.svelte +31 -0
  198. package/dist/shell-shard/rich/ViewsTable.svelte.d.ts +13 -0
  199. package/dist/shell-shard/rich/ZoneTree.svelte +19 -0
  200. package/dist/shell-shard/rich/ZoneTree.svelte.d.ts +8 -0
  201. package/dist/shell-shard/rich/ZonesTable.svelte +27 -0
  202. package/dist/shell-shard/rich/ZonesTable.svelte.d.ts +11 -0
  203. package/dist/shell-shard/scrollback.svelte.d.ts +36 -0
  204. package/dist/shell-shard/scrollback.svelte.js +43 -0
  205. package/dist/shell-shard/session-client.svelte.d.ts +23 -0
  206. package/dist/shell-shard/session-client.svelte.js +120 -0
  207. package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
  208. package/dist/shell-shard/shellShard.svelte.js +139 -0
  209. package/dist/shell-shard/verbs/apps.d.ts +3 -0
  210. package/dist/shell-shard/verbs/apps.js +50 -0
  211. package/dist/shell-shard/verbs/clear.d.ts +2 -0
  212. package/dist/shell-shard/verbs/clear.js +7 -0
  213. package/dist/shell-shard/verbs/help.d.ts +2 -0
  214. package/dist/shell-shard/verbs/help.js +21 -0
  215. package/dist/shell-shard/verbs/history.d.ts +2 -0
  216. package/dist/shell-shard/verbs/history.js +20 -0
  217. package/dist/shell-shard/verbs/index.d.ts +2 -0
  218. package/dist/shell-shard/verbs/index.js +29 -0
  219. package/dist/shell-shard/verbs/session.d.ts +5 -0
  220. package/dist/shell-shard/verbs/session.js +65 -0
  221. package/dist/shell-shard/verbs/shards.d.ts +2 -0
  222. package/dist/shell-shard/verbs/shards.js +14 -0
  223. package/dist/shell-shard/verbs/views.d.ts +4 -0
  224. package/dist/shell-shard/verbs/views.js +90 -0
  225. package/dist/shell-shard/verbs/zones.d.ts +3 -0
  226. package/dist/shell-shard/verbs/zones.js +38 -0
  227. package/dist/shellRuntime.svelte.d.ts +27 -0
  228. package/dist/shellRuntime.svelte.js +27 -0
  229. package/dist/state/backends.d.ts +26 -0
  230. package/dist/state/backends.js +99 -0
  231. package/dist/state/manage.d.ts +14 -0
  232. package/dist/state/manage.js +40 -0
  233. package/dist/state/types.d.ts +55 -0
  234. package/dist/state/types.js +17 -0
  235. package/dist/state/zones.svelte.d.ts +53 -0
  236. package/dist/state/zones.svelte.js +141 -0
  237. package/dist/theme.d.ts +28 -0
  238. package/dist/theme.js +92 -0
  239. package/dist/tokens.css +102 -0
  240. package/dist/version.d.ts +2 -0
  241. package/dist/version.js +2 -0
  242. 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 {};