@hosty-sdk/app 0.32.0 → 0.34.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/activity-react.js +8 -8
- package/dist/app-code-exchange.d.ts +8 -0
- package/dist/app-code-exchange.js +31 -0
- package/dist/assets/jetbrains-mono-LICENSE.txt +93 -0
- package/dist/assets/jetbrains-mono-cyrillic.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin.woff2 +0 -0
- package/dist/assets/plex-sans-LICENSE.txt +93 -0
- package/dist/assets/plex-sans-cyrillic.woff2 +0 -0
- package/dist/assets/plex-sans-latin-ext.woff2 +0 -0
- package/dist/assets/plex-sans-latin.woff2 +0 -0
- package/dist/auth-notice.d.ts +4 -4
- package/dist/auth-notice.js +12 -44
- package/dist/browser-auth.d.ts +1 -1
- package/dist/browser-auth.js +1 -1
- package/dist/chrome-mark.d.ts +3 -0
- package/dist/chrome-mark.js +7 -0
- package/dist/core-mark-geometry.d.ts +17 -0
- package/dist/core-mark-geometry.js +8 -0
- package/dist/install-react.js +7 -3
- package/dist/overlay-react.js +41 -25
- package/dist/permissions-react.js +9 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +10 -19
- package/dist/sandbox-react.js +20 -9
- package/dist/sandbox-server.d.ts +2 -1
- package/dist/sandbox-server.js +5 -4
- package/dist/sdk-chrome.d.ts +13 -0
- package/dist/sdk-chrome.js +102 -0
- package/dist/ui-composition.d.ts +2 -2
- package/dist/ui-frame-layer.js +2 -1
- package/dist/ui-frame.js +4 -3
- package/dist/ui-host.d.ts +2 -1
- package/dist/ui-host.js +24 -3
- package/dist/ui-navigation-react.js +11 -11
- package/dist/ui-react.js +22 -18
- package/package.json +4 -3
package/dist/overlay-react.js
CHANGED
|
@@ -7,6 +7,7 @@ import { useAppActivity } from "./activity-react.js";
|
|
|
7
7
|
import { APP_SESSION_ENDED, APP_SESSION_RESTORED, APP_ACTIVITY_RENEWED, acceptAppAuthProtocol } from "./browser-auth.js";
|
|
8
8
|
import { buildCoreOpenUrl, readRecoveryParams } from "./index.js";
|
|
9
9
|
import { permissionReviewUrl, requestPermissionReview } from "./permissions.js";
|
|
10
|
+
import { SdkBrand, SdkChromeStyles, SdkLoader } from "./sdk-chrome.js";
|
|
10
11
|
import { HostyUiRoot } from "./ui-react.js";
|
|
11
12
|
function snapshot(body) {
|
|
12
13
|
const value = body;
|
|
@@ -33,6 +34,14 @@ function sessionReady(session) {
|
|
|
33
34
|
export function HostyOverlay({ children, probePath = "/api/hosty/session", appCodePath = "/api/auth/app-code", uiPath, panelLayout = "auto", localContent, chrome, navigation }) {
|
|
34
35
|
const actor = useRef(null);
|
|
35
36
|
const changingActor = useRef(false);
|
|
37
|
+
const restoration = useRef({ established: false, ready: false, announced: false });
|
|
38
|
+
const announceRestoration = useRef(() => {
|
|
39
|
+
const state = restoration.current;
|
|
40
|
+
if (!state.established || state.ready || state.announced || changingActor.current)
|
|
41
|
+
return;
|
|
42
|
+
state.announced = true;
|
|
43
|
+
window.dispatchEvent(new CustomEvent(APP_SESSION_RESTORED, { detail: { userId: actor.current } }));
|
|
44
|
+
}).current;
|
|
36
45
|
const [session, setSession] = useState(null);
|
|
37
46
|
const [reviewing, setReviewing] = useState(false);
|
|
38
47
|
const renewedAwaitingReadiness = useRef(false);
|
|
@@ -53,7 +62,7 @@ export function HostyOverlay({ children, probePath = "/api/hosty/session", appCo
|
|
|
53
62
|
const next = snapshot(body);
|
|
54
63
|
if (renewedAwaitingReadiness.current && next && sessionReady(next) && next.userId === actor.current && !changingActor.current) {
|
|
55
64
|
renewedAwaitingReadiness.current = false;
|
|
56
|
-
|
|
65
|
+
announceRestoration();
|
|
57
66
|
window.dispatchEvent(new Event(APP_ACTIVITY_RENEWED));
|
|
58
67
|
}
|
|
59
68
|
return body;
|
|
@@ -65,7 +74,7 @@ export function HostyOverlay({ children, probePath = "/api/hosty/session", appCo
|
|
|
65
74
|
renewedAwaitingReadiness.current = !sessionReady(next);
|
|
66
75
|
if (renewedAwaitingReadiness.current)
|
|
67
76
|
return false;
|
|
68
|
-
|
|
77
|
+
announceRestoration();
|
|
69
78
|
return true;
|
|
70
79
|
}).current;
|
|
71
80
|
const activity = useAppActivity(identity.activity ? { ...identity.activity, probePath, appCodePath, validateSession: validate } : null);
|
|
@@ -75,6 +84,18 @@ export function HostyOverlay({ children, probePath = "/api/hosty/session", appCo
|
|
|
75
84
|
const mounted = useRef(false);
|
|
76
85
|
if (ready)
|
|
77
86
|
mounted.current = true;
|
|
87
|
+
useLayoutEffect(() => {
|
|
88
|
+
const state = restoration.current;
|
|
89
|
+
if (!ready) {
|
|
90
|
+
if (state.ready)
|
|
91
|
+
state.announced = false;
|
|
92
|
+
state.ready = false;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
announceRestoration();
|
|
96
|
+
state.established = true;
|
|
97
|
+
state.ready = true;
|
|
98
|
+
}, [ready, announceRestoration]);
|
|
78
99
|
useEffect(() => {
|
|
79
100
|
if (session?.setup === "ready")
|
|
80
101
|
setReviewing(false);
|
|
@@ -168,7 +189,7 @@ export function HostyOverlay({ children, probePath = "/api/hosty/session", appCo
|
|
|
168
189
|
}
|
|
169
190
|
const localOffline = (identity.ui.kind === "unavailable" || (identity.ui.kind === "active" && session?.setup === "unavailable"))
|
|
170
191
|
&& localContent !== undefined;
|
|
171
|
-
return _jsxs(_Fragment, { children: [localOffline && _jsxs("div", { "data-hosty-local-content": true, children: [
|
|
192
|
+
return _jsxs(_Fragment, { children: [localOffline && _jsxs("div", { "data-hosty-local-content": true, children: [_jsxs("div", { "data-hosty-sdk": true, className: "hosty-overlay-offline", role: "status", children: [_jsx(SdkChromeStyles, {}), _jsx("style", { children: styles }), _jsx(SdkBrand, {}), _jsx("span", { children: "Hosty is unavailable. Local content remains available." }), _jsx("button", { type: "button", className: "hosty-sdk-button", onClick: () => { void refreshRef.current(); }, children: "Retry" })] }), localContent] }), _jsx("div", { "data-hosty-content": true, hidden: !ready, inert: !ready, style: ready ? { display: "contents" } : { display: "none" }, children: _jsx(HostyUiRoot, { chrome: chrome, navigation: navigation, uiPath: uiPath, panelLayout: panelLayout, active: ready, children: mounted.current ? children : null }) }), !ready && !localOffline && _jsx(OverlaySurface, { pending: pending, title: title, message: message, action: action, actionLabel: actionLabel, reviewUrl: reviewUrl })] });
|
|
172
193
|
}
|
|
173
194
|
function OverlaySurface({ pending, title, message, action, actionLabel, reviewUrl }) {
|
|
174
195
|
const [portal, setPortal] = useState(null);
|
|
@@ -223,33 +244,28 @@ function OverlaySurface({ pending, title, message, action, actionLabel, reviewUr
|
|
|
223
244
|
return () => { if (element.open && typeof element.close === "function")
|
|
224
245
|
element.close(); };
|
|
225
246
|
}, [portal]);
|
|
226
|
-
const content = _jsxs(_Fragment, { children: [_jsx("style", { children: styles }), _jsx("dialog", { ref: dialog, className: "hosty-overlay-dialog", "aria-label": "Hosty access", tabIndex: -1, onCancel: event => event.preventDefault(), "data-hosty-activity-control": true, children: _jsx("section", { className: "hosty-overlay-card", "aria-live": "polite", "aria-busy": pending, children: pending ? _jsx("div", { className: "hosty-overlay-loading", role: "status", "aria-label": title, children: showProgress && _jsxs(_Fragment, { children: [_jsx(
|
|
227
|
-
return portal ? createPortal(content, portal) :
|
|
247
|
+
const content = _jsxs(_Fragment, { children: [_jsx(SdkChromeStyles, {}), _jsx("style", { children: styles }), _jsx("dialog", { ref: dialog, "data-hosty-sdk": true, className: "hosty-overlay-dialog", "aria-label": "Hosty access", tabIndex: -1, onCancel: event => event.preventDefault(), "data-hosty-activity-control": true, children: _jsx("section", { className: "hosty-overlay-card", "aria-live": "polite", "aria-busy": pending, children: pending ? _jsx("div", { className: "hosty-overlay-loading", role: "status", "aria-label": title, children: showProgress && _jsxs(_Fragment, { children: [_jsx(SdkBrand, {}), _jsx(SdkLoader, {}), _jsx("h1", { children: title }), _jsx("p", { children: message })] }) }) : _jsxs(_Fragment, { children: [_jsx(SdkBrand, {}), _jsx("h1", { children: title }), _jsx("p", { children: message }), action && _jsx("button", { type: "button", className: "hosty-sdk-button hosty-sdk-primary", onClick: action, children: actionLabel }), reviewUrl && _jsx("a", { className: "hosty-overlay-review", href: reviewUrl, target: "_blank", rel: "noopener noreferrer", children: "Open Core permissions" })] }) }) })] });
|
|
248
|
+
return portal ? createPortal(content, portal) : _jsxs("div", { "data-hosty-sdk": true, className: "hosty-overlay-boot", role: "status", "aria-label": "Connecting to Hosty", children: [_jsx(SdkChromeStyles, {}), _jsx("style", { children: styles })] });
|
|
228
249
|
}
|
|
229
250
|
const styles = `
|
|
230
|
-
.hosty-overlay-boot
|
|
231
|
-
html.dark .hosty-overlay-dialog,html[data-hosty-theme=dark] .hosty-overlay-dialog,html.dark .hosty-overlay-boot{--hosty-bg:#14171c;--hosty-fg:#f0f2f5;--hosty-muted:#a2aab7;--hosty-border:#323843;color-scheme:dark}
|
|
232
|
-
.hosty-overlay-boot{position:fixed;inset:0;background:var(--hosty-bg);z-index:2147483647}
|
|
251
|
+
.hosty-overlay-boot{position:fixed;inset:0;background:var(--hs-bg);z-index:2147483647}
|
|
233
252
|
html[data-hosty-overlay-blocked] body>:not([data-hosty-overlay-portal]){visibility:hidden!important}
|
|
234
|
-
html[data-hosty-overlay-blocked],html[data-hosty-overlay-blocked] body{background:#
|
|
235
|
-
html.dark[data-hosty-overlay-blocked],html.dark[data-hosty-overlay-blocked] body{background:#
|
|
253
|
+
html[data-hosty-overlay-blocked],html[data-hosty-overlay-blocked] body{background:#F6F8FB!important}
|
|
254
|
+
html.dark[data-hosty-overlay-blocked],html.dark[data-hosty-overlay-blocked] body,html[data-hosty-theme=dark][data-hosty-overlay-blocked],html[data-hosty-theme=dark][data-hosty-overlay-blocked] body{background:#0F1B2D!important}
|
|
236
255
|
html[data-hosty-launch=embedded][data-hosty-overlay-blocked],html[data-hosty-launch=embedded][data-hosty-overlay-blocked] body{background:transparent!important}
|
|
237
|
-
.hosty-overlay-dialog{position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;
|
|
256
|
+
.hosty-overlay-dialog{position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;margin:0;padding:24px;border:0;background:var(--hs-bg);outline:0}
|
|
238
257
|
.hosty-overlay-dialog[open]{display:grid;place-items:center}
|
|
239
258
|
.hosty-overlay-dialog::backdrop{background:transparent}
|
|
240
259
|
html[data-hosty-launch=embedded] .hosty-overlay-dialog,html[data-hosty-launch=embedded] .hosty-overlay-boot{background:transparent}
|
|
241
|
-
.hosty-overlay-card{width:min(100%,360px);text-align:
|
|
242
|
-
.hosty-overlay-
|
|
243
|
-
.hosty-overlay-
|
|
244
|
-
.hosty-overlay-
|
|
245
|
-
.hosty-overlay-card
|
|
246
|
-
.hosty-overlay-
|
|
247
|
-
.hosty-overlay-
|
|
248
|
-
.hosty-overlay-
|
|
249
|
-
|
|
250
|
-
.hosty-overlay-
|
|
251
|
-
|
|
252
|
-
@keyframes hosty-overlay-spin{to{transform:rotate(360deg)}}
|
|
253
|
-
@keyframes hosty-overlay-enter{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:translateY(0)}}
|
|
254
|
-
@media(prefers-reduced-motion:reduce){.hosty-overlay-card,.hosty-overlay-spinner{animation:none}}
|
|
260
|
+
.hosty-overlay-card{box-sizing:border-box;width:min(100%,360px);padding:24px;border:1px solid var(--hs-border);border-radius:14px;background:var(--hs-card);box-shadow:0 14px 34px -8px #0F1B2D3D;text-align:left;overflow-wrap:anywhere;animation:hosty-overlay-enter 160ms ease-out}
|
|
261
|
+
.hosty-overlay-card .hosty-sdk-brand{margin-bottom:16px}
|
|
262
|
+
.hosty-overlay-card h1{font:600 20px/26px var(--hs-font);letter-spacing:-.02em;margin:0 0 10px;color:var(--hs-fg)}
|
|
263
|
+
.hosty-overlay-card p{font:400 14px/22px var(--hs-font);margin:0 0 20px;color:var(--hs-muted)}
|
|
264
|
+
.hosty-overlay-card .hosty-sdk-button{width:100%}
|
|
265
|
+
.hosty-overlay-review{display:inline-block;color:var(--hs-info);font-size:13px;margin-top:16px;text-decoration:underline;text-underline-offset:3px}
|
|
266
|
+
.hosty-overlay-loading{min-height:64px}.hosty-overlay-loading .hosty-sdk-loader{margin:0 0 16px}.hosty-overlay-loading p{margin-bottom:0}
|
|
267
|
+
.hosty-overlay-offline{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:8px;padding:12px 16px;border:1px solid var(--hs-border);border-radius:10px;background:var(--hs-card);box-shadow:0 4px 14px -4px #0F1B2D29}.hosty-overlay-offline>span:not(.hosty-sdk-brand){flex:1;min-width:180px}
|
|
268
|
+
@keyframes hosty-overlay-enter{from{opacity:0}to{opacity:1}}
|
|
269
|
+
@media(max-width:480px){.hosty-overlay-dialog{padding:16px}.hosty-overlay-card{padding:20px}.hosty-overlay-card h1{font-size:18px;line-height:24px}}
|
|
270
|
+
@media(prefers-reduced-motion:reduce){.hosty-overlay-card{animation:none}}
|
|
255
271
|
`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
+
import { SdkBrand, SdkChromeStyles, SdkIcon, SdkSpinner } from "./sdk-chrome.js";
|
|
4
5
|
import { appFetch } from "./browser-auth.js";
|
|
5
6
|
import { permissionNotice, requestPermissionReview } from "./permissions.js";
|
|
6
7
|
/** App-owned GET endpoint authenticates the viewer and calls readOwnPermissionNotice. */
|
|
@@ -41,8 +42,13 @@ export function MissingPermissionsNotice({ endpoint = "/api/hosty/permissions" }
|
|
|
41
42
|
const kind = state && permissionNotice(state);
|
|
42
43
|
if (dismissed || !kind || !state)
|
|
43
44
|
return null;
|
|
44
|
-
return _jsxs("section", { "data-hosty-activity-control": true, role: "alert", "aria-label": "Required permissions",
|
|
45
|
+
return _jsxs("section", { "data-hosty-sdk": true, "data-hosty-activity-control": true, role: "alert", "aria-label": "Required permissions", className: "hosty-permissions-notice", children: [_jsx(SdkChromeStyles, {}), _jsx("style", { children: styles }), _jsxs("header", { children: [_jsx(SdkBrand, {}), _jsx(SdkIcon, { name: "warning" }), _jsx("strong", { children: "Permissions needed" })] }), kind === "unsupported"
|
|
45
46
|
? _jsxs("p", { children: ["Core does not support required permissions: ", state.permissions.unsupportedRequired.join(", "), ". Update the app or Core."] })
|
|
46
47
|
: _jsx("p", { children: "This app needs required permissions. Operations using them are unavailable until approval." }), kind === "missing" && state.permissions?.reviewAvailable !== false && state.corePublicOrigin &&
|
|
47
|
-
_jsx("button", { type: "button", onClick: () => { requestPermissionReview(state); setPending(true); }, children: "Request permissions" }), pending &&
|
|
48
|
+
_jsx("button", { type: "button", className: "hosty-sdk-button", onClick: () => { requestPermissionReview(state); setPending(true); }, children: "Request permissions" }), pending && _jsxs("p", { className: "hosty-sdk-status", children: [_jsx(SdkSpinner, {}), "Review permissions in Core, then return here. You can leave this app installed without approving."] }), _jsx("button", { type: "button", onClick: () => { setDismissed(true); setPending(false); }, className: "hosty-sdk-button hosty-sdk-ghost", children: "Dismiss" })] });
|
|
48
49
|
}
|
|
50
|
+
const styles = `
|
|
51
|
+
.hosty-permissions-notice{margin:8px;padding:12px 16px;border:1px solid var(--hs-warning-border);border-radius:10px;background:var(--hs-warning-soft);color:var(--hs-fg)}
|
|
52
|
+
.hosty-permissions-notice header{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.hosty-permissions-notice header>.hosty-sdk-icon{color:var(--hs-warning)}
|
|
53
|
+
.hosty-permissions-notice p{margin:8px 0 12px;font-size:13px;line-height:20px}.hosty-permissions-notice>button{margin:0 8px 0 0}
|
|
54
|
+
`;
|
package/dist/react.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export declare function useAppIdentity({ probePath, appCodePath, onSession, }?:
|
|
|
77
77
|
hasBeenActive: boolean;
|
|
78
78
|
refresh: () => Promise<unknown>;
|
|
79
79
|
};
|
|
80
|
-
export declare function AppIdentityBridge({ renderState, children, ...options }?: AppIdentityBridgeProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> |
|
|
80
|
+
export declare function AppIdentityBridge({ renderState, children, ...options }?: AppIdentityBridgeProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
81
81
|
export interface HostThemeBridgeProps {
|
|
82
82
|
/**
|
|
83
83
|
* Whether the operating system decides the theme while no shell has spoken — `true` unless the
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { exchangeAppCode } from "./app-code-exchange.js";
|
|
3
4
|
import { captureChromeHints } from "./ui-composition.js";
|
|
4
5
|
import { replaceConsumedUrl } from "./consumed-url.js";
|
|
5
6
|
// React slice: the client identity bridge — probe, silent recovery, and the fallback
|
|
@@ -8,7 +9,7 @@ import { replaceConsumedUrl } from "./consumed-url.js";
|
|
|
8
9
|
import { readAppContinuity } from "./continuity.js";
|
|
9
10
|
import { configureAppContinuity } from "./continuity-browser.js";
|
|
10
11
|
import { AppActivityBridge } from "./activity-react.js";
|
|
11
|
-
import { AuthNotice, AuthNoticeButton
|
|
12
|
+
import { AuthNotice, AuthNoticeButton } from "./auth-notice.js";
|
|
12
13
|
import { useEffect, useRef, useState } from "react";
|
|
13
14
|
import { appFetch, appSessionActive, appGrantRevision, rememberAppGrant, restoreAppGrant, forgetRejectedAppGrant, openAppSignIn, APP_SESSION_ENDED } from "./browser-auth.js";
|
|
14
15
|
import { acceptAppAuthProtocol, createAppAuthAttempt, persistAppAuthAttempt, takeAppAuthAttempt, submitAppAuthIntent, appAuthNavigationUrl, APP_AUTH_ATTEMPT_PREFIX } from "./browser-auth.js";
|
|
@@ -359,12 +360,8 @@ export function useAppIdentity({ probePath = "/api/auth/identity", appCodePath =
|
|
|
359
360
|
const result = openAppSignIn(openUrl, controller.signal, protocol, mode === "native", probePath);
|
|
360
361
|
setUi({ kind: "recovering" });
|
|
361
362
|
void result.then(async (proof) => {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
body: JSON.stringify(proof),
|
|
365
|
-
}, false);
|
|
366
|
-
const body = await response.json();
|
|
367
|
-
if (!response.ok)
|
|
363
|
+
const { ok, body } = await exchangeAppCode(appCodePath, proof, controller.signal);
|
|
364
|
+
if (!ok)
|
|
368
365
|
throw new Error("Hosty could not establish this app session.");
|
|
369
366
|
if (cancelled)
|
|
370
367
|
return;
|
|
@@ -372,7 +369,7 @@ export function useAppIdentity({ probePath = "/api/auth/identity", appCodePath =
|
|
|
372
369
|
await probeAndRecover();
|
|
373
370
|
return;
|
|
374
371
|
}
|
|
375
|
-
if (typeof body
|
|
372
|
+
if (typeof body?.accessToken === "string" && body.accessToken)
|
|
376
373
|
rememberAppGrant(body.accessToken);
|
|
377
374
|
silentError.current = null;
|
|
378
375
|
writeGuard(false);
|
|
@@ -410,24 +407,18 @@ export function useAppIdentity({ probePath = "/api/auth/identity", appCodePath =
|
|
|
410
407
|
exchangeRef.current = {
|
|
411
408
|
path: appCodePath,
|
|
412
409
|
revision: appGrantRevision(),
|
|
413
|
-
response:
|
|
414
|
-
method: "POST",
|
|
415
|
-
headers: { "Content-Type": "application/json" },
|
|
416
|
-
body: JSON.stringify({ code, codeVerifier: attempt.codeVerifier }),
|
|
417
|
-
credentials: "same-origin", redirect: "error",
|
|
418
|
-
}),
|
|
410
|
+
response: exchangeAppCode(appCodePath, { code, codeVerifier: attempt.codeVerifier }),
|
|
419
411
|
};
|
|
420
412
|
}
|
|
421
413
|
const exchange = exchangeRef.current;
|
|
422
414
|
if (exchange && exchange.path === appCodePath) {
|
|
423
415
|
void exchange.response
|
|
424
|
-
.then(async (
|
|
416
|
+
.then(async ({ ok, body }) => {
|
|
425
417
|
if (cancelled) {
|
|
426
418
|
return;
|
|
427
419
|
}
|
|
428
|
-
if (
|
|
420
|
+
if (ok) {
|
|
429
421
|
writeGuard(false);
|
|
430
|
-
const body = await response.json().catch(() => null);
|
|
431
422
|
if (cancelled)
|
|
432
423
|
return;
|
|
433
424
|
if (exchange.revision !== appGrantRevision()) {
|
|
@@ -474,8 +465,8 @@ export function AppIdentityBridge({ renderState, children, ...options } = {}) {
|
|
|
474
465
|
if (ui.kind === "active")
|
|
475
466
|
return children ?? null;
|
|
476
467
|
if (ui.kind === "recovering")
|
|
477
|
-
return _jsx(AuthNotice, { children: "Connecting to Hosty\u2026" });
|
|
478
|
-
return (_jsx(AuthNotice, { children: ui.kind === "signin" ? (_jsxs(_Fragment, { children: [_jsx("span", { children: ui.error ?? "Sign in through Hosty to use this app." }), ui.signIn ? _jsx(AuthNoticeButton, { onClick: ui.signIn, children: "Sign in via Hosty" }) : ui.openUrl ? (_jsx("a", { href: ui.openUrl, ...(ui.embedded ? { target: "_blank", rel: "noopener noreferrer" } : {}),
|
|
468
|
+
return _jsx(AuthNotice, { busy: true, children: "Connecting to Hosty\u2026" });
|
|
469
|
+
return (_jsx(AuthNotice, { children: ui.kind === "signin" ? (_jsxs(_Fragment, { children: [_jsx("span", { children: ui.error ?? "Sign in through Hosty to use this app." }), ui.signIn ? _jsx(AuthNoticeButton, { onClick: ui.signIn, children: "Sign in via Hosty" }) : ui.openUrl ? (_jsx("a", { href: ui.openUrl, ...(ui.embedded ? { target: "_blank", rel: "noopener noreferrer" } : {}), className: "hosty-sdk-button hosty-sdk-primary", children: "Sign in via Hosty" })) : (_jsx("span", { children: "Open this app from the machine running Hosty, or configure a public origin." }))] })) : ui.kind === "denied" ? (_jsx("span", { children: "You are signed in to Hosty but are not allowed to use this app." })) : ui.kind === "misconfigured" ? (_jsx("span", { children: "This app is not configured correctly on the host. Contact the administrator." })) : (_jsxs(_Fragment, { children: [_jsx("span", { children: "Can\u2019t reach Hosty right now." }), _jsx(AuthNoticeButton, { onClick: () => window.location.reload(), children: "Retry" })] })) }));
|
|
479
470
|
}
|
|
480
471
|
function readStoredTheme(key) {
|
|
481
472
|
try {
|
package/dist/sandbox-react.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
|
|
5
|
-
const
|
|
4
|
+
import { SdkChromeStyles, SdkProgress, SdkSpinner } from "./sdk-chrome.js";
|
|
5
|
+
const button = "hosty-sdk-button";
|
|
6
|
+
const field = "hosty-sdk-input";
|
|
6
7
|
function message(error) { return error instanceof Error ? error.message : "Sandbox request failed."; }
|
|
7
8
|
function link(value) {
|
|
8
9
|
try {
|
|
@@ -161,16 +162,16 @@ export function CoreEnvironmentPanel({ request, storageKey, workspace, workspace
|
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
const disabled = busy || pending !== null;
|
|
164
|
-
return _jsxs("section", {
|
|
165
|
+
return _jsxs("section", { "data-hosty-sdk": true, className: "hosty-sandbox", "aria-label": "Sandbox environments", children: [_jsx(SdkChromeStyles, {}), _jsx("style", { children: styles }), _jsxs("header", { className: "hosty-sandbox-header", children: [_jsxs("div", { children: [_jsx("h3", { className: "hosty-sandbox-title", children: "Sandbox environments" }), _jsx("p", { className: "hosty-sandbox-muted", children: "Separate Core instances with their own apps, users and temporary data." })] }), _jsxs("div", { className: "hosty-sandbox-actions", children: [_jsx("button", { className: button, onClick: () => { setError(""); void refresh(); }, children: "Refresh sandboxes" }), workspace && _jsx("button", { className: button, disabled: disabled || !workspace.worktrees.some(t => t.state === "active"), onClick: () => setCreating(!creating), children: "Create sandbox" })] })] }), busy && _jsx(SdkProgress, { label: "Sandbox operation in progress" }), creating && workspace && _jsx(CreateEnvironment, { workspace: workspace, disabled: disabled, onCreate: create, onCancel: () => setCreating(false) }), notice && _jsx("p", { role: "status", className: "hosty-sandbox-muted", children: notice }), (error || readError) && _jsx("p", { role: "alert", className: "hosty-sandbox-error", children: error || readError }), pending && _jsxs("div", { className: "hosty-sandbox-pending", children: [_jsxs("span", { children: [busy && _jsx(SdkSpinner, {}), busy ? `Sandbox ${pending.kind} is in progress…` : "The request outcome is not confirmed."] }), _jsx("button", { className: button, disabled: busy, onClick: () => void run(pending), children: "Retry same request" })] }), loading ? _jsxs("p", { role: "status", className: "hosty-sdk-status", children: [_jsx(SdkSpinner, {}), "Loading sandboxes\u2026"] }) : !environments.length && !error && !readError && _jsx("p", { className: "hosty-sandbox-muted", children: "No active sandbox environments." }), !workspace && consents.length > 0 && _jsxs("details", { className: "hosty-sandbox-box", children: [_jsxs("summary", { className: "hosty-sandbox-summary", children: ["Saved launch permissions (", consents.length, ")"] }), _jsx("p", { className: "hosty-sandbox-fine", children: "Revocation affects all matching launches and delegated access. Running children and their own accounts remain; use Stop or Delete sandbox to end them." }), _jsx("ul", { className: "hosty-sandbox-list", children: consents.map(grant => _jsxs("li", { className: "hosty-sandbox-consent", children: [_jsxs("p", { children: [grant.appId, " \u00B7 ", grant.mode, " \u00B7 ", grant.state] }), _jsx("p", { className: "hosty-sandbox-path", children: grant.target }), _jsxs("button", { className: button, disabled: disabled, onClick: () => { setBusy(true); void request(`/consents/${grant.id}/revoke`, {}).then(() => refresh()).catch(cause => setError(message(cause))).finally(() => setBusy(false)); }, children: ["Revoke permission for ", grant.appId] })] }, grant.id)) })] }), environments.map(item => _jsxs("article", { className: "hosty-sandbox-box", "aria-label": `Sandbox ${item.label}`, children: [_jsxs("header", { className: "hosty-sandbox-header", children: [_jsxs("div", { children: [_jsxs("h4", { className: "hosty-sandbox-title", children: [item.label, " ", _jsx("span", { className: "hosty-sandbox-state", children: item.state })] }), _jsxs("p", { className: "hosty-sandbox-fine", children: [item.mode === "source" ? "Core built from workspace source" : item.mode === "release" ? "Installed Core release" : "Current Core build", item.context?.workspaceId && workspaceHref && _jsxs(_Fragment, { children: [" \u00B7 ", _jsx("a", { className: "hosty-sandbox-link", href: workspaceHref(item.context.workspaceId), children: "Open workspace" })] })] })] }), _jsxs("div", { className: "hosty-sandbox-actions", children: [item.state === "running" && link(item.previewUrl) && _jsx("a", { className: button, href: item.previewUrl + "/login", target: "_blank", rel: "noreferrer", children: "Open Core" }), _jsx("button", { className: button, disabled: disabled || ["building", "starting", "stopping", "finishing", "cleanup-failed"].includes(item.state), onClick: () => void command(item, item.state === "running" ? "stop" : "start"), children: item.state === "running" ? "Stop" : "Start" }), _jsx("button", { className: button + " hosty-sdk-danger", disabled: disabled || item.state === "finishing", onClick: () => setRemoving(item.id), children: item.state === "cleanup-failed" ? "Retry deletion" : "Delete sandbox" })] })] }), item.limits && _jsxs("p", { className: "hosty-sandbox-fine", children: ["Reserved: ", (item.limits.memoryBytes / 1073741824).toFixed(1), " GiB container memory \u00B7 ", item.limits.cpus, " CPUs \u00B7 ", item.limits.pids, " PIDs \u00B7 ", (item.limits.diskBytes / 1073741824).toFixed(1), " GiB soft disk limit. Released after deletion."] }), item.usage && _jsx("p", { className: "hosty-sandbox-fine", children: item.usage.state === "unknown" ? "Resource usage unavailable; the reservation remains active." : `Observed: ${(item.usage.containerMemoryBytes / 1048576).toFixed(0)} MiB containers · ${(item.usage.coreMemoryBytes / 1048576).toFixed(0)} MiB Core process · ${(item.usage.ownedDiskBytes / 1073741824).toFixed(2)} GiB owned data.` }), item.access && _jsxs("div", { className: "hosty-sandbox-consent", "aria-label": "Sandbox consent", children: [_jsx("p", { children: item.access.state === "operator" ? "Operator launch" : item.access.state === "active" ? item.access.saved ? "Saved launch permission" : "Permission for this run" : item.access.state === "target-changed" ? "Core target changed or unavailable; review launch permission" : "Launch permission revoked or unavailable" }), _jsx("p", { className: "hosty-sandbox-fine", children: item.access.description }), item.access.grantId && ["active", "target-changed"].includes(item.access.state) && _jsx("button", { className: button, disabled: disabled, onClick: () => { setBusy(true); void request(`/${item.id}/consent/revoke`, {}).then(() => refresh()).catch(cause => setError(message(cause))).finally(() => setBusy(false)); }, children: "Revoke launch permission" })] }), item.error && _jsx("p", { role: "alert", className: "hosty-sandbox-error", children: item.error }), item.state === "running" && _jsxs(_Fragment, { children: [_jsx(EnvironmentApplications, { value: apps[item.id] }), apps[item.id] && ["setup-required", "sign-in-required"].includes(apps[item.id].state) && _jsx(SetupAccount, { request: request, id: item.id, disabled: disabled, onDone: () => refresh() })] }), removing === item.id && _jsxs("div", { role: "alertdialog", "aria-label": `Delete ${item.label}`, className: "hosty-sandbox-confirm", children: [_jsx("p", { className: "hosty-sandbox-text", children: "Permanently delete this sandbox, all its apps, test users, data and caches? Workspace source and shared folders are preserved." }), _jsxs("div", { className: "hosty-sandbox-actions", children: [_jsx("button", { className: button + " hosty-sdk-danger", disabled: disabled, onClick: () => { setRemoving(null); void command(item, "finish"); }, children: "Delete permanently" }), _jsx("button", { className: button, onClick: () => setRemoving(null), children: "Cancel" })] })] })] }, item.id))] });
|
|
165
166
|
}
|
|
166
167
|
function EnvironmentApplications({ value }) {
|
|
167
168
|
if (!value)
|
|
168
|
-
return
|
|
169
|
+
return _jsxs("p", { role: "status", className: "hosty-sdk-status", children: [_jsx(SdkSpinner, {}), "Reading application status\u2026"] });
|
|
169
170
|
if (value.state !== "ready")
|
|
170
|
-
return _jsx("p", { role: "status", className: "
|
|
171
|
+
return _jsx("p", { role: "status", className: "hosty-sandbox-muted", children: value.error ?? (value.state === "setup-required" ? "Set up a test administrator for this fresh Core." : "Application status is unavailable.") });
|
|
171
172
|
if (!value.apps.length)
|
|
172
|
-
return _jsx("p", { className: "
|
|
173
|
-
return _jsx("ul", { className: "
|
|
173
|
+
return _jsx("p", { className: "hosty-sandbox-muted", children: "No apps installed in this sandbox yet." });
|
|
174
|
+
return _jsx("ul", { className: "hosty-sandbox-list", "aria-label": "Sandbox applications", children: value.apps.map(app => _jsxs("li", { className: "hosty-sandbox-app", children: [_jsxs("div", { children: [_jsx("span", { className: "hosty-sandbox-title", children: app.displayName }), _jsxs("span", { className: "hosty-sandbox-app-state", children: [app.runtimeState, " \u00B7 ", app.health ?? "Health unknown"] })] }), app.runtimeState === "running" && link(app.previewUrl) && _jsxs("a", { className: button, href: app.previewUrl, target: "_blank", rel: "noreferrer", children: ["Open preview", _jsxs("span", { className: "hosty-sdk-sr-only", children: [" for ", app.displayName] })] })] }, app.id)) });
|
|
174
175
|
}
|
|
175
176
|
function CreateEnvironment({ workspace, disabled, onCreate, onCancel }) {
|
|
176
177
|
const trees = workspace.worktrees.filter(t => t.state === "active");
|
|
@@ -182,7 +183,7 @@ function CreateEnvironment({ workspace, disabled, onCreate, onCancel }) {
|
|
|
182
183
|
void onCreate({ label: form.get("label"), workspaceId: workspace.id, worktreeIds: selected,
|
|
183
184
|
...(source ? { coreWorktreeId: form.get("coreWorktreeId"), coreProject: form.get("coreProject") } : {}) });
|
|
184
185
|
}
|
|
185
|
-
return _jsxs("form", { onSubmit: submit, className: "
|
|
186
|
+
return _jsxs("form", { onSubmit: submit, className: "hosty-sandbox-form", "aria-label": "Create workspace sandbox", children: [_jsxs("label", { className: "hosty-sandbox-field", children: ["Sandbox name", _jsx("input", { className: field, name: "label", required: true, maxLength: 120, defaultValue: "Workspace sandbox" })] }), _jsxs("fieldset", { className: "hosty-sandbox-group", children: [_jsx("legend", { className: "hosty-sandbox-legend", children: "Attached worktrees" }), trees.map(t => _jsxs("label", { className: "hosty-sandbox-check", children: [_jsx("input", { type: "checkbox", checked: selected.includes(t.id), onChange: e => setSelected(old => e.target.checked ? [...old, t.id] : old.filter(id => id !== t.id)) }), t.label] }, t.id))] }), _jsxs("label", { className: "hosty-sandbox-check", children: [_jsx("input", { type: "checkbox", checked: source, onChange: e => setSource(e.target.checked) }), "Build Core from a worktree"] }), source && _jsxs("div", { className: "hosty-sandbox-fields", children: [_jsxs("label", { className: "hosty-sandbox-field", children: ["Core worktree", _jsx("select", { className: field, name: "coreWorktreeId", required: true, children: trees.filter(t => selected.includes(t.id)).map(t => _jsx("option", { value: t.id, children: t.label }, t.id)) })] }), _jsxs("label", { className: "hosty-sandbox-field", children: ["Core project, relative to worktree", _jsx("input", { className: field, name: "coreProject", required: true, defaultValue: "apps/core/src/Haas.Hosty.Core/Haas.Hosty.Core.csproj" })] })] }), _jsx("p", { className: "hosty-sandbox-fine", children: "Starts a fresh Core with separate users and data. Attached worktrees stay available until the sandbox is deleted." }), _jsxs("div", { className: "hosty-sandbox-actions", children: [_jsx("button", { className: button, type: "submit", disabled: disabled || selected.length === 0 || selected.length > 16, children: "Create and start" }), _jsx("button", { className: button, type: "button", onClick: onCancel, children: "Cancel" })] })] });
|
|
186
187
|
}
|
|
187
188
|
function SetupAccount({ request, id, disabled, onDone }) {
|
|
188
189
|
const [error, setError] = useState("");
|
|
@@ -207,5 +208,15 @@ function SetupAccount({ request, id, disabled, onDone }) {
|
|
|
207
208
|
setBusy(false);
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
|
-
return _jsxs("form", { onSubmit: submit, "aria-label": "Sandbox administrator", className: "
|
|
211
|
+
return _jsxs("form", { onSubmit: submit, "aria-label": "Sandbox administrator", className: "hosty-sandbox-box", children: [_jsx("p", { className: "hosty-sandbox-text", children: "Use a separate sandbox administrator. For an existing Core, enter its current account. Parent credentials are not copied." }), _jsxs("div", { className: "hosty-sandbox-fields", children: [_jsxs("label", { className: "hosty-sandbox-text", children: ["Display name", _jsx("input", { className: field, name: "displayName", required: true, autoComplete: "off" })] }), _jsxs("label", { className: "hosty-sandbox-text", children: ["Test email", _jsx("input", { className: field, type: "email", name: "email", required: true, autoComplete: "off" })] }), _jsxs("label", { className: "hosty-sandbox-text", children: ["Test password", _jsx("input", { className: field, type: "password", name: "password", minLength: 12, required: true, autoComplete: "new-password" })] })] }), error && _jsx("p", { role: "alert", className: "hosty-sandbox-error", children: error }), _jsx("button", { className: button, disabled: disabled || busy, children: busy ? "Connecting…" : "Connect test account" })] });
|
|
211
212
|
}
|
|
213
|
+
const styles = `
|
|
214
|
+
.hosty-sandbox{padding:16px;border:1px solid var(--hs-border);border-radius:10px;background:var(--hs-card);min-width:0}
|
|
215
|
+
.hosty-sandbox>:not(style)+:not(style){margin-top:16px}.hosty-sandbox .hosty-sandbox-header{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:12px}.hosty-sandbox :where(h3,h4,p){margin:0}.hosty-sandbox h3{font:600 16px/24px var(--hs-font)}.hosty-sandbox h4{font:500 14px/22px var(--hs-font)}.hosty-sandbox :where(header,article,form)>p{margin-top:8px}.hosty-sandbox .hosty-sandbox-title{font-weight:500}
|
|
216
|
+
.hosty-sandbox .hosty-sandbox-muted{color:var(--hs-muted);font-size:13px;line-height:20px}.hosty-sandbox .hosty-sandbox-fine{color:var(--hs-muted);font-size:12px;line-height:20px}.hosty-sandbox .hosty-sandbox-path{overflow-wrap:anywhere;color:var(--hs-muted);font:400 12px/20px var(--hs-mono)}
|
|
217
|
+
.hosty-sandbox .hosty-sandbox-actions{display:flex;align-items:center;flex-wrap:wrap;gap:8px}.hosty-sandbox .hosty-sandbox-box,.hosty-sandbox .hosty-sandbox-form,.hosty-sandbox .hosty-sandbox-confirm{border:1px solid var(--hs-border);border-radius:10px;padding:12px;min-width:0}.hosty-sandbox .hosty-sandbox-box>:not(:first-child){margin-top:12px}.hosty-sandbox .hosty-sandbox-form{background:var(--hs-bg);display:flex;flex-direction:column;gap:12px}.hosty-sandbox .hosty-sandbox-confirm{background:var(--hs-danger-soft);border-color:var(--hs-danger);margin-top:12px}.hosty-sandbox-confirm>.hosty-sandbox-actions{margin-top:12px}
|
|
218
|
+
.hosty-sandbox .hosty-sandbox-error{padding:10px 12px;border:1px solid var(--hs-danger);border-radius:8px;color:var(--hs-danger);background:var(--hs-danger-soft)}.hosty-sandbox .hosty-sandbox-pending{display:flex;align-items:center;flex-wrap:wrap;gap:12px}.hosty-sandbox-pending>span{display:flex;align-items:center;gap:8px}.hosty-sandbox .hosty-sandbox-state{display:inline-block;padding:1px 6px;margin-left:8px;border:1px solid var(--hs-border);border-radius:6px;color:var(--hs-muted);font:400 12px/18px var(--hs-font)}
|
|
219
|
+
.hosty-sandbox .hosty-sandbox-list{list-style:none;padding:0;margin:0}.hosty-sandbox .hosty-sandbox-list>li+li{border-top:1px solid var(--hs-border)}.hosty-sandbox .hosty-sandbox-consent{display:flex;flex-direction:column;align-items:flex-start;gap:8px;padding:12px 0}.hosty-sandbox .hosty-sandbox-app{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;padding:10px 0}.hosty-sandbox-app-state{color:var(--hs-muted);margin-left:8px}
|
|
220
|
+
.hosty-sandbox .hosty-sandbox-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr));gap:12px}.hosty-sandbox .hosty-sandbox-field,.hosty-sandbox .hosty-sandbox-fields>label{display:flex;flex-direction:column;gap:6px;font:500 13px/20px var(--hs-font);min-width:0}.hosty-sandbox .hosty-sandbox-check{display:flex;align-items:flex-start;gap:8px;font-size:14px}.hosty-sandbox input[type=checkbox]{flex:none;width:16px;height:16px;margin:3px 0 0;accent-color:var(--hs-brand)}.hosty-sandbox input[type=checkbox]:focus-visible{outline:2px solid var(--hs-brand);outline-offset:2px}
|
|
221
|
+
.hosty-sandbox .hosty-sandbox-group{min-width:0;border:0;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.hosty-sandbox legend{font:500 13px/20px var(--hs-font);margin-bottom:8px}.hosty-sandbox .hosty-sandbox-summary{cursor:pointer;font-weight:500}.hosty-sandbox .hosty-sandbox-link{color:var(--hs-info);text-decoration:underline;text-underline-offset:3px}
|
|
222
|
+
`;
|
package/dist/sandbox-server.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ export declare class SandboxClient {
|
|
|
131
131
|
}): Promise<SandboxInstance>;
|
|
132
132
|
call<T = unknown>(action: SandboxAction, input: Record<string, unknown>): Promise<T>;
|
|
133
133
|
}
|
|
134
|
-
export declare const coreEnvironmentActions: readonly ["environment-consent", "environment-create", "environment-list", "environment-status", "environment-start", "environment-stop", "environment-restart", "environment-finish", "environment-setup", "environment-api"];
|
|
134
|
+
export declare const coreEnvironmentActions: readonly ["environment-consent", "environment-create", "environment-list", "environment-status", "environment-start", "environment-stop", "environment-restart", "environment-finish", "environment-setup", "environment-api", "environment-initialization", "environment-initialization-resume", "environment-setup-link"];
|
|
135
135
|
export type CoreEnvironmentAction = typeof coreEnvironmentActions[number];
|
|
136
136
|
export interface CoreEnvironmentSavedConsent {
|
|
137
137
|
id: string;
|
|
@@ -152,6 +152,7 @@ export interface CoreEnvironment {
|
|
|
152
152
|
port: number;
|
|
153
153
|
dataRoot?: string;
|
|
154
154
|
previewUrl: string;
|
|
155
|
+
initializationRequested?: boolean;
|
|
155
156
|
process?: {
|
|
156
157
|
pid: number;
|
|
157
158
|
startedAt: string;
|
package/dist/sandbox-server.js
CHANGED
|
@@ -94,7 +94,7 @@ export class SandboxClient {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
export const coreEnvironmentActions = ["environment-consent", "environment-create", "environment-list", "environment-status", "environment-start",
|
|
97
|
-
"environment-stop", "environment-restart", "environment-finish", "environment-setup", "environment-api"];
|
|
97
|
+
"environment-stop", "environment-restart", "environment-finish", "environment-setup", "environment-api", "environment-initialization", "environment-initialization-resume", "environment-setup-link"];
|
|
98
98
|
/** Full child Core transport. Requires core.environments permissions and live administrator authority.
|
|
99
99
|
* Setup uses ordinary password authentication. Parent credentials are never forwarded to the child. */
|
|
100
100
|
export class CoreEnvironmentClient {
|
|
@@ -115,15 +115,16 @@ export class CoreEnvironmentClient {
|
|
|
115
115
|
if (!coreEnvironmentActions.includes(action))
|
|
116
116
|
throw new SandboxError("environment_operation_invalid", "Unknown environment operation.", 400);
|
|
117
117
|
const { environmentId, ...body } = input;
|
|
118
|
-
const read = action === "environment-list" || action === "environment-status";
|
|
118
|
+
const read = action === "environment-list" || action === "environment-status" || action === "environment-initialization";
|
|
119
119
|
let suffix = action === "environment-consent" ? "/consent" : "";
|
|
120
120
|
if (action !== "environment-list" && action !== "environment-create" && action !== "environment-consent") {
|
|
121
121
|
if (typeof environmentId !== "string" || !/^[a-f0-9]{32}$/.test(environmentId))
|
|
122
122
|
throw new SandboxError("environment_id_invalid", "Select a Core-issued environment ID.", 400);
|
|
123
123
|
suffix = `/${environmentId}` + (action === "environment-status" ? "" : action === "environment-api" ? "/api"
|
|
124
|
-
: action === "environment-
|
|
124
|
+
: action === "environment-initialization" ? "/initialization" : action === "environment-initialization-resume" ? "/initialization/resume"
|
|
125
|
+
: action === "environment-setup-link" ? "/setup-link" : action === "environment-setup" ? "/setup" : `/operations/${action.slice("environment-".length)}`);
|
|
125
126
|
}
|
|
126
|
-
const replayable = !read && action !== "environment-api" && action !== "environment-setup";
|
|
127
|
+
const replayable = !read && action !== "environment-api" && action !== "environment-setup" && action !== "environment-setup-link" && action !== "environment-initialization-resume";
|
|
127
128
|
if (replayable && (typeof body.requestId !== "string" || !/^[a-f0-9-]{32,36}$/i.test(body.requestId)))
|
|
128
129
|
throw new SandboxError("environment_request_required", "Persist a request UUID before sending lifecycle operations.", 400);
|
|
129
130
|
let response;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function SdkChromeStyles(): import("react").JSX.Element;
|
|
2
|
+
export declare function SdkBrand(): import("react").JSX.Element;
|
|
3
|
+
export declare function SdkSpinner(): import("react").JSX.Element;
|
|
4
|
+
export declare function SdkProgress({ label }: {
|
|
5
|
+
label: string;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
7
|
+
export declare function SdkLoader(): import("react").JSX.Element;
|
|
8
|
+
type Icon = "close" | "external" | "menu" | "plus" | "minus" | "check" | "warning" | "error";
|
|
9
|
+
export declare function SdkIcon({ name }: {
|
|
10
|
+
name: Icon;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare const chromeStyles = "\n[data-hosty-sdk]{--hs-font:\"Hosty SDK Sans\",\"IBM Plex Sans\",ui-sans-serif,system-ui,sans-serif;--hs-mono:\"Hosty SDK Mono\",\"JetBrains Mono\",ui-monospace,monospace;--hs-bg:#F6F8FB;--hs-card:#FFFFFF;--hs-fg:#0F1B2D;--hs-muted:#5A6A82;--hs-border:#DFE5EE;--hs-input:#C3CDDB;--hs-soft:#EEF2F7;--hs-action:#0F1B2D;--hs-action-fg:#FFFFFF;--hs-brand:#A3E635;--hs-brand-fg:#0F1B2D;--hs-brand-soft:#ECFCCB;--hs-brand-edge:#5A9A0A;--hs-info:#1449C2;--hs-info-solid:#1C68FF;--hs-info-soft:#E8F0FF;--hs-warning:#8A5300;--hs-warning-soft:#FEF3DC;--hs-warning-border:#F8D9A0;--hs-danger:#B4232A;--hs-danger-soft:#FDECEC;--hs-success:#0F6B33;--hs-success-soft:#E8F7EE;color-scheme:light;color:var(--hs-fg);font:400 14px/1.5 var(--hs-font);letter-spacing:normal;text-transform:none;box-sizing:border-box}\nhtml.dark [data-hosty-sdk],html[data-hosty-theme=dark] [data-hosty-sdk]{--hs-bg:#0F1B2D;--hs-card:#17253B;--hs-fg:#F6F8FB;--hs-muted:#93A3BA;--hs-border:#26364F;--hs-input:#3A4B66;--hs-soft:#22324B;--hs-action:#F6F8FB;--hs-action-fg:#0F1B2D;--hs-brand-soft:#273B2E;--hs-brand-edge:#A3E635;--hs-info:#8DB4FF;--hs-info-solid:#4D8BFF;--hs-info-soft:#182E50;--hs-warning:#FBBF24;--hs-warning-soft:#392E22;--hs-warning-border:#6A4C22;--hs-danger:#FF8A8E;--hs-danger-soft:#3A2432;--hs-success:#4ADE80;--hs-success-soft:#18392F;color-scheme:dark}\n[data-hosty-sdk] :where(button,input,select,textarea){font:inherit;letter-spacing:normal;text-transform:none;box-sizing:border-box}\n[data-hosty-sdk] :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline:2px solid var(--hs-brand);outline-offset:2px;box-shadow:none}\n[data-hosty-sdk] :where(input,select,textarea)[aria-invalid=true]:focus-visible{outline-color:var(--hs-danger)}\n[data-hosty-sdk] ::selection{background:var(--hs-brand);color:var(--hs-brand-fg)}\n[data-hosty-sdk] .hosty-sdk-button{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;box-sizing:border-box;min-height:36px;padding:7px 12px;border:1px solid var(--hs-input);border-radius:8px;background:var(--hs-card);color:var(--hs-fg);font:500 14px/20px var(--hs-font);text-decoration:none;cursor:pointer;transition:background-color 120ms ease-out,color 120ms ease-out,border-color 120ms ease-out;white-space:normal;text-align:center}\n[data-hosty-sdk] .hosty-sdk-primary{background:var(--hs-action);border-color:var(--hs-action);color:var(--hs-action-fg)}\n[data-hosty-sdk] .hosty-sdk-ghost{background:transparent;border-color:transparent}\n[data-hosty-sdk] .hosty-sdk-danger{color:var(--hs-danger)}\n[data-hosty-sdk] .hosty-sdk-button:hover:not(:disabled){background:var(--hs-brand);border-color:var(--hs-brand);color:var(--hs-brand-fg)}\n[data-hosty-sdk] .hosty-sdk-button:active:not(:disabled){background:var(--hs-brand-soft);border-color:var(--hs-brand-edge);color:var(--hs-fg)}\n[data-hosty-sdk] .hosty-sdk-button:disabled{opacity:.5;cursor:not-allowed}\n[data-hosty-sdk] .hosty-sdk-icon-button{flex:none;width:32px;min-height:32px;padding:6px}\n[data-hosty-sdk] .hosty-sdk-input{box-sizing:border-box;width:100%;min-height:36px;padding:7px 10px;border:1px solid var(--hs-input);border-radius:8px;background:var(--hs-card);color:var(--hs-fg);font:400 14px/20px var(--hs-font)}\n.hosty-sdk-brand{display:inline-flex;align-items:center;gap:6px;flex:none;font:500 12px/18px var(--hs-font);color:var(--hs-muted)}\n.hosty-sdk-brand>svg{display:block;width:18px;height:18px;color:var(--hs-fg);flex:none}\n.hosty-sdk-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n.hosty-sdk-icon{display:block;width:16px;height:16px;flex:none}\n.hosty-sdk-spinner{display:inline-block;flex:none;width:16px;height:16px;box-sizing:border-box;border:2px solid var(--hs-input);border-top-color:var(--hs-info-solid);border-radius:50%;animation:hosty-sdk-spin .8s linear infinite}\n.hosty-sdk-progress{height:4px;border-radius:4px;background:var(--hs-soft);overflow:hidden;width:100%}\n.hosty-sdk-progress>span{display:block;width:38%;height:100%;border-radius:inherit;background:var(--hs-brand);animation:hosty-sdk-progress 1.6s ease-in-out infinite}\n.hosty-sdk-loader{display:block;width:36px;height:36px}\n.hosty-sdk-loader rect{fill:var(--hs-card);stroke:var(--hs-input);stroke-width:3;animation:hosty-sdk-cell 1.6s ease-in-out infinite;animation-delay:var(--hosty-cell-delay)}\n.hosty-sdk-status{display:flex;align-items:center;gap:8px;color:var(--hs-muted)}\n.hosty-panel-notice[data-hosty-sdk]{padding:24px;background:var(--hosty-panel-background,var(--hs-bg));color:var(--hosty-panel-foreground,var(--hs-fg));overflow-wrap:anywhere}.hosty-panel-notice[data-hosty-sdk] p{margin:8px 0;color:var(--hosty-panel-muted,var(--hs-muted))}.hosty-panel-notice[data-hosty-sdk] a{color:var(--hs-info);text-decoration:underline;text-underline-offset:3px}\n.hosty-panel-review[data-hosty-sdk]{position:absolute;top:8px;right:8px;z-index:2;padding:8px 12px;border:1px solid var(--hosty-panel-border,var(--hs-input));border-radius:8px;background:var(--hosty-panel-background,var(--hs-card));color:var(--hosty-panel-foreground,var(--hs-fg));font:500 13px/20px var(--hs-font);text-decoration:none}.hosty-panel-review[data-hosty-sdk]:hover{background:var(--hs-brand-soft)}.hosty-panel-review[data-hosty-sdk]:focus-visible{outline:2px solid var(--hs-brand);outline-offset:2px}\n@keyframes hosty-sdk-spin{to{transform:rotate(360deg)}}\n@keyframes hosty-sdk-progress{0%{transform:translateX(-110%)}100%{transform:translateX(370%)}}\n@keyframes hosty-sdk-cell{0%,55%,100%{fill:var(--hs-card);stroke:var(--hs-input)}18%{fill:var(--hs-brand);stroke:var(--hs-brand-edge)}}\n@media(prefers-reduced-motion:reduce){.hosty-sdk-spinner,.hosty-sdk-progress>span,.hosty-sdk-loader rect{animation:none}.hosty-sdk-spinner{border-color:var(--hs-info-solid);outline:1px solid var(--hs-info-solid);outline-offset:2px}.hosty-sdk-progress>span{width:100%;opacity:.7}.hosty-sdk-loader rect:nth-child(4){fill:var(--hs-brand);stroke:var(--hs-brand-edge)}}\n@media(max-width:480px){[data-hosty-sdk] .hosty-sdk-input{font-size:16px}}\n";
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { CoreMark } from "./chrome-mark.js";
|
|
5
|
+
// Statically analyzable URLs work in workspace bundlers and the published dist alike.
|
|
6
|
+
const sansLatin = new URL("./assets/plex-sans-latin.woff2", import.meta.url).href;
|
|
7
|
+
const sansExtended = new URL("./assets/plex-sans-latin-ext.woff2", import.meta.url).href;
|
|
8
|
+
const sansCyrillic = new URL("./assets/plex-sans-cyrillic.woff2", import.meta.url).href;
|
|
9
|
+
const monoLatin = new URL("./assets/jetbrains-mono-latin.woff2", import.meta.url).href;
|
|
10
|
+
const monoExtended = new URL("./assets/jetbrains-mono-latin-ext.woff2", import.meta.url).href;
|
|
11
|
+
const monoCyrillic = new URL("./assets/jetbrains-mono-cyrillic.woff2", import.meta.url).href;
|
|
12
|
+
const fontOwners = new WeakMap();
|
|
13
|
+
function retainFonts(document) {
|
|
14
|
+
let owner = fontOwners.get(document);
|
|
15
|
+
if (!owner?.element.isConnected) {
|
|
16
|
+
const element = document.createElement("style");
|
|
17
|
+
element.dataset.hostySdkFonts = "";
|
|
18
|
+
element.textContent = fontStyles;
|
|
19
|
+
document.head.append(element);
|
|
20
|
+
owner = { element, users: 0 };
|
|
21
|
+
fontOwners.set(document, owner);
|
|
22
|
+
}
|
|
23
|
+
const retained = owner;
|
|
24
|
+
retained.users++;
|
|
25
|
+
return () => {
|
|
26
|
+
retained.users--;
|
|
27
|
+
// StrictMode and a moving access portal can replay effects before the next paint.
|
|
28
|
+
// Keep the same font sheet when another SDK surface acquires it in that interval.
|
|
29
|
+
queueMicrotask(() => {
|
|
30
|
+
if (retained.users !== 0)
|
|
31
|
+
return;
|
|
32
|
+
retained.element.remove();
|
|
33
|
+
if (fontOwners.get(document) === retained)
|
|
34
|
+
fontOwners.delete(document);
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function SdkChromeStyles() {
|
|
39
|
+
// Asset URLs differ between Node SSR and the browser bundle. The deterministic base
|
|
40
|
+
// style hydrates unchanged; only a mounted browser owner installs resolved font URLs.
|
|
41
|
+
useEffect(() => retainFonts(document), []);
|
|
42
|
+
return _jsx("style", { "data-hosty-sdk-styles": true, children: chromeStyles });
|
|
43
|
+
}
|
|
44
|
+
export function SdkBrand() { return _jsxs("span", { className: "hosty-sdk-brand", children: [_jsx(CoreMark, {}), "Hosty"] }); }
|
|
45
|
+
export function SdkSpinner() { return _jsx("span", { className: "hosty-sdk-spinner", "aria-hidden": "true" }); }
|
|
46
|
+
export function SdkProgress({ label }) {
|
|
47
|
+
return _jsx("div", { className: "hosty-sdk-progress", role: "progressbar", "aria-label": label, children: _jsx("span", {}) });
|
|
48
|
+
}
|
|
49
|
+
export function SdkLoader() {
|
|
50
|
+
return _jsx("svg", { className: "hosty-sdk-loader", viewBox: "0 0 100 100", "aria-hidden": "true", focusable: "false", children: [[12, 12], [12, 41], [12, 70], [41, 41], [70, 70], [70, 41], [70, 12]].map(([x, y], index) => _jsx("rect", { x: x, y: y, width: "18", height: "18", style: { "--hosty-cell-delay": `${index * .16}s` } }, index)) });
|
|
51
|
+
}
|
|
52
|
+
const paths = {
|
|
53
|
+
close: "m18 6-12 12M6 6l12 12", external: "M15 3h6v6m0-6L10 14m8-1v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
|
|
54
|
+
menu: "M4 6h16M4 12h16M4 18h16", plus: "M12 5v14M5 12h14", minus: "M5 12h14", check: "m20 6-11 11-5-5",
|
|
55
|
+
warning: "m12 3 9 9-9 9-9-9 9-9Zm0 4v6m0 3v.01", error: "M12 8v4m0 4v.01M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z",
|
|
56
|
+
};
|
|
57
|
+
export function SdkIcon({ name }) {
|
|
58
|
+
return _jsx("svg", { className: "hosty-sdk-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: paths[name] }) });
|
|
59
|
+
}
|
|
60
|
+
// These roots contain SDK chrome only. Layout ancestors and the app document are deliberately absent.
|
|
61
|
+
const fontStyles = `
|
|
62
|
+
@font-face{font-family:"Hosty SDK Sans";font-style:normal;font-weight:100 900;font-display:swap;src:url("${sansLatin}") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
|
63
|
+
@font-face{font-family:"Hosty SDK Sans";font-style:normal;font-weight:100 900;font-display:swap;src:url("${sansExtended}") format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C4,U+2113,U+2C60-2C7F,U+A720-A7FF}
|
|
64
|
+
@font-face{font-family:"Hosty SDK Sans";font-style:normal;font-weight:100 900;font-display:swap;src:url("${sansCyrillic}") format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
|
|
65
|
+
@font-face{font-family:"Hosty SDK Mono";font-style:normal;font-weight:100 800;font-display:swap;src:url("${monoLatin}") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
|
66
|
+
@font-face{font-family:"Hosty SDK Mono";font-style:normal;font-weight:100 800;font-display:swap;src:url("${monoExtended}") format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C4,U+2113,U+2C60-2C7F,U+A720-A7FF}
|
|
67
|
+
@font-face{font-family:"Hosty SDK Mono";font-style:normal;font-weight:100 800;font-display:swap;src:url("${monoCyrillic}") format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
|
|
68
|
+
`;
|
|
69
|
+
export const chromeStyles = `
|
|
70
|
+
[data-hosty-sdk]{--hs-font:"Hosty SDK Sans","IBM Plex Sans",ui-sans-serif,system-ui,sans-serif;--hs-mono:"Hosty SDK Mono","JetBrains Mono",ui-monospace,monospace;--hs-bg:#F6F8FB;--hs-card:#FFFFFF;--hs-fg:#0F1B2D;--hs-muted:#5A6A82;--hs-border:#DFE5EE;--hs-input:#C3CDDB;--hs-soft:#EEF2F7;--hs-action:#0F1B2D;--hs-action-fg:#FFFFFF;--hs-brand:#A3E635;--hs-brand-fg:#0F1B2D;--hs-brand-soft:#ECFCCB;--hs-brand-edge:#5A9A0A;--hs-info:#1449C2;--hs-info-solid:#1C68FF;--hs-info-soft:#E8F0FF;--hs-warning:#8A5300;--hs-warning-soft:#FEF3DC;--hs-warning-border:#F8D9A0;--hs-danger:#B4232A;--hs-danger-soft:#FDECEC;--hs-success:#0F6B33;--hs-success-soft:#E8F7EE;color-scheme:light;color:var(--hs-fg);font:400 14px/1.5 var(--hs-font);letter-spacing:normal;text-transform:none;box-sizing:border-box}
|
|
71
|
+
html.dark [data-hosty-sdk],html[data-hosty-theme=dark] [data-hosty-sdk]{--hs-bg:#0F1B2D;--hs-card:#17253B;--hs-fg:#F6F8FB;--hs-muted:#93A3BA;--hs-border:#26364F;--hs-input:#3A4B66;--hs-soft:#22324B;--hs-action:#F6F8FB;--hs-action-fg:#0F1B2D;--hs-brand-soft:#273B2E;--hs-brand-edge:#A3E635;--hs-info:#8DB4FF;--hs-info-solid:#4D8BFF;--hs-info-soft:#182E50;--hs-warning:#FBBF24;--hs-warning-soft:#392E22;--hs-warning-border:#6A4C22;--hs-danger:#FF8A8E;--hs-danger-soft:#3A2432;--hs-success:#4ADE80;--hs-success-soft:#18392F;color-scheme:dark}
|
|
72
|
+
[data-hosty-sdk] :where(button,input,select,textarea){font:inherit;letter-spacing:normal;text-transform:none;box-sizing:border-box}
|
|
73
|
+
[data-hosty-sdk] :where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{outline:2px solid var(--hs-brand);outline-offset:2px;box-shadow:none}
|
|
74
|
+
[data-hosty-sdk] :where(input,select,textarea)[aria-invalid=true]:focus-visible{outline-color:var(--hs-danger)}
|
|
75
|
+
[data-hosty-sdk] ::selection{background:var(--hs-brand);color:var(--hs-brand-fg)}
|
|
76
|
+
[data-hosty-sdk] .hosty-sdk-button{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;box-sizing:border-box;min-height:36px;padding:7px 12px;border:1px solid var(--hs-input);border-radius:8px;background:var(--hs-card);color:var(--hs-fg);font:500 14px/20px var(--hs-font);text-decoration:none;cursor:pointer;transition:background-color 120ms ease-out,color 120ms ease-out,border-color 120ms ease-out;white-space:normal;text-align:center}
|
|
77
|
+
[data-hosty-sdk] .hosty-sdk-primary{background:var(--hs-action);border-color:var(--hs-action);color:var(--hs-action-fg)}
|
|
78
|
+
[data-hosty-sdk] .hosty-sdk-ghost{background:transparent;border-color:transparent}
|
|
79
|
+
[data-hosty-sdk] .hosty-sdk-danger{color:var(--hs-danger)}
|
|
80
|
+
[data-hosty-sdk] .hosty-sdk-button:hover:not(:disabled){background:var(--hs-brand);border-color:var(--hs-brand);color:var(--hs-brand-fg)}
|
|
81
|
+
[data-hosty-sdk] .hosty-sdk-button:active:not(:disabled){background:var(--hs-brand-soft);border-color:var(--hs-brand-edge);color:var(--hs-fg)}
|
|
82
|
+
[data-hosty-sdk] .hosty-sdk-button:disabled{opacity:.5;cursor:not-allowed}
|
|
83
|
+
[data-hosty-sdk] .hosty-sdk-icon-button{flex:none;width:32px;min-height:32px;padding:6px}
|
|
84
|
+
[data-hosty-sdk] .hosty-sdk-input{box-sizing:border-box;width:100%;min-height:36px;padding:7px 10px;border:1px solid var(--hs-input);border-radius:8px;background:var(--hs-card);color:var(--hs-fg);font:400 14px/20px var(--hs-font)}
|
|
85
|
+
.hosty-sdk-brand{display:inline-flex;align-items:center;gap:6px;flex:none;font:500 12px/18px var(--hs-font);color:var(--hs-muted)}
|
|
86
|
+
.hosty-sdk-brand>svg{display:block;width:18px;height:18px;color:var(--hs-fg);flex:none}
|
|
87
|
+
.hosty-sdk-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
|
|
88
|
+
.hosty-sdk-icon{display:block;width:16px;height:16px;flex:none}
|
|
89
|
+
.hosty-sdk-spinner{display:inline-block;flex:none;width:16px;height:16px;box-sizing:border-box;border:2px solid var(--hs-input);border-top-color:var(--hs-info-solid);border-radius:50%;animation:hosty-sdk-spin .8s linear infinite}
|
|
90
|
+
.hosty-sdk-progress{height:4px;border-radius:4px;background:var(--hs-soft);overflow:hidden;width:100%}
|
|
91
|
+
.hosty-sdk-progress>span{display:block;width:38%;height:100%;border-radius:inherit;background:var(--hs-brand);animation:hosty-sdk-progress 1.6s ease-in-out infinite}
|
|
92
|
+
.hosty-sdk-loader{display:block;width:36px;height:36px}
|
|
93
|
+
.hosty-sdk-loader rect{fill:var(--hs-card);stroke:var(--hs-input);stroke-width:3;animation:hosty-sdk-cell 1.6s ease-in-out infinite;animation-delay:var(--hosty-cell-delay)}
|
|
94
|
+
.hosty-sdk-status{display:flex;align-items:center;gap:8px;color:var(--hs-muted)}
|
|
95
|
+
.hosty-panel-notice[data-hosty-sdk]{padding:24px;background:var(--hosty-panel-background,var(--hs-bg));color:var(--hosty-panel-foreground,var(--hs-fg));overflow-wrap:anywhere}.hosty-panel-notice[data-hosty-sdk] p{margin:8px 0;color:var(--hosty-panel-muted,var(--hs-muted))}.hosty-panel-notice[data-hosty-sdk] a{color:var(--hs-info);text-decoration:underline;text-underline-offset:3px}
|
|
96
|
+
.hosty-panel-review[data-hosty-sdk]{position:absolute;top:8px;right:8px;z-index:2;padding:8px 12px;border:1px solid var(--hosty-panel-border,var(--hs-input));border-radius:8px;background:var(--hosty-panel-background,var(--hs-card));color:var(--hosty-panel-foreground,var(--hs-fg));font:500 13px/20px var(--hs-font);text-decoration:none}.hosty-panel-review[data-hosty-sdk]:hover{background:var(--hs-brand-soft)}.hosty-panel-review[data-hosty-sdk]:focus-visible{outline:2px solid var(--hs-brand);outline-offset:2px}
|
|
97
|
+
@keyframes hosty-sdk-spin{to{transform:rotate(360deg)}}
|
|
98
|
+
@keyframes hosty-sdk-progress{0%{transform:translateX(-110%)}100%{transform:translateX(370%)}}
|
|
99
|
+
@keyframes hosty-sdk-cell{0%,55%,100%{fill:var(--hs-card);stroke:var(--hs-input)}18%{fill:var(--hs-brand);stroke:var(--hs-brand-edge)}}
|
|
100
|
+
@media(prefers-reduced-motion:reduce){.hosty-sdk-spinner,.hosty-sdk-progress>span,.hosty-sdk-loader rect{animation:none}.hosty-sdk-spinner{border-color:var(--hs-info-solid);outline:1px solid var(--hs-info-solid);outline-offset:2px}.hosty-sdk-progress>span{width:100%;opacity:.7}.hosty-sdk-loader rect:nth-child(4){fill:var(--hs-brand);stroke:var(--hs-brand-edge)}}
|
|
101
|
+
@media(max-width:480px){[data-hosty-sdk] .hosty-sdk-input{font-size:16px}}
|
|
102
|
+
`;
|
package/dist/ui-composition.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ export declare function parseChromeHints(search: string): UiChromeOverrides & {
|
|
|
5
5
|
};
|
|
6
6
|
export declare function validChromeOverrides(value: unknown): value is UiChromeOverrides;
|
|
7
7
|
export declare function resolveChrome(defaults: UiChromeOverrides, hints: ReturnType<typeof parseChromeHints>, host?: UiChromeOverrides): {
|
|
8
|
-
navigation: "
|
|
8
|
+
navigation: "show" | "hide";
|
|
9
9
|
enabled: boolean;
|
|
10
|
-
launcher: "
|
|
10
|
+
launcher: "show" | "hide";
|
|
11
11
|
sources: {
|
|
12
12
|
navigation: UiChromeSource;
|
|
13
13
|
enabled: UiChromeSource;
|