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,13 @@
1
+ // Ambient module declarations for static asset imports.
2
+ // Vite resolves these to URL strings at bundle time; svelte-check/tsc
3
+ // need a type declaration so that `import url from './foo.svg'` typechecks.
4
+
5
+ declare module '*.svg' {
6
+ const url: string;
7
+ export default url;
8
+ }
9
+
10
+ declare module '*.png' {
11
+ const url: string;
12
+ export default url;
13
+ }
@@ -0,0 +1,134 @@
1
+ <script lang="ts">
2
+ /**
3
+ * GuestBanner — persistent bar shown when browsing as guest.
4
+ * Clicking "Sign in" opens a modal-like overlay with the sign-in form.
5
+ */
6
+
7
+ import { isGuest, login } from './index';
8
+
9
+ let showSignIn = $state(false);
10
+ let username = $state('');
11
+ let password = $state('');
12
+ let error = $state<string | null>(null);
13
+ let loading = $state(false);
14
+
15
+ async function handleLogin() {
16
+ if (!username.trim() || !password.trim() || loading) return;
17
+ loading = true;
18
+ error = null;
19
+ const result = await login(username.trim(), password.trim());
20
+ loading = false;
21
+ if (result.ok) {
22
+ showSignIn = false;
23
+ } else {
24
+ error = result.error;
25
+ }
26
+ }
27
+ </script>
28
+
29
+ <div class="guest-banner-slot">
30
+ {#if isGuest()}
31
+ <div class="guest-banner">
32
+ <span class="guest-banner-text">Browsing as guest. Sign in to save your work.</span>
33
+ <button type="button" class="guest-banner-action" onclick={() => { showSignIn = true; }}>
34
+ Sign in
35
+ </button>
36
+ </div>
37
+
38
+ {#if showSignIn}
39
+ <div class="guest-signin-overlay" role="dialog">
40
+ <div class="guest-signin-card">
41
+ <form class="guest-signin-form" onsubmit={(e) => { e.preventDefault(); handleLogin(); }}>
42
+ <input class="guest-signin-input" type="text" placeholder="Username" bind:value={username} disabled={loading} autocomplete="username" />
43
+ <input class="guest-signin-input" type="password" placeholder="Password" bind:value={password} disabled={loading} autocomplete="current-password" />
44
+ <div class="guest-signin-actions">
45
+ <button type="submit" class="guest-signin-btn" disabled={loading || !username.trim() || !password.trim()}>
46
+ {loading ? 'Signing in...' : 'Sign in'}
47
+ </button>
48
+ <button type="button" class="guest-signin-cancel" onclick={() => { showSignIn = false; error = null; }}>
49
+ Cancel
50
+ </button>
51
+ </div>
52
+ </form>
53
+ {#if error}
54
+ <div class="guest-signin-error">{error}</div>
55
+ {/if}
56
+ </div>
57
+ </div>
58
+ {/if}
59
+ {/if}
60
+ </div>
61
+
62
+ <style>
63
+ .guest-banner {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ gap: 12px;
68
+ padding: 6px var(--shell-pad-md, 12px);
69
+ background: color-mix(in srgb, var(--shell-accent, #7c7cf0) 15%, transparent);
70
+ border-bottom: 1px solid var(--shell-border, #3a3a5c);
71
+ font-size: 12px;
72
+ color: var(--shell-fg, #e0e0e0);
73
+ }
74
+ .guest-banner-action {
75
+ padding: 3px 10px;
76
+ color: var(--shell-bg, #1a1a2e);
77
+ font-size: 11px;
78
+ font-weight: 600;
79
+ }
80
+ .guest-signin-overlay {
81
+ position: fixed;
82
+ inset: 0;
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ background: rgba(0, 0, 0, 0.5);
87
+ z-index: 9999;
88
+ }
89
+ .guest-signin-card {
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 12px;
93
+ padding: 32px;
94
+ background: var(--shell-bg-elevated, #252540);
95
+ border: 1px solid var(--shell-border, #3a3a5c);
96
+ border-radius: var(--shell-radius-lg, 12px);
97
+ min-width: 300px;
98
+ }
99
+ .guest-signin-form {
100
+ display: flex;
101
+ flex-direction: column;
102
+ gap: 10px;
103
+ }
104
+ .guest-signin-input {
105
+ padding: 8px 12px;
106
+ background: var(--shell-bg, #1a1a2e);
107
+ color: var(--shell-fg, #e0e0e0);
108
+ border: 1px solid var(--shell-border, #3a3a5c);
109
+ border-radius: var(--shell-radius, 6px);
110
+ font-size: 13px;
111
+ }
112
+ .guest-signin-input::placeholder { color: var(--shell-fg-muted, #888); }
113
+ .guest-signin-actions { display: flex; gap: 8px; }
114
+ .guest-signin-btn {
115
+ flex: 1;
116
+ padding: 8px;
117
+ color: var(--shell-bg, #1a1a2e);
118
+ font-weight: 600;
119
+ }
120
+ .guest-signin-btn:disabled { opacity: 0.6; cursor: not-allowed; }
121
+ .guest-signin-cancel {
122
+ padding: 8px 12px;
123
+ background: transparent;
124
+ color: var(--shell-fg-subtle, #aaa);
125
+ border: 1px solid var(--shell-border, #3a3a5c);
126
+ }
127
+ .guest-signin-error {
128
+ padding: 6px 10px;
129
+ font-size: 12px;
130
+ color: var(--shell-error, #d32f2f);
131
+ background: color-mix(in srgb, var(--shell-error, #d32f2f) 10%, transparent);
132
+ border-radius: var(--shell-radius, 6px);
133
+ }
134
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const GuestBanner: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type GuestBanner = ReturnType<typeof GuestBanner>;
3
+ export default GuestBanner;
@@ -0,0 +1,203 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SignInWall — standalone sign-in screen shown before shell boots.
4
+ * Mounted directly to the target element by createShell().
5
+ */
6
+
7
+ import { login, register } from './index';
8
+
9
+ interface Props {
10
+ selfRegistration: boolean;
11
+ onSuccess: () => void;
12
+ }
13
+
14
+ let { selfRegistration, onSuccess }: Props = $props();
15
+
16
+ let mode = $state<'login' | 'register'>('login');
17
+ let username = $state('');
18
+ let password = $state('');
19
+ let displayName = $state('');
20
+ let error = $state<string | null>(null);
21
+ let loading = $state(false);
22
+
23
+ async function handleLogin() {
24
+ if (!username.trim() || !password.trim() || loading) return;
25
+ loading = true;
26
+ error = null;
27
+ const result = await login(username.trim(), password.trim());
28
+ loading = false;
29
+ if (result.ok) {
30
+ onSuccess();
31
+ } else {
32
+ error = result.error;
33
+ }
34
+ }
35
+
36
+ async function handleRegister() {
37
+ if (!username.trim() || !password.trim() || loading) return;
38
+ loading = true;
39
+ error = null;
40
+ const result = await register(
41
+ username.trim(),
42
+ password.trim(),
43
+ displayName.trim() || undefined,
44
+ );
45
+ loading = false;
46
+ if (result.ok) {
47
+ onSuccess();
48
+ } else {
49
+ error = result.error;
50
+ }
51
+ }
52
+
53
+ function switchMode(m: 'login' | 'register') {
54
+ mode = m;
55
+ error = null;
56
+ }
57
+ </script>
58
+
59
+ <div class="signin-wall">
60
+ <div class="signin-card">
61
+ <h1 class="signin-brand">SH3</h1>
62
+
63
+ {#if mode === 'login'}
64
+ <form class="signin-form" onsubmit={(e) => { e.preventDefault(); handleLogin(); }}>
65
+ <input
66
+ class="signin-input"
67
+ type="text"
68
+ placeholder="Username"
69
+ bind:value={username}
70
+ disabled={loading}
71
+ autocomplete="username"
72
+ />
73
+ <input
74
+ class="signin-input"
75
+ type="password"
76
+ placeholder="Password"
77
+ bind:value={password}
78
+ disabled={loading}
79
+ autocomplete="current-password"
80
+ />
81
+ <button type="submit" class="signin-btn" disabled={loading || !username.trim() || !password.trim()}>
82
+ {loading ? 'Signing in...' : 'Sign in'}
83
+ </button>
84
+ </form>
85
+ {#if selfRegistration}
86
+ <button type="button" class="signin-link" onclick={() => switchMode('register')}>
87
+ Create an account
88
+ </button>
89
+ {/if}
90
+ {:else}
91
+ <form class="signin-form" onsubmit={(e) => { e.preventDefault(); handleRegister(); }}>
92
+ <input
93
+ class="signin-input"
94
+ type="text"
95
+ placeholder="Username"
96
+ bind:value={username}
97
+ disabled={loading}
98
+ autocomplete="username"
99
+ />
100
+ <input
101
+ class="signin-input"
102
+ type="text"
103
+ placeholder="Display name (optional)"
104
+ bind:value={displayName}
105
+ disabled={loading}
106
+ />
107
+ <input
108
+ class="signin-input"
109
+ type="password"
110
+ placeholder="Password"
111
+ bind:value={password}
112
+ disabled={loading}
113
+ autocomplete="new-password"
114
+ />
115
+ <button type="submit" class="signin-btn" disabled={loading || !username.trim() || !password.trim()}>
116
+ {loading ? 'Creating...' : 'Create account'}
117
+ </button>
118
+ </form>
119
+ <button type="button" class="signin-link" onclick={() => switchMode('login')}>
120
+ Back to sign in
121
+ </button>
122
+ {/if}
123
+
124
+ {#if error}
125
+ <div class="signin-error">{error}</div>
126
+ {/if}
127
+ </div>
128
+ </div>
129
+
130
+ <style>
131
+ .signin-wall {
132
+ position: absolute;
133
+ inset: 0;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ background: var(--shell-grad-bg, var(--shell-bg, #1a1a2e));
138
+ color: var(--shell-fg, #e0e0e0);
139
+ font-family: system-ui, sans-serif;
140
+ }
141
+ .signin-card {
142
+ display: flex;
143
+ flex-direction: column;
144
+ align-items: center;
145
+ gap: 16px;
146
+ padding: 48px 40px;
147
+ background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated, #252540));
148
+ border: 1px solid var(--shell-border, #3a3a5c);
149
+ border-radius: var(--shell-radius-lg, 12px);
150
+ min-width: 320px;
151
+ }
152
+ .signin-brand {
153
+ margin: 0 0 8px;
154
+ font-size: 42px;
155
+ color: var(--shell-accent, #7c7cf0);
156
+ letter-spacing: 2px;
157
+ }
158
+ .signin-form {
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: 12px;
162
+ width: 100%;
163
+ }
164
+ .signin-input {
165
+ padding: 10px 14px;
166
+ background: var(--shell-bg, #1a1a2e);
167
+ color: var(--shell-fg, #e0e0e0);
168
+ border: 1px solid var(--shell-border, #3a3a5c);
169
+ border-radius: var(--shell-radius, 6px);
170
+ font-size: 14px;
171
+ }
172
+ .signin-input::placeholder {
173
+ color: var(--shell-fg-muted, #888);
174
+ }
175
+ .signin-btn {
176
+ padding: 10px 16px;
177
+ color: var(--shell-bg, #1a1a2e);
178
+ font-weight: 600;
179
+ font-size: 14px;
180
+ }
181
+ .signin-btn:disabled {
182
+ opacity: 0.6;
183
+ cursor: not-allowed;
184
+ }
185
+ .signin-link {
186
+ background: none;
187
+ color: var(--shell-accent, #7c7cf0);
188
+ font-size: 13px;
189
+ padding: 0;
190
+ }
191
+ .signin-link:hover {
192
+ text-decoration: underline;
193
+ }
194
+ .signin-error {
195
+ padding: 8px 12px;
196
+ font-size: 13px;
197
+ color: var(--shell-error, #d32f2f);
198
+ background: color-mix(in srgb, var(--shell-error, #d32f2f) 10%, transparent);
199
+ border-radius: var(--shell-radius, 6px);
200
+ width: 100%;
201
+ text-align: center;
202
+ }
203
+ </style>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ selfRegistration: boolean;
3
+ onSuccess: () => void;
4
+ }
5
+ declare const SignInWall: import("svelte").Component<Props, {}, "">;
6
+ type SignInWall = ReturnType<typeof SignInWall>;
7
+ export default SignInWall;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Client-side auth — session-based identity for SH3.
3
+ *
4
+ * The boot flow (createShell) calls initFromBoot() with the server's
5
+ * boot config. After that, login/logout call the server and update
6
+ * the reactive state. isAdmin/isGuest/isAuthenticated are reactive
7
+ * getters consumed by shell components.
8
+ *
9
+ * .svelte.ts because it uses $state for reactive auth status.
10
+ */
11
+ import type { AuthUser, AuthSession, BootConfig } from './types';
12
+ /**
13
+ * Initialize auth from boot config. Called once by createShell()
14
+ * after fetching /api/boot.
15
+ */
16
+ export declare function initFromBoot(url: string, config: BootConfig): void;
17
+ /**
18
+ * Log in with username + password. On success, updates reactive state.
19
+ * Returns { ok: true } or { ok: false, error: string }.
20
+ */
21
+ export declare function login(username: string, password: string): Promise<{
22
+ ok: true;
23
+ } | {
24
+ ok: false;
25
+ error: string;
26
+ }>;
27
+ /**
28
+ * Register a new account (when self-registration is enabled).
29
+ * On success, auto-logs in and updates reactive state.
30
+ */
31
+ export declare function register(username: string, password: string, displayName?: string): Promise<{
32
+ ok: true;
33
+ } | {
34
+ ok: false;
35
+ error: string;
36
+ }>;
37
+ /**
38
+ * Log out — clear session on server and client.
39
+ *
40
+ * If the boot policy forbids guest browsing (auth.required &&
41
+ * !auth.guestAllowed), trigger a full page reload so the boot-time
42
+ * hard gate in createShell.ts re-runs and shows the sign-in wall.
43
+ * This keeps the policy authoritative in a single place rather than
44
+ * duplicating it here.
45
+ */
46
+ export declare function logout(): Promise<void>;
47
+ /**
48
+ * Mark this session as local-owner — auto-elevate to admin without
49
+ * server verification. Called by the host in Tauri / dev environments.
50
+ */
51
+ export declare function setLocalOwner(): void;
52
+ /** Reactive — true when running as local owner (Tauri / dev). */
53
+ export declare function isLocalOwner(): boolean;
54
+ /** Reactive — true when the user has admin role. */
55
+ export declare function isAdmin(): boolean;
56
+ /** Reactive — true when the user has a valid session. */
57
+ export declare function isAuthenticated(): boolean;
58
+ /** Reactive — true when browsing without a session. */
59
+ export declare function isGuest(): boolean;
60
+ /** Get the current user (reactive). */
61
+ export declare function getUser(): AuthUser | null;
62
+ /** Get the current session (reactive). */
63
+ export declare function getSession(): AuthSession | null;
64
+ /**
65
+ * Build an Authorization header value for authenticated fetch calls
66
+ * that need explicit headers (e.g. non-cookie contexts).
67
+ * Returns null if not authenticated.
68
+ */
69
+ export declare function getAuthHeader(): string | null;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Client-side auth — session-based identity for SH3.
3
+ *
4
+ * The boot flow (createShell) calls initFromBoot() with the server's
5
+ * boot config. After that, login/logout call the server and update
6
+ * the reactive state. isAdmin/isGuest/isAuthenticated are reactive
7
+ * getters consumed by shell components.
8
+ *
9
+ * .svelte.ts because it uses $state for reactive auth status.
10
+ */
11
+ /** Reactive auth state. */
12
+ let currentUser = $state(null);
13
+ let currentSession = $state(null);
14
+ let guest = $state(false);
15
+ /** Server base URL, set during boot. */
16
+ let serverUrl = '';
17
+ /** Boot auth policy, captured at initFromBoot. Used by logout() to
18
+ * decide whether a post-logout reload is required to re-run the
19
+ * boot-time hard gate. Non-reactive — no consumer observes this. */
20
+ let authConfig = null;
21
+ /**
22
+ * Initialize auth from boot config. Called once by createShell()
23
+ * after fetching /api/boot.
24
+ */
25
+ export function initFromBoot(url, config) {
26
+ serverUrl = url;
27
+ authConfig = config.auth;
28
+ currentUser = config.user;
29
+ currentSession = config.session;
30
+ guest = !config.session && !config.user;
31
+ }
32
+ /**
33
+ * Log in with username + password. On success, updates reactive state.
34
+ * Returns { ok: true } or { ok: false, error: string }.
35
+ */
36
+ export async function login(username, password) {
37
+ try {
38
+ const res = await fetch(`${serverUrl}/api/auth/login`, {
39
+ method: 'POST',
40
+ headers: { 'Content-Type': 'application/json' },
41
+ credentials: 'include',
42
+ body: JSON.stringify({ username, password }),
43
+ });
44
+ if (!res.ok) {
45
+ const body = await res.json().catch(() => ({}));
46
+ return { ok: false, error: body.error || 'Login failed' };
47
+ }
48
+ const body = await res.json();
49
+ currentUser = body.user;
50
+ currentSession = body.session;
51
+ guest = false;
52
+ return { ok: true };
53
+ }
54
+ catch (_a) {
55
+ return { ok: false, error: 'Network error' };
56
+ }
57
+ }
58
+ /**
59
+ * Register a new account (when self-registration is enabled).
60
+ * On success, auto-logs in and updates reactive state.
61
+ */
62
+ export async function register(username, password, displayName) {
63
+ try {
64
+ const res = await fetch(`${serverUrl}/api/auth/register`, {
65
+ method: 'POST',
66
+ headers: { 'Content-Type': 'application/json' },
67
+ credentials: 'include',
68
+ body: JSON.stringify({ username, password, displayName }),
69
+ });
70
+ if (!res.ok) {
71
+ const body = await res.json().catch(() => ({}));
72
+ return { ok: false, error: body.error || 'Registration failed' };
73
+ }
74
+ const body = await res.json();
75
+ currentUser = body.user;
76
+ currentSession = body.session;
77
+ guest = false;
78
+ return { ok: true };
79
+ }
80
+ catch (_a) {
81
+ return { ok: false, error: 'Network error' };
82
+ }
83
+ }
84
+ /**
85
+ * Log out — clear session on server and client.
86
+ *
87
+ * If the boot policy forbids guest browsing (auth.required &&
88
+ * !auth.guestAllowed), trigger a full page reload so the boot-time
89
+ * hard gate in createShell.ts re-runs and shows the sign-in wall.
90
+ * This keeps the policy authoritative in a single place rather than
91
+ * duplicating it here.
92
+ */
93
+ export async function logout() {
94
+ try {
95
+ await fetch(`${serverUrl}/api/auth/logout`, {
96
+ method: 'POST',
97
+ credentials: 'include',
98
+ });
99
+ }
100
+ catch (_a) {
101
+ // Best effort
102
+ }
103
+ if ((authConfig === null || authConfig === void 0 ? void 0 : authConfig.required) && !authConfig.guestAllowed) {
104
+ // Policy forbids guest browsing — re-run the boot-time hard gate.
105
+ // Do not touch reactive state: the page is leaving.
106
+ window.location.reload();
107
+ return;
108
+ }
109
+ currentUser = null;
110
+ currentSession = null;
111
+ guest = true;
112
+ }
113
+ /**
114
+ * Mark this session as local-owner — auto-elevate to admin without
115
+ * server verification. Called by the host in Tauri / dev environments.
116
+ */
117
+ export function setLocalOwner() {
118
+ currentUser = {
119
+ id: 'local',
120
+ username: 'local',
121
+ displayName: 'Local Owner',
122
+ role: 'admin',
123
+ createdAt: '',
124
+ updatedAt: '',
125
+ };
126
+ currentSession = {
127
+ token: 'local',
128
+ userId: 'local',
129
+ role: 'admin',
130
+ expiresAt: Infinity,
131
+ };
132
+ guest = false;
133
+ }
134
+ /** Reactive — true when running as local owner (Tauri / dev). */
135
+ export function isLocalOwner() {
136
+ return (currentSession === null || currentSession === void 0 ? void 0 : currentSession.token) === 'local';
137
+ }
138
+ /** Reactive — true when the user has admin role. */
139
+ export function isAdmin() {
140
+ return (currentSession === null || currentSession === void 0 ? void 0 : currentSession.role) === 'admin';
141
+ }
142
+ /** Reactive — true when the user has a valid session. */
143
+ export function isAuthenticated() {
144
+ return currentSession !== null;
145
+ }
146
+ /** Reactive — true when browsing without a session. */
147
+ export function isGuest() {
148
+ return guest;
149
+ }
150
+ /** Get the current user (reactive). */
151
+ export function getUser() {
152
+ return currentUser;
153
+ }
154
+ /** Get the current session (reactive). */
155
+ export function getSession() {
156
+ return currentSession;
157
+ }
158
+ /**
159
+ * Build an Authorization header value for authenticated fetch calls
160
+ * that need explicit headers (e.g. non-cookie contexts).
161
+ * Returns null if not authenticated.
162
+ */
163
+ export function getAuthHeader() {
164
+ return currentSession ? `Bearer ${currentSession.token}` : null;
165
+ }
@@ -0,0 +1,2 @@
1
+ export { initFromBoot, login, logout, register, isAdmin, isLocalOwner, isAuthenticated, isGuest, getUser, getSession, getAuthHeader, setLocalOwner, } from './auth.svelte';
2
+ export type { AuthUser, AuthSession, BootConfig, GlobalSettings } from './types';
@@ -0,0 +1 @@
1
+ export { initFromBoot, login, logout, register, isAdmin, isLocalOwner, isAuthenticated, isGuest, getUser, getSession, getAuthHeader, setLocalOwner, } from './auth.svelte';
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared auth types — used by both client and server.
3
+ * Kept in sh3-core so the server can import them at build time
4
+ * and the client uses them directly.
5
+ */
6
+ /** Public user shape (never includes passwordHash). */
7
+ export interface AuthUser {
8
+ id: string;
9
+ username: string;
10
+ displayName: string;
11
+ role: 'admin' | 'user';
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ }
15
+ /** Session shape returned to the client. */
16
+ export interface AuthSession {
17
+ token: string;
18
+ userId: string;
19
+ role: 'admin' | 'user';
20
+ expiresAt: number;
21
+ }
22
+ /** Response from GET /api/boot. */
23
+ export interface BootConfig {
24
+ auth: {
25
+ required: boolean;
26
+ guestAllowed: boolean;
27
+ selfRegistration: boolean;
28
+ };
29
+ user: AuthUser | null;
30
+ session: AuthSession | null;
31
+ tenantId: string;
32
+ }
33
+ /** Global settings shape. */
34
+ export interface GlobalSettings {
35
+ auth: {
36
+ required: boolean;
37
+ guestAllowed: boolean;
38
+ sessionTTL: number;
39
+ selfRegistration: boolean;
40
+ };
41
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared auth types — used by both client and server.
3
+ * Kept in sh3-core so the server can import them at build time
4
+ * and the client uses them directly.
5
+ */
6
+ export {};