@sevenfold/setto-client 0.10.0 → 0.11.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/chrome.d.ts +42 -1
- package/dist/index.d.ts +2 -0
- package/dist/provider.d.ts +13 -2
- package/dist/setto-client.js +49 -3
- package/dist/setto-client.js.map +1 -1
- package/package.json +1 -1
package/dist/chrome.d.ts
CHANGED
|
@@ -6,6 +6,42 @@ export interface SettoChromeHandshake {
|
|
|
6
6
|
/** The host's React, so the chrome bundle ships no framework of its own. */
|
|
7
7
|
react: typeof React;
|
|
8
8
|
reactDom: typeof ReactDOM;
|
|
9
|
+
/**
|
|
10
|
+
* Hand back a component and the host renders it.
|
|
11
|
+
*
|
|
12
|
+
* Inverted deliberately. The first cut had the chrome create its own React
|
|
13
|
+
* root, which cannot work: `createRoot` lives in `react-dom/client`, not
|
|
14
|
+
* `react-dom`, and React 19 removed `render` altogether — so the bundle
|
|
15
|
+
* loaded, found neither, and mounted nothing at all.
|
|
16
|
+
*
|
|
17
|
+
* Rendering it from here is better than passing `createRoot` across would
|
|
18
|
+
* have been. The chrome ends up inside the host's own tree, so its hooks are
|
|
19
|
+
* the host's hooks with no second root to keep in step, and the error
|
|
20
|
+
* boundary that keeps a mistake off the customer's page lives on this side
|
|
21
|
+
* where it cannot be forgotten.
|
|
22
|
+
*/
|
|
23
|
+
mount: (Component: React.ComponentType) => void;
|
|
24
|
+
/**
|
|
25
|
+
* The same, for the page at `/setto`.
|
|
26
|
+
*
|
|
27
|
+
* A second slot because the dashboard is not an overlay: it belongs in the
|
|
28
|
+
* host's own route, where the customer navigated to it. Registering nothing
|
|
29
|
+
* leaves the bundled dashboard in place, which is what keeps a chrome that
|
|
30
|
+
* fails to load from taking the admin down with it.
|
|
31
|
+
*/
|
|
32
|
+
mountAdmin: (Component: React.ComponentType) => void;
|
|
33
|
+
/**
|
|
34
|
+
* The host's own `useSetto`, callable from the chrome.
|
|
35
|
+
*
|
|
36
|
+
* This is what makes the whole arrangement cheap. The chrome renders inside
|
|
37
|
+
* the provider's tree, so it can simply use the context — supabase, api,
|
|
38
|
+
* session, sites, the i18n store — rather than having each field copied
|
|
39
|
+
* across a handshake that could never be extended without a re-pin.
|
|
40
|
+
*
|
|
41
|
+
* It is a hook: obey the rules of hooks, and only call it from a component
|
|
42
|
+
* this file rendered.
|
|
43
|
+
*/
|
|
44
|
+
useSetto: () => unknown;
|
|
9
45
|
config: {
|
|
10
46
|
siteId: string;
|
|
11
47
|
apiUrl: string;
|
|
@@ -33,4 +69,9 @@ declare global {
|
|
|
33
69
|
__settoChromeLoaded__?: boolean;
|
|
34
70
|
}
|
|
35
71
|
}
|
|
36
|
-
|
|
72
|
+
/**
|
|
73
|
+
* What the host should render at `/setto`, or null while the chrome has not
|
|
74
|
+
* offered anything. Callers fall back to their bundled dashboard.
|
|
75
|
+
*/
|
|
76
|
+
export declare function useSettoAdminChrome(): React.ComponentType | null;
|
|
77
|
+
export declare function SettoChrome(): import("react/jsx-runtime").JSX.Element | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export { SettoAnimation } from './SettoAnimation';
|
|
|
22
22
|
export type { SettoAnimationProps } from './SettoAnimation';
|
|
23
23
|
export { useSectionTheme } from './use-section-theme';
|
|
24
24
|
export { SettoAdminApp } from './admin/App';
|
|
25
|
+
export { SettoContext } from './provider';
|
|
26
|
+
export type { SettoContextValue } from './provider';
|
|
25
27
|
export { SETTO_BASE, adminViewUrl } from './lib/urls';
|
|
26
28
|
export { AuthGate } from './edit-mode/auth-gate';
|
|
27
29
|
export type { SettoConfig, BrandColor, DeploymentRow, SiteRow, ContentFile, PublishFile, PublishResult, } from './types';
|
package/dist/provider.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { I18nStore } from './lib/i18n-store';
|
|
|
5
5
|
import { AssetStore } from './lib/asset-store';
|
|
6
6
|
import { ThemeStore } from './lib/theme-store';
|
|
7
7
|
import type { SettoConfig, SiteRow } from './types';
|
|
8
|
-
interface SettoContextValue {
|
|
8
|
+
export interface SettoContextValue {
|
|
9
9
|
config: SettoConfig;
|
|
10
10
|
supabase: SupabaseClient;
|
|
11
11
|
api: SettoApi;
|
|
@@ -26,6 +26,18 @@ interface SettoContextValue {
|
|
|
26
26
|
themeStore: ThemeStore | null;
|
|
27
27
|
assetStore: AssetStore | null;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Exported for one caller: the chrome bundle.
|
|
31
|
+
*
|
|
32
|
+
* The dashboard is compiled into that bundle, so its `useSetto` reads *this*
|
|
33
|
+
* module's context — a different instance from the one the host provider
|
|
34
|
+
* fills, which would otherwise throw "must be used within SettoProvider" the
|
|
35
|
+
* moment it rendered. Handing it the host's value through this provider is
|
|
36
|
+
* what lets the same components run on either side of the boundary.
|
|
37
|
+
*
|
|
38
|
+
* Not part of the public API in any other sense. Use `useSetto`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SettoContext: import("react").Context<SettoContextValue | null>;
|
|
29
41
|
export interface SettoProviderProps {
|
|
30
42
|
config: SettoConfig;
|
|
31
43
|
children: ReactNode;
|
|
@@ -44,4 +56,3 @@ export interface SettoProviderProps {
|
|
|
44
56
|
*/
|
|
45
57
|
export declare function SettoProvider({ config, children }: SettoProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
46
58
|
export declare function useSetto(): SettoContextValue;
|
|
47
|
-
export {};
|
package/dist/setto-client.js
CHANGED
|
@@ -21364,8 +21364,45 @@ const CHROME_CONTRACT = 1;
|
|
|
21364
21364
|
function chromeUrl(apiUrl) {
|
|
21365
21365
|
return `${apiUrl.replace(/\/$/, "")}/chrome/v${CHROME_CONTRACT}.js`;
|
|
21366
21366
|
}
|
|
21367
|
+
class ChromeBoundary extends React.Component {
|
|
21368
|
+
state = { dead: false };
|
|
21369
|
+
static getDerivedStateFromError() {
|
|
21370
|
+
return { dead: true };
|
|
21371
|
+
}
|
|
21372
|
+
componentDidCatch(error) {
|
|
21373
|
+
console.warn("[setto] chrome failed, continuing without it", error);
|
|
21374
|
+
}
|
|
21375
|
+
render() {
|
|
21376
|
+
return this.state.dead ? null : this.props.children;
|
|
21377
|
+
}
|
|
21378
|
+
}
|
|
21379
|
+
const slots = {
|
|
21380
|
+
admin: null,
|
|
21381
|
+
listeners: /* @__PURE__ */ new Set()
|
|
21382
|
+
};
|
|
21383
|
+
function publishSlot(which, Component) {
|
|
21384
|
+
slots[which] = Component;
|
|
21385
|
+
for (const listener of slots.listeners) {
|
|
21386
|
+
try {
|
|
21387
|
+
listener();
|
|
21388
|
+
} catch {
|
|
21389
|
+
}
|
|
21390
|
+
}
|
|
21391
|
+
}
|
|
21392
|
+
function useSettoAdminChrome() {
|
|
21393
|
+
const [, force] = useState(0);
|
|
21394
|
+
useEffect(() => {
|
|
21395
|
+
const listener = () => force((n) => n + 1);
|
|
21396
|
+
slots.listeners.add(listener);
|
|
21397
|
+
return () => {
|
|
21398
|
+
slots.listeners.delete(listener);
|
|
21399
|
+
};
|
|
21400
|
+
}, []);
|
|
21401
|
+
return slots.admin;
|
|
21402
|
+
}
|
|
21367
21403
|
function SettoChrome() {
|
|
21368
21404
|
const setto = useSetto();
|
|
21405
|
+
const [Chrome, setChrome] = useState(null);
|
|
21369
21406
|
const listeners = useRef(/* @__PURE__ */ new Set());
|
|
21370
21407
|
const stateRef = useRef(() => ({
|
|
21371
21408
|
hasSession: false,
|
|
@@ -21412,10 +21449,15 @@ function SettoChrome() {
|
|
|
21412
21449
|
subscribe: (listener) => {
|
|
21413
21450
|
listeners.current.add(listener);
|
|
21414
21451
|
return () => listeners.current.delete(listener);
|
|
21415
|
-
}
|
|
21452
|
+
},
|
|
21453
|
+
// `setChrome(() => C)`: a component is a function, and the updater form
|
|
21454
|
+
// is the only way to put one into state without React calling it.
|
|
21455
|
+
mount: (Component) => setChrome(() => Component),
|
|
21456
|
+
mountAdmin: (Component) => publishSlot("admin", Component),
|
|
21457
|
+
useSetto
|
|
21416
21458
|
};
|
|
21417
21459
|
const script = document.createElement("script");
|
|
21418
|
-
script.src = chromeUrl(setto.config.apiUrl)
|
|
21460
|
+
script.src = `${chromeUrl(setto.config.apiUrl)}?site=${encodeURIComponent(setto.config.siteId)}`;
|
|
21419
21461
|
script.async = true;
|
|
21420
21462
|
script.onerror = () => void 0;
|
|
21421
21463
|
document.head.appendChild(script);
|
|
@@ -21423,7 +21465,8 @@ function SettoChrome() {
|
|
|
21423
21465
|
} catch {
|
|
21424
21466
|
}
|
|
21425
21467
|
}, []);
|
|
21426
|
-
return null;
|
|
21468
|
+
if (!Chrome) return null;
|
|
21469
|
+
return /* @__PURE__ */ jsx(ChromeBoundary, { children: /* @__PURE__ */ jsx(Chrome, {}) });
|
|
21427
21470
|
}
|
|
21428
21471
|
const SETTO_BASE = "/setto";
|
|
21429
21472
|
function siteHomeUrl(pathname = "/") {
|
|
@@ -26542,6 +26585,8 @@ function depDotStyle(status) {
|
|
|
26542
26585
|
};
|
|
26543
26586
|
}
|
|
26544
26587
|
function SettoAdminApp() {
|
|
26588
|
+
const Chrome = useSettoAdminChrome();
|
|
26589
|
+
if (Chrome) return /* @__PURE__ */ jsx(Chrome, {});
|
|
26545
26590
|
return /* @__PURE__ */ jsx(AuthGate, { children: /* @__PURE__ */ jsx(SiteList, {}) });
|
|
26546
26591
|
}
|
|
26547
26592
|
const DEPLOYMENTS_VIEW = "deployments";
|
|
@@ -27144,6 +27189,7 @@ export {
|
|
|
27144
27189
|
SettoBlock,
|
|
27145
27190
|
SettoBlockTree,
|
|
27146
27191
|
SettoChrome,
|
|
27192
|
+
SettoContext,
|
|
27147
27193
|
SettoForm,
|
|
27148
27194
|
SettoIcon,
|
|
27149
27195
|
SettoImage,
|