sh3-core 0.17.0 → 0.19.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/dist/Sh3.svelte +107 -39
- package/dist/__screenshots__/handheld.browser.test.ts/handheld-viewport-flip-e2e-viewport-override-flips-chrome-and-body-branches-1.png +0 -0
- package/dist/actions/CommandPalette.svelte +1 -2
- package/dist/actions/listActionsFromEntries.test.js +29 -0
- package/dist/actions/listActive.js +2 -0
- package/dist/actions/listeners.js +16 -1
- package/dist/actions/programmatic-dispatch.svelte.test.js +9 -2
- package/dist/actions/types.d.ts +8 -0
- package/dist/api.d.ts +8 -1
- 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 +130 -0
- package/dist/chrome/CompactChrome.svelte.d.ts +3 -0
- package/dist/chrome/CompactChrome.svelte.test.d.ts +1 -0
- package/dist/chrome/CompactChrome.svelte.test.js +174 -0
- package/dist/chrome/MenuSheet.svelte +224 -0
- package/dist/chrome/MenuSheet.svelte.d.ts +7 -0
- package/dist/chrome/MenuSheet.svelte.test.d.ts +1 -0
- package/dist/chrome/MenuSheet.svelte.test.js +46 -0
- 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 +119 -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/handheld.browser.test.d.ts +1 -0
- package/dist/handheld.browser.test.js +90 -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 +27 -3
- package/dist/layout/LayoutRenderer.svelte.d.ts +4 -1
- 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 +361 -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 +53 -0
- package/dist/layout/compact/CompactRenderer.svelte.d.ts +3 -0
- package/dist/layout/compact/CompactRenderer.svelte.test.d.ts +1 -0
- package/dist/layout/compact/CompactRenderer.svelte.test.js +125 -0
- package/dist/layout/compact/derive.d.ts +3 -0
- package/dist/layout/compact/derive.js +157 -0
- package/dist/layout/compact/derive.test.d.ts +1 -0
- package/dist/layout/compact/derive.test.js +197 -0
- package/dist/layout/compact/drawerStore.svelte.d.ts +21 -0
- package/dist/layout/compact/drawerStore.svelte.js +75 -0
- package/dist/layout/compact/drawerStore.svelte.test.d.ts +1 -0
- package/dist/layout/compact/drawerStore.svelte.test.js +43 -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/resolveRole.d.ts +6 -0
- package/dist/layout/compact/resolveRole.js +13 -0
- package/dist/layout/compact/resolveRole.test.d.ts +1 -0
- package/dist/layout/compact/resolveRole.test.js +18 -0
- package/dist/layout/compact/types.d.ts +30 -0
- package/dist/layout/compact/types.js +15 -0
- package/dist/layout/drag.svelte.js +13 -0
- package/dist/layout/presets.compactVariant.test.d.ts +1 -0
- package/dist/layout/presets.compactVariant.test.js +27 -0
- package/dist/layout/presets.d.ts +12 -0
- package/dist/layout/presets.js +16 -0
- package/dist/layout/store.drawers.svelte.test.d.ts +1 -0
- package/dist/layout/store.drawers.svelte.test.js +49 -0
- package/dist/layout/store.schemaVersion.test.d.ts +1 -0
- package/dist/layout/store.schemaVersion.test.js +35 -0
- package/dist/layout/store.svelte.js +52 -2
- package/dist/layout/types.d.ts +51 -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/DrawerSurface.svelte +141 -0
- package/dist/overlays/DrawerSurface.svelte.d.ts +12 -0
- package/dist/overlays/DrawerSurface.svelte.test.d.ts +1 -0
- package/dist/overlays/DrawerSurface.svelte.test.js +67 -0
- package/dist/overlays/ModalFrame.svelte +3 -1
- package/dist/overlays/ModalFrame.svelte.d.ts +1 -0
- package/dist/overlays/OverlayRoots.svelte +12 -9
- 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 +10 -1
- 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/sh3Api/headless.js +9 -1
- package/dist/sh3Api/headless.svelte.test.js +45 -1
- package/dist/sh3Runtime.svelte.d.ts +36 -0
- package/dist/sh3Runtime.svelte.js +33 -0
- package/dist/shards/activate.svelte.js +10 -0
- package/dist/shards/ctx-fetch.test.d.ts +1 -0
- package/dist/shards/ctx-fetch.test.js +66 -0
- package/dist/shards/types.d.ts +22 -1
- package/dist/tokens.css +3 -2
- 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/verbs/types.d.ts +5 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport/classify.d.ts +8 -0
- package/dist/viewport/classify.js +20 -0
- package/dist/viewport/classify.test.d.ts +1 -0
- package/dist/viewport/classify.test.js +32 -0
- package/dist/viewport/store.browser.test.d.ts +1 -0
- package/dist/viewport/store.browser.test.js +33 -0
- package/dist/viewport/store.svelte.d.ts +9 -0
- package/dist/viewport/store.svelte.js +71 -0
- package/dist/viewport/store.svelte.test.d.ts +1 -0
- package/dist/viewport/store.svelte.test.js +54 -0
- package/dist/viewport/types.d.ts +9 -0
- package/dist/viewport/types.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* DOM smoke for MenuSheet — verifies open/closed rendering. The
|
|
3
|
+
* container/item resolution is exercised via the same model functions
|
|
4
|
+
* MenuBar uses; their unit tests cover the resolution semantics so
|
|
5
|
+
* this test only asserts the wrapper structure.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
8
|
+
import { mount, unmount, flushSync } from 'svelte';
|
|
9
|
+
import MenuSheet from './MenuSheet.svelte';
|
|
10
|
+
const MenuSheetAny = MenuSheet;
|
|
11
|
+
let mounted = null;
|
|
12
|
+
let host = null;
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
if (mounted) {
|
|
15
|
+
unmount(mounted);
|
|
16
|
+
mounted = null;
|
|
17
|
+
}
|
|
18
|
+
if (host) {
|
|
19
|
+
host.remove();
|
|
20
|
+
host = null;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
describe('MenuSheet (dom)', () => {
|
|
24
|
+
it('renders nothing when closed', () => {
|
|
25
|
+
host = document.createElement('div');
|
|
26
|
+
document.body.appendChild(host);
|
|
27
|
+
mounted = mount(MenuSheetAny, {
|
|
28
|
+
target: host,
|
|
29
|
+
props: { open: false, onClose: () => { } },
|
|
30
|
+
});
|
|
31
|
+
flushSync();
|
|
32
|
+
expect(host.querySelector('[data-sh3-region="menu-sheet"]')).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
it('renders a sheet with a Cancel button when open', () => {
|
|
35
|
+
host = document.createElement('div');
|
|
36
|
+
document.body.appendChild(host);
|
|
37
|
+
mounted = mount(MenuSheetAny, {
|
|
38
|
+
target: host,
|
|
39
|
+
props: { open: true, onClose: () => { } },
|
|
40
|
+
});
|
|
41
|
+
flushSync();
|
|
42
|
+
const sheet = host.querySelector('[data-sh3-region="menu-sheet"]');
|
|
43
|
+
expect(sheet).not.toBeNull();
|
|
44
|
+
expect(sheet.querySelector('.cancel').textContent).toContain('Cancel');
|
|
45
|
+
});
|
|
46
|
+
});
|
package/dist/createShell.d.ts
CHANGED
|
@@ -22,5 +22,14 @@ export interface Sh3Config {
|
|
|
22
22
|
target?: string | HTMLElement;
|
|
23
23
|
/** Server base URL ('' for same-origin) */
|
|
24
24
|
serverUrl?: string;
|
|
25
|
+
/**
|
|
26
|
+
* When true, override the local-owner short-circuit and run the
|
|
27
|
+
* full server-driven auth flow (boot config fetch, SignInWall when
|
|
28
|
+
* required) against `serverUrl`. Used by Tauri clients connecting
|
|
29
|
+
* to a remote sh3-server (e.g. Android), where Tauri presence makes
|
|
30
|
+
* `platform.localOwner` true even though authentication is server-
|
|
31
|
+
* gated.
|
|
32
|
+
*/
|
|
33
|
+
remoteAuth?: boolean;
|
|
25
34
|
}
|
|
26
35
|
export declare function createShell(config?: Sh3Config): Promise<void>;
|
package/dist/createShell.js
CHANGED
|
@@ -10,8 +10,9 @@ import { mount, unmount } from 'svelte';
|
|
|
10
10
|
import { Sh3 } from './index';
|
|
11
11
|
import { registerShard, registerApp, bootstrap, bootstrapSatellite, __setBackend, setLocalOwner, } from './host';
|
|
12
12
|
import { resolvePlatform } from './platform/index';
|
|
13
|
+
import { apiFetch } from './transport/apiFetch';
|
|
13
14
|
import { hydrateTokenOverrides } from './theme';
|
|
14
|
-
import { __setEnvServerUrl } from './env/index';
|
|
15
|
+
import { __setEnvServerUrl, getEnvServerUrl } from './env/index';
|
|
15
16
|
import { __setActiveScope } from './documents/config';
|
|
16
17
|
import { initFromBoot } from './auth/index';
|
|
17
18
|
import SignInWall from './auth/SignInWall.svelte';
|
|
@@ -83,11 +84,13 @@ export async function createShell(config) {
|
|
|
83
84
|
mount(SatelliteShell, { target, props: { payload: satellite.payload } });
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
|
-
// 3. Fetch boot config (skip for local
|
|
87
|
+
// 3. Fetch boot config (skip for purely-local owners; remoteAuth
|
|
88
|
+
// forces it for cross-origin Tauri clients).
|
|
87
89
|
let bootConfig = null;
|
|
88
|
-
|
|
90
|
+
const useServerAuth = !platform.localOwner || (config === null || config === void 0 ? void 0 : config.remoteAuth) === true;
|
|
91
|
+
if (useServerAuth) {
|
|
89
92
|
try {
|
|
90
|
-
const res = await
|
|
93
|
+
const res = await apiFetch(`${sUrl}/api/boot`);
|
|
91
94
|
if (res.ok) {
|
|
92
95
|
bootConfig = await res.json();
|
|
93
96
|
}
|
|
@@ -97,7 +100,7 @@ export async function createShell(config) {
|
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
// 4. Auth decision point
|
|
100
|
-
if (platform.localOwner) {
|
|
103
|
+
if (platform.localOwner && !(config === null || config === void 0 ? void 0 : config.remoteAuth)) {
|
|
101
104
|
// Local-owner (Tauri/dev): no auth, no sign-in, scope is 'local'.
|
|
102
105
|
// setLocalOwner() already called above — admin is assumed.
|
|
103
106
|
__setActiveScope('local');
|
|
@@ -110,7 +113,7 @@ export async function createShell(config) {
|
|
|
110
113
|
if (!session && auth.required && !auth.guestAllowed) {
|
|
111
114
|
await showSignInWall(target, bootConfig);
|
|
112
115
|
// After successful sign-in, re-fetch boot config
|
|
113
|
-
const res = await
|
|
116
|
+
const res = await apiFetch(`${sUrl}/api/boot`);
|
|
114
117
|
if (res.ok) {
|
|
115
118
|
bootConfig = await res.json();
|
|
116
119
|
initFromBoot(sUrl, bootConfig);
|
|
@@ -150,7 +153,17 @@ async function loadDiscoveredPackages(packages) {
|
|
|
150
153
|
return;
|
|
151
154
|
for (const pkg of packages) {
|
|
152
155
|
try {
|
|
153
|
-
|
|
156
|
+
// Server returns server-relative paths like `/packages/<id>/client.js`.
|
|
157
|
+
// In a cross-origin Tauri client these resolve against the webview
|
|
158
|
+
// origin (`tauri://localhost`) instead of the configured server, so
|
|
159
|
+
// we get the SPA's index.html back and the loader chokes on `<`.
|
|
160
|
+
// Resolve against the active serverUrl and route through apiFetch
|
|
161
|
+
// for the cross-origin-safe transport + bearer header.
|
|
162
|
+
const isAbsolute = pkg.bundleUrl.startsWith('http://') || pkg.bundleUrl.startsWith('https://');
|
|
163
|
+
const base = getEnvServerUrl();
|
|
164
|
+
const sep = pkg.bundleUrl.startsWith('/') ? '' : '/';
|
|
165
|
+
const url = isAbsolute ? pkg.bundleUrl : `${base}${sep}${pkg.bundleUrl}`;
|
|
166
|
+
const res = await apiFetch(url);
|
|
154
167
|
if (!res.ok) {
|
|
155
168
|
console.warn(`[sh3] Failed to fetch discovered package "${pkg.id}": HTTP ${res.status}`);
|
|
156
169
|
continue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
describe('createShell remoteAuth flag', () => {
|
|
3
|
+
let originalFetch;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
originalFetch = globalThis.fetch;
|
|
6
|
+
vi.resetModules();
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
globalThis.fetch = originalFetch;
|
|
10
|
+
vi.doUnmock('./platform/index');
|
|
11
|
+
vi.doUnmock('./host');
|
|
12
|
+
});
|
|
13
|
+
function shortCircuitAfterBoot() {
|
|
14
|
+
// Mock bootstrap so createShell throws right after the boot-config
|
|
15
|
+
// fetch we want to observe — and never reaches mount(Sh3, ...).
|
|
16
|
+
vi.doMock('./host', async () => {
|
|
17
|
+
const actual = await vi.importActual('./host');
|
|
18
|
+
return Object.assign(Object.assign({}, actual), { bootstrap: async () => {
|
|
19
|
+
throw new Error('test-skip-bootstrap');
|
|
20
|
+
} });
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
it('fetches /api/boot when remoteAuth is true even if localOwner is detected', async () => {
|
|
24
|
+
const calls = [];
|
|
25
|
+
globalThis.fetch = vi.fn(async (input) => {
|
|
26
|
+
calls.push(String(input));
|
|
27
|
+
return new Response(JSON.stringify({
|
|
28
|
+
version: '0.18.0',
|
|
29
|
+
tenantId: 't1',
|
|
30
|
+
auth: { required: false, guestAllowed: true, selfRegistration: false },
|
|
31
|
+
session: { token: 'tok', userId: 'u1', role: 'user', expiresAt: Number.MAX_SAFE_INTEGER },
|
|
32
|
+
user: { id: 'u1', username: 'u', displayName: 'U', role: 'user', createdAt: '', updatedAt: '' },
|
|
33
|
+
}), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
34
|
+
});
|
|
35
|
+
vi.doMock('./platform/index', () => ({
|
|
36
|
+
resolvePlatform: async () => ({ backends: null, localOwner: true }),
|
|
37
|
+
}));
|
|
38
|
+
shortCircuitAfterBoot();
|
|
39
|
+
document.body.innerHTML = '<div id="app"></div>';
|
|
40
|
+
const { createShell } = await import('./createShell');
|
|
41
|
+
// The full boot pipeline (mount, bootstrap, etc.) may throw in this
|
|
42
|
+
// test env — we only care that the boot-config fetch was attempted.
|
|
43
|
+
try {
|
|
44
|
+
await createShell({ serverUrl: 'https://remote.example.com', remoteAuth: true });
|
|
45
|
+
}
|
|
46
|
+
catch (_a) {
|
|
47
|
+
// ignore — assertion below is the contract.
|
|
48
|
+
}
|
|
49
|
+
expect(calls.some(u => u === 'https://remote.example.com/api/boot')).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
it('keeps the legacy localOwner short-circuit when remoteAuth is absent', async () => {
|
|
52
|
+
const calls = [];
|
|
53
|
+
globalThis.fetch = vi.fn(async (input) => {
|
|
54
|
+
calls.push(String(input));
|
|
55
|
+
return new Response('ok');
|
|
56
|
+
});
|
|
57
|
+
vi.doMock('./platform/index', () => ({
|
|
58
|
+
resolvePlatform: async () => ({ backends: null, localOwner: true }),
|
|
59
|
+
}));
|
|
60
|
+
shortCircuitAfterBoot();
|
|
61
|
+
document.body.innerHTML = '<div id="app"></div>';
|
|
62
|
+
const { createShell } = await import('./createShell');
|
|
63
|
+
try {
|
|
64
|
+
await createShell({ serverUrl: '' });
|
|
65
|
+
}
|
|
66
|
+
catch (_a) {
|
|
67
|
+
// ignore — assertion below is the contract.
|
|
68
|
+
}
|
|
69
|
+
expect(calls.some(u => u.endsWith('/api/boot'))).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -20,6 +20,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
20
20
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
21
21
|
};
|
|
22
22
|
var _HttpDocumentBackend_instances, _HttpDocumentBackend_baseUrl, _HttpDocumentBackend_apiKey, _HttpDocumentBackend_authHeaders;
|
|
23
|
+
import { apiFetch } from '../transport/apiFetch';
|
|
23
24
|
export class HttpDocumentBackend {
|
|
24
25
|
/**
|
|
25
26
|
* @param baseUrl - The server origin (e.g. 'http://localhost:3000' or window.location.origin).
|
|
@@ -36,7 +37,7 @@ export class HttpDocumentBackend {
|
|
|
36
37
|
async read(tenantId, shardId, path) {
|
|
37
38
|
var _a;
|
|
38
39
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}`;
|
|
39
|
-
const res = await
|
|
40
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
40
41
|
if (res.status === 404)
|
|
41
42
|
return null;
|
|
42
43
|
if (!res.ok)
|
|
@@ -50,45 +51,45 @@ export class HttpDocumentBackend {
|
|
|
50
51
|
async write(tenantId, shardId, path, content) {
|
|
51
52
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}`;
|
|
52
53
|
const headers = Object.assign(Object.assign({}, __classPrivateFieldGet(this, _HttpDocumentBackend_instances, "m", _HttpDocumentBackend_authHeaders).call(this)), { 'Content-Type': typeof content === 'string' ? 'text/plain' : 'application/octet-stream' });
|
|
53
|
-
const res = await
|
|
54
|
+
const res = await apiFetch(url, { method: 'PUT', headers, body: content, credentials: 'include' });
|
|
54
55
|
if (!res.ok)
|
|
55
56
|
throw new Error(`Document write failed: ${res.status}`);
|
|
56
57
|
}
|
|
57
58
|
async delete(tenantId, shardId, path) {
|
|
58
59
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}`;
|
|
59
|
-
const res = await
|
|
60
|
+
const res = await apiFetch(url, { method: 'DELETE', headers: __classPrivateFieldGet(this, _HttpDocumentBackend_instances, "m", _HttpDocumentBackend_authHeaders).call(this), credentials: 'include' });
|
|
60
61
|
if (!res.ok)
|
|
61
62
|
throw new Error(`Document delete failed: ${res.status}`);
|
|
62
63
|
}
|
|
63
64
|
async list(tenantId, shardId) {
|
|
64
65
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}`;
|
|
65
|
-
const res = await
|
|
66
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
66
67
|
if (!res.ok)
|
|
67
68
|
throw new Error(`Document list failed: ${res.status}`);
|
|
68
69
|
return res.json();
|
|
69
70
|
}
|
|
70
71
|
async exists(tenantId, shardId, path) {
|
|
71
72
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}`;
|
|
72
|
-
const res = await
|
|
73
|
+
const res = await apiFetch(url, { method: 'HEAD', credentials: 'include' });
|
|
73
74
|
return res.ok;
|
|
74
75
|
}
|
|
75
76
|
async listAllShards(tenantId) {
|
|
76
77
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/_shards`;
|
|
77
|
-
const res = await
|
|
78
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
78
79
|
if (!res.ok)
|
|
79
80
|
throw new Error(`listAllShards failed: ${res.status}`);
|
|
80
81
|
return res.json();
|
|
81
82
|
}
|
|
82
83
|
async listAllDocuments(tenantId) {
|
|
83
84
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/_all`;
|
|
84
|
-
const res = await
|
|
85
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
85
86
|
if (!res.ok)
|
|
86
87
|
throw new Error(`listAllDocuments failed: ${res.status}`);
|
|
87
88
|
return res.json();
|
|
88
89
|
}
|
|
89
90
|
async readMeta(tenantId, shardId, path) {
|
|
90
91
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}?meta=1`;
|
|
91
|
-
const res = await
|
|
92
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
92
93
|
if (!res.ok)
|
|
93
94
|
throw new Error(`readMeta failed: ${res.status}`);
|
|
94
95
|
const body = await res.json();
|
|
@@ -101,7 +102,7 @@ export class HttpDocumentBackend {
|
|
|
101
102
|
const body = typeof choice === 'string'
|
|
102
103
|
? { choice }
|
|
103
104
|
: { choice: choice.origin };
|
|
104
|
-
const res = await
|
|
105
|
+
const res = await apiFetch(url, {
|
|
105
106
|
method: 'POST',
|
|
106
107
|
credentials: 'include',
|
|
107
108
|
headers: Object.assign(Object.assign({}, __classPrivateFieldGet(this, _HttpDocumentBackend_instances, "m", _HttpDocumentBackend_authHeaders).call(this)), { 'Content-Type': 'application/json' }),
|
|
@@ -112,7 +113,7 @@ export class HttpDocumentBackend {
|
|
|
112
113
|
}
|
|
113
114
|
async readBranch(tenantId, shardId, path, origin) {
|
|
114
115
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${path}/branch?origin=${encodeURIComponent(origin)}`;
|
|
115
|
-
const res = await
|
|
116
|
+
const res = await apiFetch(url, { credentials: 'include' });
|
|
116
117
|
if (res.status === 404)
|
|
117
118
|
return null;
|
|
118
119
|
if (!res.ok)
|
|
@@ -122,7 +123,7 @@ export class HttpDocumentBackend {
|
|
|
122
123
|
async rename(tenantId, shardId, oldPath, newPath) {
|
|
123
124
|
const url = `${__classPrivateFieldGet(this, _HttpDocumentBackend_baseUrl, "f")}/api/docs/${tenantId}/${shardId}/${oldPath}/rename`;
|
|
124
125
|
const headers = Object.assign(Object.assign({}, __classPrivateFieldGet(this, _HttpDocumentBackend_instances, "m", _HttpDocumentBackend_authHeaders).call(this)), { 'Content-Type': 'application/json' });
|
|
125
|
-
const res = await
|
|
126
|
+
const res = await apiFetch(url, {
|
|
126
127
|
method: 'POST',
|
|
127
128
|
headers,
|
|
128
129
|
body: JSON.stringify({ to: newPath }),
|
package/dist/env/client.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* from the server.
|
|
4
4
|
*/
|
|
5
5
|
import { getAuthHeader, isAdmin } from '../auth/index';
|
|
6
|
+
import { apiFetch } from '../transport/apiFetch';
|
|
6
7
|
/** Server base URL, set once during configuration. */
|
|
7
8
|
let serverUrl = '';
|
|
8
9
|
/** Configure the server URL for env state operations. */
|
|
@@ -18,7 +19,9 @@ export function getEnvServerUrl() {
|
|
|
18
19
|
* Returns an empty object if the server has no stored state.
|
|
19
20
|
*/
|
|
20
21
|
export async function fetchEnvState(shardId) {
|
|
21
|
-
const res = await
|
|
22
|
+
const res = await apiFetch(`${serverUrl}/api/env-state/${encodeURIComponent(shardId)}`, {
|
|
23
|
+
credentials: 'omit',
|
|
24
|
+
});
|
|
22
25
|
if (!res.ok) {
|
|
23
26
|
console.warn(`[sh3] Failed to fetch env state for "${shardId}": HTTP ${res.status}`);
|
|
24
27
|
return {};
|
|
@@ -38,10 +41,11 @@ export async function putEnvState(shardId, state) {
|
|
|
38
41
|
const headers = { 'Content-Type': 'application/json' };
|
|
39
42
|
if (auth)
|
|
40
43
|
headers['Authorization'] = auth;
|
|
41
|
-
const res = await
|
|
44
|
+
const res = await apiFetch(`${serverUrl}/api/env-state/${encodeURIComponent(shardId)}`, {
|
|
42
45
|
method: 'PUT',
|
|
43
46
|
headers,
|
|
44
47
|
body: JSON.stringify(state),
|
|
48
|
+
credentials: 'omit',
|
|
45
49
|
});
|
|
46
50
|
if (!res.ok) {
|
|
47
51
|
const body = await res.json().catch(() => ({}));
|
|
@@ -73,10 +77,11 @@ export async function serverInstallPackage(manifest, clientBundle, serverBundle)
|
|
|
73
77
|
const headers = {};
|
|
74
78
|
if (auth)
|
|
75
79
|
headers['Authorization'] = auth;
|
|
76
|
-
const res = await
|
|
80
|
+
const res = await apiFetch(`${serverUrl}/api/packages/install`, {
|
|
77
81
|
method: 'POST',
|
|
78
82
|
headers,
|
|
79
83
|
body: form,
|
|
84
|
+
credentials: 'omit',
|
|
80
85
|
});
|
|
81
86
|
if (!res.ok) {
|
|
82
87
|
let body = {};
|
|
@@ -104,10 +109,11 @@ export async function serverUninstallPackage(id) {
|
|
|
104
109
|
const headers = { 'Content-Type': 'application/json' };
|
|
105
110
|
if (auth)
|
|
106
111
|
headers['Authorization'] = auth;
|
|
107
|
-
const res = await
|
|
112
|
+
const res = await apiFetch(`${serverUrl}/api/packages/uninstall`, {
|
|
108
113
|
method: 'POST',
|
|
109
114
|
headers,
|
|
110
115
|
body: JSON.stringify({ id }),
|
|
116
|
+
credentials: 'omit',
|
|
111
117
|
});
|
|
112
118
|
if (!res.ok) {
|
|
113
119
|
const body = await res.json().catch(() => ({}));
|
|
@@ -118,7 +124,7 @@ export async function serverUninstallPackage(id) {
|
|
|
118
124
|
* Fetch the list of packages installed on the server.
|
|
119
125
|
*/
|
|
120
126
|
export async function fetchServerPackages() {
|
|
121
|
-
const res = await
|
|
127
|
+
const res = await apiFetch(`${serverUrl}/api/packages`, { credentials: 'omit' });
|
|
122
128
|
if (!res.ok)
|
|
123
129
|
return [];
|
|
124
130
|
return await res.json();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reference to a document passed to file handler callbacks and app launch args.
|
|
3
|
+
*/
|
|
4
|
+
export interface FileRef {
|
|
5
|
+
path: string;
|
|
6
|
+
tenantId: string;
|
|
7
|
+
/** True when the file was identified as binary content. */
|
|
8
|
+
binary: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** A single header pattern rule. */
|
|
11
|
+
export type FileHandlerPattern = {
|
|
12
|
+
type: 'startsWith';
|
|
13
|
+
value: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'includes';
|
|
16
|
+
value: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'regex';
|
|
19
|
+
pattern: string;
|
|
20
|
+
flags?: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Optional header-based disambiguation used when multiple handlers share
|
|
24
|
+
* an extension. The dispatcher reads the file head and tests these rules
|
|
25
|
+
* to narrow the candidate set.
|
|
26
|
+
*/
|
|
27
|
+
export interface FileHandlerHeader {
|
|
28
|
+
/**
|
|
29
|
+
* Max bytes/chars to read from the file head.
|
|
30
|
+
* @default 256
|
|
31
|
+
*/
|
|
32
|
+
readBytes?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Declarative patterns tested in order — first match wins.
|
|
35
|
+
* Evaluated before `predicate`.
|
|
36
|
+
*/
|
|
37
|
+
patterns?: FileHandlerPattern[];
|
|
38
|
+
/**
|
|
39
|
+
* Escape-hatch for logic that cannot be expressed as patterns.
|
|
40
|
+
* Receives `string` for text files, `Uint8Array` for binary.
|
|
41
|
+
*/
|
|
42
|
+
predicate?: (header: string | Uint8Array) => boolean;
|
|
43
|
+
}
|
|
44
|
+
/** File matching rules for a handler. */
|
|
45
|
+
export interface FileHandlerMatch {
|
|
46
|
+
/**
|
|
47
|
+
* File extensions this handler claims, e.g. `['.svg', '.svgz']`.
|
|
48
|
+
* Compared case-insensitively by the dispatcher.
|
|
49
|
+
*/
|
|
50
|
+
extensions: string[];
|
|
51
|
+
/**
|
|
52
|
+
* When true, this handler accepts binary files.
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
binary?: boolean;
|
|
56
|
+
/** Optional header rules for disambiguation when extensions collide. */
|
|
57
|
+
header?: FileHandlerHeader;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* How the dispatcher should open the matched file.
|
|
61
|
+
*
|
|
62
|
+
* - `view` — the shard's callback is called; the shard mounts the view
|
|
63
|
+
* itself via its own `ctx` closure. Placement is the dispatcher's concern.
|
|
64
|
+
* - `app` — the dispatcher calls `launchApp(appId, { args: { file } })`.
|
|
65
|
+
* The app reads `ctx.args.file` in `activate()`.
|
|
66
|
+
*/
|
|
67
|
+
export type FileHandlerOpen = {
|
|
68
|
+
type: 'view';
|
|
69
|
+
/**
|
|
70
|
+
* Called by the dispatcher with the resolved file. The shard closes
|
|
71
|
+
* over its own ShardContext — it wires the file to internal state and
|
|
72
|
+
* mounts its view using its existing shell access.
|
|
73
|
+
*/
|
|
74
|
+
open: (file: FileRef) => void | Promise<void>;
|
|
75
|
+
} | {
|
|
76
|
+
type: 'app';
|
|
77
|
+
/** Id of the app to launch. Must be registered. */
|
|
78
|
+
appId: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Descriptor registered at contribution point `sh3.file-handler`.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* ctx.contributions.register('sh3.file-handler', {
|
|
86
|
+
* label: 'SVG Viewer',
|
|
87
|
+
* match: { extensions: ['.svg'] },
|
|
88
|
+
* open: {
|
|
89
|
+
* type: 'view',
|
|
90
|
+
* open: (file) => { pendingFile.set(file); shell.openViewInCurrentLayout(viewId); },
|
|
91
|
+
* },
|
|
92
|
+
* } satisfies FileHandlerDescriptor);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export interface FileHandlerDescriptor {
|
|
96
|
+
/** Human-readable name shown in "open with" UI. */
|
|
97
|
+
label: string;
|
|
98
|
+
match: FileHandlerMatch;
|
|
99
|
+
open: FileHandlerOpen;
|
|
100
|
+
/**
|
|
101
|
+
* Tie-breaking priority. Higher wins when multiple handlers match after
|
|
102
|
+
* extension + header filtering.
|
|
103
|
+
* @default 0
|
|
104
|
+
*/
|
|
105
|
+
priority?: number;
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { GestureOptions, GestureHandle } from './types';
|
|
2
|
+
export interface GestureRegistry {
|
|
3
|
+
register(opts: GestureOptions): GestureHandle;
|
|
4
|
+
destroy(): void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createGestureRegistry(defaultContainer: HTMLElement | null): GestureRegistry;
|