sh3-core 0.17.2 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Sh3.svelte +59 -4
- package/dist/actions/CommandPalette.svelte +1 -2
- package/dist/actions/listeners.js +12 -1
- package/dist/api.d.ts +4 -0
- package/dist/app/store/storeShard.svelte.js +1 -21
- package/dist/app/store/version.d.ts +11 -0
- package/dist/app/store/version.js +39 -0
- package/dist/app/store/version.test.d.ts +1 -0
- package/dist/app/store/version.test.js +44 -0
- package/dist/apps/lifecycle.d.ts +6 -0
- package/dist/apps/lifecycle.js +5 -2
- package/dist/apps/lifecycle.test.js +30 -0
- package/dist/apps/types.d.ts +12 -0
- package/dist/assets/iconIds.generated.d.ts +1 -1
- package/dist/assets/iconIds.generated.js +5 -0
- package/dist/assets/icons.svg +31 -0
- package/dist/auth/auth.svelte.js +18 -8
- package/dist/auth/types.d.ts +6 -0
- package/dist/chrome/CompactChrome.svelte +54 -20
- package/dist/chrome/CompactChrome.svelte.test.js +112 -5
- package/dist/createShell.d.ts +9 -0
- package/dist/createShell.js +20 -7
- package/dist/createShell.remoteAuth.test.d.ts +1 -0
- package/dist/createShell.remoteAuth.test.js +71 -0
- package/dist/documents/http-backend.js +12 -11
- package/dist/env/client.js +11 -5
- package/dist/files/types.d.ts +106 -0
- package/dist/files/types.js +1 -0
- package/dist/gestures/gestureRegistry.d.ts +6 -0
- package/dist/gestures/gestureRegistry.js +190 -0
- package/dist/gestures/gestureRegistry.test.d.ts +1 -0
- package/dist/gestures/gestureRegistry.test.js +120 -0
- package/dist/gestures/index.d.ts +6 -0
- package/dist/gestures/index.js +12 -0
- package/dist/gestures/pointerClaim.d.ts +7 -0
- package/dist/gestures/pointerClaim.js +36 -0
- package/dist/gestures/pointerClaim.test.d.ts +1 -0
- package/dist/gestures/pointerClaim.test.js +64 -0
- package/dist/gestures/types.d.ts +83 -0
- package/dist/gestures/types.js +1 -0
- package/dist/host-entry.d.ts +1 -0
- package/dist/host-entry.js +1 -0
- package/dist/layout/LayoutRenderer.browser.test.js +15 -3
- package/dist/layout/LayoutRenderer.svelte +16 -3
- package/dist/layout/LayoutRenderer.svelte.d.ts +2 -0
- package/dist/layout/__screenshots__/LayoutRenderer.browser.test.ts/LayoutRenderer-browser---E-3-splitter-drag-updates-split-sizes-when-the-splitter-handle-is-dragged-1.png +0 -0
- package/dist/layout/__screenshots__/LayoutRenderer.browser.test.ts/LayoutRenderer-browser---E-5-splitter-collapse-toggle-toggles-collapsed-i--on-double-click-1.png +0 -0
- package/dist/layout/__screenshots__/LayoutRenderer.browser.test.ts/LayoutRenderer-browser---E-6-fixed-slots-hides-the-collapse-widget-on-a-fixed-pane-but-keeps-it-on-panes-with-a-non-fixed-neighbor-1.png +0 -0
- package/dist/layout/compact/CarouselTabs.svelte +362 -0
- package/dist/layout/compact/CarouselTabs.svelte.d.ts +10 -0
- package/dist/layout/compact/CarouselTabs.svelte.test.d.ts +1 -0
- package/dist/layout/compact/CarouselTabs.svelte.test.js +300 -0
- package/dist/layout/compact/CompactRenderer.svelte +1 -1
- package/dist/layout/compact/CompactRenderer.svelte.test.js +49 -0
- package/dist/layout/compact/derive.js +2 -0
- package/dist/layout/compact/derive.test.js +37 -0
- package/dist/layout/compact/enrichCarousels.d.ts +8 -0
- package/dist/layout/compact/enrichCarousels.js +44 -0
- package/dist/layout/compact/enrichCarousels.test.d.ts +1 -0
- package/dist/layout/compact/enrichCarousels.test.js +88 -0
- package/dist/layout/compact/types.d.ts +3 -0
- package/dist/layout/drag.svelte.js +13 -0
- package/dist/layout/store.schemaVersion.test.js +2 -2
- package/dist/layout/types.d.ts +9 -1
- package/dist/layout/types.js +1 -1
- package/dist/layout/types.test.d.ts +1 -0
- package/dist/layout/types.test.js +26 -0
- package/dist/overlays/ModalFrame.svelte +3 -1
- package/dist/overlays/ModalFrame.svelte.d.ts +1 -0
- package/dist/overlays/floatDismiss.js +5 -0
- package/dist/overlays/focusTrap.d.ts +11 -1
- package/dist/overlays/focusTrap.js +11 -9
- package/dist/overlays/modal.js +1 -0
- package/dist/overlays/popup.js +4 -0
- package/dist/overlays/types.d.ts +9 -0
- package/dist/primitives/Button.svelte +18 -0
- package/dist/primitives/Button.svelte.d.ts +6 -0
- package/dist/primitives/ResizableSplitter.svelte +71 -11
- package/dist/primitives/ResizableSplitter.svelte.d.ts +8 -0
- package/dist/primitives/ResizableSplitter.svelte.test.d.ts +1 -0
- package/dist/primitives/ResizableSplitter.svelte.test.js +74 -0
- package/dist/server-shard/types.d.ts +2 -1
- package/dist/shards/activate.svelte.js +16 -0
- package/dist/shards/ctx-fetch.test.d.ts +1 -0
- package/dist/shards/ctx-fetch.test.js +136 -0
- package/dist/shards/types.d.ts +29 -0
- package/dist/transport/apiFetch.d.ts +1 -0
- package/dist/transport/apiFetch.js +65 -0
- package/dist/transport/apiFetch.test.d.ts +1 -0
- package/dist/transport/apiFetch.test.js +37 -0
- package/dist/transport/authToken.d.ts +2 -0
- package/dist/transport/authToken.js +53 -0
- package/dist/transport/authToken.test.d.ts +1 -0
- package/dist/transport/authToken.test.js +33 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/shards/types.d.ts
CHANGED
|
@@ -205,6 +205,35 @@ export interface ShardContext {
|
|
|
205
205
|
registerVerb(verb: Verb): void;
|
|
206
206
|
/** Obtain a file-oriented document handle scoped to this shard. */
|
|
207
207
|
documents(options: DocumentHandleOptions): DocumentHandle;
|
|
208
|
+
/**
|
|
209
|
+
* Cross-origin-safe HTTP helper. Resolves relative `/api/...` paths
|
|
210
|
+
* against the configured serverUrl. In Tauri, routes through
|
|
211
|
+
* @tauri-apps/plugin-http (no browser CORS, cookies via reqwest).
|
|
212
|
+
* On web, behaves like `fetch` with `credentials: 'include'`.
|
|
213
|
+
*
|
|
214
|
+
* Server-shards must use this instead of global `fetch` to remain
|
|
215
|
+
* compatible with cross-origin clients (e.g. Tauri Android).
|
|
216
|
+
*
|
|
217
|
+
* @param path - Relative `/api/...` path or fully-qualified URL.
|
|
218
|
+
* @param init - Standard RequestInit.
|
|
219
|
+
*/
|
|
220
|
+
fetch(path: string, init?: RequestInit): Promise<Response>;
|
|
221
|
+
/**
|
|
222
|
+
* The configured server base URL (e.g. `https://my-sh3.example.com`).
|
|
223
|
+
* Empty string when running local-only (no remote server).
|
|
224
|
+
* Use this as the `BaseAddress` for non-fetch HTTP clients (e.g. WASM .NET
|
|
225
|
+
* `HttpClient`) that cannot go through `ctx.fetch`.
|
|
226
|
+
*/
|
|
227
|
+
readonly serverUrl: string;
|
|
228
|
+
/**
|
|
229
|
+
* Resolve a path to an absolute URL against the configured server, using
|
|
230
|
+
* the same rules as `ctx.fetch` but without making a request. Useful for
|
|
231
|
+
* WebSocket URLs and any transport that bypasses `ctx.fetch`.
|
|
232
|
+
*
|
|
233
|
+
* @param path - Relative `/api/...` path or fully-qualified URL.
|
|
234
|
+
* @returns Absolute URL string.
|
|
235
|
+
*/
|
|
236
|
+
resolveUrl(path: string): string;
|
|
208
237
|
/**
|
|
209
238
|
* Declare environment state for this shard and receive a hydrated snapshot.
|
|
210
239
|
* Env state is server-authoritative, fetched once at activation, and
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function apiFetch(url: string, init?: RequestInit): Promise<Response>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* apiFetch — single source of truth for HTTP calls against the
|
|
3
|
+
* configured sh3-server, transparently using Tauri's plugin-http
|
|
4
|
+
* when running inside a Tauri webview.
|
|
5
|
+
*
|
|
6
|
+
* Browser fetch enforces CORS and respects SameSite cookie rules,
|
|
7
|
+
* which breaks cross-origin requests from a Tauri webview at e.g.
|
|
8
|
+
* `tauri://localhost` to a remote sh3-server. plugin-http (reqwest
|
|
9
|
+
* under the hood) is not subject to browser CORS and uses a
|
|
10
|
+
* per-host cookie store, so existing same-origin auth keeps working
|
|
11
|
+
* across origins.
|
|
12
|
+
*
|
|
13
|
+
* The plugin-http import is dynamic and behind try/catch — same
|
|
14
|
+
* defensive pattern as `platform/index.ts`. Vite code-splits it
|
|
15
|
+
* into a Tauri-only chunk that never loads in web builds.
|
|
16
|
+
*/
|
|
17
|
+
import { getAuthToken } from './authToken';
|
|
18
|
+
let tauriFetch = null;
|
|
19
|
+
let tauriProbed = false;
|
|
20
|
+
function inTauriRuntime() {
|
|
21
|
+
// The plugin's fetch implementation calls into IPC via window.__TAURI__,
|
|
22
|
+
// so the *package being installed* is not enough — we have to be running
|
|
23
|
+
// inside a Tauri webview where these globals are injected.
|
|
24
|
+
if (typeof window === 'undefined')
|
|
25
|
+
return false;
|
|
26
|
+
return '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
|
|
27
|
+
}
|
|
28
|
+
async function getTauriFetch() {
|
|
29
|
+
if (tauriProbed)
|
|
30
|
+
return tauriFetch;
|
|
31
|
+
tauriProbed = true;
|
|
32
|
+
if (!inTauriRuntime())
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
// Static analysis is skipped so Vite/svelte-package don't try to bundle
|
|
36
|
+
// the optional Tauri-only dependency in pure-web builds.
|
|
37
|
+
const specifier = '@tauri-apps/plugin-http';
|
|
38
|
+
const mod = await import(/* @vite-ignore */ specifier);
|
|
39
|
+
tauriFetch = mod.fetch;
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
tauriFetch = null;
|
|
43
|
+
}
|
|
44
|
+
return tauriFetch;
|
|
45
|
+
}
|
|
46
|
+
export async function apiFetch(url, init) {
|
|
47
|
+
var _a;
|
|
48
|
+
// Inject Authorization: Bearer <session-token> if a session is active
|
|
49
|
+
// and the caller didn't already supply one. Cookies don't survive the
|
|
50
|
+
// cross-origin hop (SameSite=Lax + plugin-http has no cookie store),
|
|
51
|
+
// so the header carries the session for both transports uniformly.
|
|
52
|
+
const token = getAuthToken();
|
|
53
|
+
let finalInit = init !== null && init !== void 0 ? init : {};
|
|
54
|
+
if (token) {
|
|
55
|
+
const headers = new Headers((_a = finalInit.headers) !== null && _a !== void 0 ? _a : {});
|
|
56
|
+
if (!headers.has('Authorization')) {
|
|
57
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
58
|
+
finalInit = Object.assign(Object.assign({}, finalInit), { headers });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const tf = await getTauriFetch();
|
|
62
|
+
if (tf)
|
|
63
|
+
return tf(url, finalInit);
|
|
64
|
+
return fetch(url, Object.assign({ credentials: 'include' }, finalInit));
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
describe('apiFetch', () => {
|
|
3
|
+
let originalFetch;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
originalFetch = globalThis.fetch;
|
|
6
|
+
vi.resetModules();
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
globalThis.fetch = originalFetch;
|
|
10
|
+
});
|
|
11
|
+
it('uses global fetch with credentials:include when Tauri plugin-http is unavailable', async () => {
|
|
12
|
+
const calls = [];
|
|
13
|
+
globalThis.fetch = vi.fn(async (input, init) => {
|
|
14
|
+
calls.push([input, init]);
|
|
15
|
+
return new Response('ok');
|
|
16
|
+
});
|
|
17
|
+
const { apiFetch } = await import('./apiFetch');
|
|
18
|
+
const res = await apiFetch('https://example.com/api/foo', { method: 'GET' });
|
|
19
|
+
expect(await res.text()).toBe('ok');
|
|
20
|
+
expect(calls).toHaveLength(1);
|
|
21
|
+
const [input, init] = calls[0];
|
|
22
|
+
expect(input).toBe('https://example.com/api/foo');
|
|
23
|
+
expect(init.credentials).toBe('include');
|
|
24
|
+
expect(init.method).toBe('GET');
|
|
25
|
+
});
|
|
26
|
+
it('lets caller-provided credentials override the default', async () => {
|
|
27
|
+
const calls = [];
|
|
28
|
+
globalThis.fetch = vi.fn(async (input, init) => {
|
|
29
|
+
calls.push([input, init]);
|
|
30
|
+
return new Response('ok');
|
|
31
|
+
});
|
|
32
|
+
const { apiFetch } = await import('./apiFetch');
|
|
33
|
+
await apiFetch('https://example.com/api/foo', { credentials: 'omit' });
|
|
34
|
+
const [, init] = calls[0];
|
|
35
|
+
expect(init.credentials).toBe('omit');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Auth-token store used by `apiFetch` to attach `Authorization: Bearer
|
|
3
|
+
* <token>` to every request when a session exists.
|
|
4
|
+
*
|
|
5
|
+
* The browser auth flow relies on Set-Cookie + same-origin requests to
|
|
6
|
+
* keep the session alive. That breaks down for cross-origin Tauri
|
|
7
|
+
* clients (e.g. Android): the WebView's origin is `tauri://localhost`
|
|
8
|
+
* and the sh3-server lives on a different domain, so the session
|
|
9
|
+
* cookie is treated as cross-site and dropped under SameSite=Lax. On
|
|
10
|
+
* top of that, `@tauri-apps/plugin-http` (reqwest under the hood)
|
|
11
|
+
* doesn't enable a persistent cookie store by default, so even if
|
|
12
|
+
* SameSite weren't an issue cookies wouldn't survive between calls.
|
|
13
|
+
*
|
|
14
|
+
* Carrying the session token in a header sidesteps both problems.
|
|
15
|
+
* `auth.svelte.ts` populates this store after login/register/initFromBoot
|
|
16
|
+
* and clears it on logout. The token is mirrored to localStorage so an
|
|
17
|
+
* app restart doesn't dump the user back at the sign-in wall.
|
|
18
|
+
*/
|
|
19
|
+
const KEY = 'sh3:authToken';
|
|
20
|
+
let token = null;
|
|
21
|
+
let restored = false;
|
|
22
|
+
function restore() {
|
|
23
|
+
if (restored)
|
|
24
|
+
return;
|
|
25
|
+
restored = true;
|
|
26
|
+
if (typeof localStorage === 'undefined')
|
|
27
|
+
return;
|
|
28
|
+
try {
|
|
29
|
+
token = localStorage.getItem(KEY);
|
|
30
|
+
}
|
|
31
|
+
catch (_a) {
|
|
32
|
+
token = null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function setAuthToken(value) {
|
|
36
|
+
restored = true;
|
|
37
|
+
token = value;
|
|
38
|
+
if (typeof localStorage === 'undefined')
|
|
39
|
+
return;
|
|
40
|
+
try {
|
|
41
|
+
if (value)
|
|
42
|
+
localStorage.setItem(KEY, value);
|
|
43
|
+
else
|
|
44
|
+
localStorage.removeItem(KEY);
|
|
45
|
+
}
|
|
46
|
+
catch (_a) {
|
|
47
|
+
// localStorage may be disabled (private browsing); in-memory copy still works.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function getAuthToken() {
|
|
51
|
+
restore();
|
|
52
|
+
return token;
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, vi } from 'vitest';
|
|
2
|
+
describe('authToken', () => {
|
|
3
|
+
beforeEach(() => {
|
|
4
|
+
vi.resetModules();
|
|
5
|
+
if (typeof localStorage !== 'undefined')
|
|
6
|
+
localStorage.clear();
|
|
7
|
+
});
|
|
8
|
+
it('returns null when nothing stored', async () => {
|
|
9
|
+
const { getAuthToken } = await import('./authToken');
|
|
10
|
+
expect(getAuthToken()).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
it('round-trips set/get', async () => {
|
|
13
|
+
const { setAuthToken, getAuthToken } = await import('./authToken');
|
|
14
|
+
setAuthToken('sh3s_deadbeef');
|
|
15
|
+
expect(getAuthToken()).toBe('sh3s_deadbeef');
|
|
16
|
+
});
|
|
17
|
+
it('persists across module re-imports via localStorage', async () => {
|
|
18
|
+
const first = await import('./authToken');
|
|
19
|
+
first.setAuthToken('sh3s_persisted');
|
|
20
|
+
vi.resetModules();
|
|
21
|
+
const second = await import('./authToken');
|
|
22
|
+
expect(second.getAuthToken()).toBe('sh3s_persisted');
|
|
23
|
+
});
|
|
24
|
+
it('clear removes from storage', async () => {
|
|
25
|
+
const { setAuthToken, getAuthToken } = await import('./authToken');
|
|
26
|
+
setAuthToken('sh3s_x');
|
|
27
|
+
setAuthToken(null);
|
|
28
|
+
expect(getAuthToken()).toBeNull();
|
|
29
|
+
vi.resetModules();
|
|
30
|
+
const reloaded = await import('./authToken');
|
|
31
|
+
expect(reloaded.getAuthToken()).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
});
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.19.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export const VERSION = '0.
|
|
2
|
+
export const VERSION = '0.19.1';
|