@replohq/sandbox-runtime 1.2.0 → 1.4.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/LinkInterceptor.js +33 -13
- package/LinkInterceptor.js.map +2 -2
- package/NavigationReceiver.d.ts +1 -0
- package/NavigationReceiver.js +25 -0
- package/NavigationReceiver.js.map +7 -0
- package/_vendor/schemas/componentPreview.mjs +2 -0
- package/_vendor/schemas/loaderKeys.d.ts +4 -0
- package/_vendor/schemas/selectModeIframeRpc.d.ts +6 -0
- package/_vendor/schemas/selectModeIframeRpc.mjs +5 -0
- package/buildMetadata.js +3 -3
- package/package.json +4 -4
- package/sandbox-runtime.js +2 -0
- package/sandbox-runtime.js.map +2 -2
- package/select-mode/iframeRpcChannel.d.ts +4 -1
- package/select-mode/iframeRpcChannel.js +8 -0
- package/select-mode/iframeRpcChannel.js.map +2 -2
package/LinkInterceptor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { displayModeStore } from "./select-mode/displayModeStore";
|
|
4
|
+
const EXTERNAL_NAVIGATION_HANDLER_KEY = "__reploExternalNavigationHandler";
|
|
4
5
|
function blockNavigation(event) {
|
|
5
6
|
event.preventDefault();
|
|
6
7
|
event.stopPropagation();
|
|
@@ -25,14 +26,20 @@ function shouldInterceptNavigationForAgentPreview() {
|
|
|
25
26
|
}
|
|
26
27
|
return new URLSearchParams(window.location.search).get("__reploAgentPreview") === "1";
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
+
function resolveUrl(rawUrl) {
|
|
29
30
|
try {
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
return new URL(
|
|
32
|
+
typeof rawUrl === "string" ? rawUrl : rawUrl.href,
|
|
33
|
+
window.location.href
|
|
34
|
+
);
|
|
32
35
|
} catch {
|
|
33
36
|
return null;
|
|
34
37
|
}
|
|
35
38
|
}
|
|
39
|
+
function urlLeavesSandbox(rawUrl) {
|
|
40
|
+
const resolved = resolveUrl(rawUrl);
|
|
41
|
+
return resolved === null ? null : resolved.origin !== window.location.origin;
|
|
42
|
+
}
|
|
36
43
|
function LinkInterceptor() {
|
|
37
44
|
useEffect(() => {
|
|
38
45
|
if (!shouldInterceptNavigationForAgentPreview()) {
|
|
@@ -43,25 +50,34 @@ function LinkInterceptor() {
|
|
|
43
50
|
const originalReplaceState = history.replaceState;
|
|
44
51
|
const navigation = getWindowNavigation();
|
|
45
52
|
const reportNavigated = (rawUrl) => {
|
|
46
|
-
let route;
|
|
47
|
-
try {
|
|
48
|
-
route = new URL(
|
|
49
|
-
typeof rawUrl === "string" ? rawUrl : rawUrl.href,
|
|
50
|
-
window.location.href
|
|
51
|
-
).pathname;
|
|
52
|
-
} catch {
|
|
53
|
-
route = String(rawUrl);
|
|
54
|
-
}
|
|
55
53
|
window.parent.postMessage(
|
|
56
54
|
{
|
|
57
55
|
type: "replo:navigated",
|
|
58
|
-
route
|
|
56
|
+
route: resolveUrl(rawUrl)?.pathname ?? String(rawUrl)
|
|
57
|
+
},
|
|
58
|
+
"*"
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
const openInParent = (rawUrl) => {
|
|
62
|
+
const resolved = resolveUrl(rawUrl);
|
|
63
|
+
if (!resolved) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
window.parent.postMessage(
|
|
67
|
+
{
|
|
68
|
+
type: "replo:open-external",
|
|
69
|
+
url: resolved.toString()
|
|
59
70
|
},
|
|
60
71
|
"*"
|
|
61
72
|
);
|
|
62
73
|
};
|
|
74
|
+
Reflect.set(window, EXTERNAL_NAVIGATION_HANDLER_KEY, (url) => {
|
|
75
|
+
openInParent(url);
|
|
76
|
+
return true;
|
|
77
|
+
});
|
|
63
78
|
window.open = function(url, target, features) {
|
|
64
79
|
if (url !== void 0 && url !== "" && urlLeavesSandbox(url) === true) {
|
|
80
|
+
openInParent(url);
|
|
65
81
|
return null;
|
|
66
82
|
}
|
|
67
83
|
return originalWindowOpen.call(window, url, target, features);
|
|
@@ -92,6 +108,7 @@ function LinkInterceptor() {
|
|
|
92
108
|
return;
|
|
93
109
|
}
|
|
94
110
|
event.preventDefault?.();
|
|
111
|
+
openInParent(destinationUrl);
|
|
95
112
|
};
|
|
96
113
|
const handleClick = (event) => {
|
|
97
114
|
if (displayModeStore.getSnapshot() === "selection") {
|
|
@@ -115,10 +132,12 @@ function LinkInterceptor() {
|
|
|
115
132
|
const linkTarget = link.getAttribute("target");
|
|
116
133
|
if (linkTarget && linkTarget !== "_self") {
|
|
117
134
|
blockNavigation(event);
|
|
135
|
+
openInParent(href);
|
|
118
136
|
return;
|
|
119
137
|
}
|
|
120
138
|
if (urlLeavesSandbox(href) === true) {
|
|
121
139
|
blockNavigation(event);
|
|
140
|
+
openInParent(href);
|
|
122
141
|
return;
|
|
123
142
|
}
|
|
124
143
|
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
@@ -137,6 +156,7 @@ function LinkInterceptor() {
|
|
|
137
156
|
navigation?.addEventListener("navigate", handleNavigate);
|
|
138
157
|
document.addEventListener("click", handleClick, true);
|
|
139
158
|
return () => {
|
|
159
|
+
Reflect.deleteProperty(window, EXTERNAL_NAVIGATION_HANDLER_KEY);
|
|
140
160
|
window.open = originalWindowOpen;
|
|
141
161
|
history.pushState = originalPushState;
|
|
142
162
|
history.replaceState = originalReplaceState;
|
package/LinkInterceptor.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../LinkInterceptor.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\n\nimport { useEffect } from \"react\";\n\nimport { displayModeStore } from \"./select-mode/displayModeStore\";\n\ntype NavigationNavigateEvent = {\n destination?: { url?: string };\n preventDefault?: () => void;\n};\n\ntype NavigationLike = {\n addEventListener: (\n type: \"navigate\",\n listener: (event: NavigationNavigateEvent) => void,\n ) => void;\n removeEventListener: (\n type: \"navigate\",\n listener: (event: NavigationNavigateEvent) => void,\n ) => void;\n};\n\nfunction blockNavigation(event: MouseEvent) {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n}\n\nfunction isNavigationLike(value: unknown): value is NavigationLike {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n return (\n typeof Reflect.get(value, \"addEventListener\") === \"function\" &&\n typeof Reflect.get(value, \"removeEventListener\") === \"function\"\n );\n}\n\nfunction getWindowNavigation() {\n const navigation = Reflect.get(window, \"navigation\");\n return isNavigationLike(navigation) ? navigation : null;\n}\n\nfunction shouldInterceptNavigationForAgentPreview() {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n if (window.parent === window) {\n return false;\n }\n\n return (\n new URLSearchParams(window.location.search).get(\"__reploAgentPreview\") ===\n \"1\"\n );\n}\n\nfunction
|
|
5
|
-
"mappings": ";AAEA,SAAS,iBAAiB;AAE1B,SAAS,wBAAwB;
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport { useEffect } from \"react\";\n\nimport { displayModeStore } from \"./select-mode/displayModeStore\";\n\ntype NavigationNavigateEvent = {\n destination?: { url?: string };\n preventDefault?: () => void;\n};\n\ntype NavigationLike = {\n addEventListener: (\n type: \"navigate\",\n listener: (event: NavigationNavigateEvent) => void,\n ) => void;\n removeEventListener: (\n type: \"navigate\",\n listener: (event: NavigationNavigateEvent) => void,\n ) => void;\n};\n\n// NOTE (Max, 2026-08-26): Shared by name with @replohq/sdk's `navigateExternal`\n// (packages/sdk/lib/external-navigation.ts) rather than by import \u2014 the two\n// packages publish independently and must not depend on each other.\nconst EXTERNAL_NAVIGATION_HANDLER_KEY = \"__reploExternalNavigationHandler\";\n\nfunction blockNavigation(event: MouseEvent) {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n}\n\nfunction isNavigationLike(value: unknown): value is NavigationLike {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n return (\n typeof Reflect.get(value, \"addEventListener\") === \"function\" &&\n typeof Reflect.get(value, \"removeEventListener\") === \"function\"\n );\n}\n\nfunction getWindowNavigation() {\n const navigation = Reflect.get(window, \"navigation\");\n return isNavigationLike(navigation) ? navigation : null;\n}\n\nfunction shouldInterceptNavigationForAgentPreview() {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n if (window.parent === window) {\n return false;\n }\n\n return (\n new URLSearchParams(window.location.search).get(\"__reploAgentPreview\") ===\n \"1\"\n );\n}\n\nfunction resolveUrl(rawUrl: string | URL): URL | null {\n try {\n return new URL(\n typeof rawUrl === \"string\" ? rawUrl : rawUrl.href,\n window.location.href,\n );\n } catch {\n return null;\n }\n}\n\nfunction urlLeavesSandbox(rawUrl: string | URL): boolean | null {\n const resolved = resolveUrl(rawUrl);\n return resolved === null ? null : resolved.origin !== window.location.origin;\n}\n\nexport default function LinkInterceptor() {\n // eslint-disable-next-line replo/no-use-effect -- Browser navigation APIs must be patched at client runtime and restored when the interceptor unmounts.\n useEffect(() => {\n if (!shouldInterceptNavigationForAgentPreview()) {\n return;\n }\n\n const originalWindowOpen = window.open;\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n const navigation = getWindowNavigation();\n\n // Tell the parent editor where the site's own navigation went so it can\n // keep its URL, page list, and select-mode in sync without reloading the\n // iframe. A fact, not a request: it is only sent once a navigation is\n // actually happening.\n const reportNavigated = (rawUrl: string | URL) => {\n window.parent.postMessage(\n {\n type: \"replo:navigated\",\n route: resolveUrl(rawUrl)?.pathname ?? String(rawUrl),\n },\n \"*\",\n );\n };\n\n // A navigation that leaves the sandbox cannot happen in place: checkout\n // providers refuse to be framed and the iframe has no `allow-popups`. Hand\n // the destination to the editor, which opens it in a real browser tab.\n const openInParent = (rawUrl: string | URL) => {\n const resolved = resolveUrl(rawUrl);\n if (!resolved) {\n return;\n }\n window.parent.postMessage(\n {\n type: \"replo:open-external\",\n url: resolved.toString(),\n },\n \"*\",\n );\n };\n\n Reflect.set(window, EXTERNAL_NAVIGATION_HANDLER_KEY, (url: string) => {\n openInParent(url);\n return true;\n });\n\n window.open = function (\n url?: string | URL,\n target?: string,\n features?: string,\n ) {\n if (url !== undefined && url !== \"\" && urlLeavesSandbox(url) === true) {\n openInParent(url);\n return null;\n }\n\n return originalWindowOpen.call(window, url, target, features);\n };\n\n // The history patches are where client-side navigations are reported:\n // next/link cancels its click and routes through pushState, so the click\n // handler below cannot know whether the site actually navigated \u2014 these\n // patches fire exactly when it did (link clicks and programmatic\n // router.push/redirects alike).\n history.pushState = function (\n state: Parameters<History[\"pushState\"]>[0],\n unused: string,\n url?: string | URL | null,\n ) {\n if (url && urlLeavesSandbox(url) === true) {\n return;\n }\n\n const result = originalPushState.call(history, state, unused, url);\n if (url) {\n reportNavigated(url);\n }\n return result;\n };\n\n history.replaceState = function (\n state: Parameters<History[\"replaceState\"]>[0],\n unused: string,\n url?: string | URL | null,\n ) {\n if (url && urlLeavesSandbox(url) === true) {\n return;\n }\n\n const result = originalReplaceState.call(history, state, unused, url);\n if (url) {\n reportNavigated(url);\n }\n return result;\n };\n\n const handleNavigate = (event: NavigationNavigateEvent) => {\n const destinationUrl = event.destination?.url;\n if (\n destinationUrl === undefined ||\n destinationUrl === \"\" ||\n urlLeavesSandbox(destinationUrl) !== true\n ) {\n return;\n }\n\n event.preventDefault?.();\n openInParent(destinationUrl);\n };\n\n const handleClick = (event: MouseEvent) => {\n // While select mode is active a link click must select the element, not\n // navigate. `useSelectionInteractions` prevents the default nav, but this\n // sibling capture listener would still post `replo:navigate` and move the\n // preview off the page \u2014 `stopPropagation` there can't suppress a\n // listener on the same node, so we bail out here explicitly.\n if (displayModeStore.getSnapshot() === \"selection\") {\n return;\n }\n\n const target = event.target;\n\n if (!(target instanceof Element)) {\n return;\n }\n\n const link = target.closest(\"a[href]\");\n\n if (!(link instanceof HTMLAnchorElement)) {\n return;\n }\n\n const href = link.getAttribute(\"href\");\n if (!href) {\n return;\n }\n\n if (href.startsWith(\"#\")) {\n return;\n }\n\n const linkTarget = link.getAttribute(\"target\");\n if (linkTarget && linkTarget !== \"_self\") {\n blockNavigation(event);\n openInParent(href);\n return;\n }\n\n if (urlLeavesSandbox(href) === true) {\n blockNavigation(event);\n openInParent(href);\n return;\n }\n\n // A modified click (new tab / etc.) is the browser's to handle \u2014 the\n // iframe sandbox has no `allow-popups`, so it can't escape anyway.\n // Don't hijack it or tell the parent we navigated.\n if (\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n ) {\n return;\n }\n\n // A download link never navigates, so there is nothing to report.\n if (link.hasAttribute(\"download\")) {\n return;\n }\n\n // Let the site navigate itself \u2014 next/link does an instant client-side\n // transition, exactly like a normal Next.js app \u2014 instead of cancelling\n // the click and making the parent editor tear down and reload the whole\n // preview iframe. next/link navigations are reported by the pushState\n // patch above; this deferred report covers plain anchors the browser\n // itself navigates (a full document load inside the iframe). Deferred a\n // microtask because this capture listener runs before the site's own\n // handlers: a cancelled click (next/link included) navigates nothing.\n queueMicrotask(() => {\n if (event.defaultPrevented) {\n return;\n }\n reportNavigated(href);\n });\n };\n\n navigation?.addEventListener(\"navigate\", handleNavigate);\n document.addEventListener(\"click\", handleClick, true);\n\n return () => {\n Reflect.deleteProperty(window, EXTERNAL_NAVIGATION_HANDLER_KEY);\n window.open = originalWindowOpen;\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n navigation?.removeEventListener(\"navigate\", handleNavigate);\n document.removeEventListener(\"click\", handleClick, true);\n };\n }, []);\n\n return null;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function NavigationReceiver(): null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useMemo } from "react";
|
|
3
|
+
import { useRouter } from "next/navigation";
|
|
4
|
+
import { useIframeRpcChannel } from "./_vendor/replo-utils/react/use-iframe-rpc-channel.mjs";
|
|
5
|
+
import {
|
|
6
|
+
getSelectModeIframeRpcChannel,
|
|
7
|
+
setNavigateToRouteHandler
|
|
8
|
+
} from "./select-mode/iframeRpcChannel";
|
|
9
|
+
function NavigationReceiver() {
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
useIframeRpcChannel(useMemo(() => getSelectModeIframeRpcChannel(), []));
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setNavigateToRouteHandler(({ pathname }) => {
|
|
14
|
+
router.push(pathname);
|
|
15
|
+
});
|
|
16
|
+
return () => {
|
|
17
|
+
setNavigateToRouteHandler(null);
|
|
18
|
+
};
|
|
19
|
+
}, [router]);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
NavigationReceiver
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=NavigationReceiver.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../NavigationReceiver.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\n\nimport { useRouter } from \"next/navigation\";\n\nimport { useIframeRpcChannel } from \"replo-utils/react/use-iframe-rpc-channel\";\n\nimport {\n getSelectModeIframeRpcChannel,\n setNavigateToRouteHandler,\n} from \"./select-mode/iframeRpcChannel\";\n\n// Hands the editor's `navigateToRoute` commands to the app router; `LinkInterceptor` reports the resulting navigation up.\nexport function NavigationReceiver() {\n const router = useRouter();\n useIframeRpcChannel(useMemo(() => getSelectModeIframeRpcChannel(), []));\n\n // eslint-disable-next-line replo/no-use-effect -- RPC handler registration tied to the router's lifetime.\n useEffect(() => {\n setNavigateToRouteHandler(({ pathname }) => {\n router.push(pathname);\n });\n return () => {\n setNavigateToRouteHandler(null);\n };\n }, [router]);\n\n return null;\n}\n"],
|
|
5
|
+
"mappings": ";AAEA,SAAS,WAAW,eAAe;AAEnC,SAAS,iBAAiB;AAE1B,SAAS,2BAA2B;AAEpC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAGA,SAAS,qBAAqB;AACnC,QAAM,SAAS,UAAU;AACzB,sBAAoB,QAAQ,MAAM,8BAA8B,GAAG,CAAC,CAAC,CAAC;AAGtE,YAAU,MAAM;AACd,8BAA0B,CAAC,EAAE,SAAS,MAAM;AAC1C,aAAO,KAAK,QAAQ;AAAA,IACtB,CAAC;AACD,WAAO,MAAM;AACX,gCAA0B,IAAI;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -19,6 +19,8 @@ var DATA_LOADER_KEYS = {
|
|
|
19
19
|
YOTPO_PRODUCT_REVIEW_AGGREGATE: "yotpo.product_review_aggregate",
|
|
20
20
|
REVIEWS_IO_PRODUCT_REVIEWS: "reviews_io.product_reviews",
|
|
21
21
|
REVIEWS_IO_PRODUCT_REVIEW_AGGREGATE: "reviews_io.product_review_aggregate",
|
|
22
|
+
LOOX_PRODUCT_REVIEWS: "loox.product_reviews",
|
|
23
|
+
LOOX_PRODUCT_REVIEW_AGGREGATE: "loox.product_review_aggregate",
|
|
22
24
|
STATSIG_EXPERIMENT: "statsig.experiment",
|
|
23
25
|
CONTENTFUL_ENTRY: "contentful.entry",
|
|
24
26
|
CONTENTFUL_ENTRIES: "contentful.entries"
|
|
@@ -28,6 +28,8 @@ export declare const DATA_LOADER_KEYS: {
|
|
|
28
28
|
readonly YOTPO_PRODUCT_REVIEW_AGGREGATE: "yotpo.product_review_aggregate";
|
|
29
29
|
readonly REVIEWS_IO_PRODUCT_REVIEWS: "reviews_io.product_reviews";
|
|
30
30
|
readonly REVIEWS_IO_PRODUCT_REVIEW_AGGREGATE: "reviews_io.product_review_aggregate";
|
|
31
|
+
readonly LOOX_PRODUCT_REVIEWS: "loox.product_reviews";
|
|
32
|
+
readonly LOOX_PRODUCT_REVIEW_AGGREGATE: "loox.product_review_aggregate";
|
|
31
33
|
readonly STATSIG_EXPERIMENT: "statsig.experiment";
|
|
32
34
|
readonly CONTENTFUL_ENTRY: "contentful.entry";
|
|
33
35
|
readonly CONTENTFUL_ENTRIES: "contentful.entries";
|
|
@@ -51,6 +53,8 @@ export declare const dataLoaderKeySchema: z.ZodEnum<{
|
|
|
51
53
|
"yotpo.product_review_aggregate": "yotpo.product_review_aggregate";
|
|
52
54
|
"reviews_io.product_reviews": "reviews_io.product_reviews";
|
|
53
55
|
"reviews_io.product_review_aggregate": "reviews_io.product_review_aggregate";
|
|
56
|
+
"loox.product_reviews": "loox.product_reviews";
|
|
57
|
+
"loox.product_review_aggregate": "loox.product_review_aggregate";
|
|
54
58
|
"statsig.experiment": "statsig.experiment";
|
|
55
59
|
"contentful.entry": "contentful.entry";
|
|
56
60
|
"contentful.entries": "contentful.entries";
|
|
@@ -131,6 +131,12 @@ export declare const websiteBuilderToCanopyMethodConfig: {
|
|
|
131
131
|
}, z.core.$strip>;
|
|
132
132
|
timeoutMs: number;
|
|
133
133
|
};
|
|
134
|
+
navigateToRoute: {
|
|
135
|
+
inputSchema: z.ZodObject<{
|
|
136
|
+
pathname: z.ZodString;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
outputSchema: z.ZodVoid;
|
|
139
|
+
};
|
|
134
140
|
setDisplayMode: {
|
|
135
141
|
inputSchema: z.ZodObject<{
|
|
136
142
|
displayMode: z.ZodEnum<{
|
|
@@ -18,6 +18,11 @@ var websiteBuilderToCanopyMethodConfig = {
|
|
|
18
18
|
outputSchema: selectedElementSchema,
|
|
19
19
|
timeoutMs: 1500
|
|
20
20
|
},
|
|
21
|
+
// Client-side transition command; fire-and-forget because success is observed as the `replo:navigated` echo.
|
|
22
|
+
navigateToRoute: {
|
|
23
|
+
inputSchema: z.object({ pathname: z.string() }),
|
|
24
|
+
outputSchema: z.void()
|
|
25
|
+
},
|
|
21
26
|
setDisplayMode: {
|
|
22
27
|
inputSchema: z.object({ displayMode: displayModeSchema }),
|
|
23
28
|
outputSchema: z.void()
|
package/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sandbox-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-08-
|
|
5
|
+
"commit": "24d52db6a49bcade4693ce801896805675d114fe",
|
|
6
|
+
"builtAt": "2026-08-27T00:53:21.140Z"
|
|
7
7
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sandbox-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sandbox-runtime",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.4.0",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-08-
|
|
8
|
+
"commit": "24d52db6a49bcade4693ce801896805675d114fe",
|
|
9
|
+
"builtAt": "2026-08-27T00:53:21.140Z"
|
|
10
10
|
},
|
|
11
11
|
"description": "Replo sandbox runtime — editor integration for agent-built Next.js sites.",
|
|
12
12
|
"license": "SEE LICENSE IN LICENSE",
|
package/sandbox-runtime.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ClientErrorBoundary } from "./ClientErrorBoundary";
|
|
|
5
5
|
import { DesignLibraryPreview } from "./design-library-preview/DesignLibraryPreview";
|
|
6
6
|
import { DocumentReadyBeacon } from "./DocumentReadyBeacon";
|
|
7
7
|
import LinkInterceptor from "./LinkInterceptor";
|
|
8
|
+
import { NavigationReceiver } from "./NavigationReceiver";
|
|
8
9
|
import { NextErrorReporter } from "./NextErrorReporter";
|
|
9
10
|
import PostHogRelay from "./posthog-relay";
|
|
10
11
|
import { EditorSelection } from "./select-mode/EditorSelection";
|
|
@@ -15,6 +16,7 @@ function SandboxRuntime({ children }) {
|
|
|
15
16
|
/* @__PURE__ */ jsx(NextErrorReporter, {}),
|
|
16
17
|
/* @__PURE__ */ jsxs(ClientErrorBoundary, { children: [
|
|
17
18
|
/* @__PURE__ */ jsx(LinkInterceptor, {}),
|
|
19
|
+
/* @__PURE__ */ jsx(NavigationReceiver, {}),
|
|
18
20
|
/* @__PURE__ */ jsx(PostHogRelay, {}),
|
|
19
21
|
/* @__PURE__ */ jsx(EditorSelection, {}),
|
|
20
22
|
/* @__PURE__ */ jsx(AnnotationLayerMount, {}),
|
package/sandbox-runtime.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../sandbox-runtime.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\n\nimport { AnnotationLayerMount } from \"./annotations/AnnotationLayerMount\";\nimport { ClientErrorBoundary } from \"./ClientErrorBoundary\";\nimport { DesignLibraryPreview } from \"./design-library-preview/DesignLibraryPreview\";\nimport { DocumentReadyBeacon } from \"./DocumentReadyBeacon\";\nimport LinkInterceptor from \"./LinkInterceptor\";\nimport { NextErrorReporter } from \"./NextErrorReporter\";\nimport PostHogRelay from \"./posthog-relay\";\nimport { EditorSelection } from \"./select-mode/EditorSelection\";\n\nexport function SandboxRuntime({ children }: React.PropsWithChildren) {\n // The editor only embeds dev servers (`next dev`), so editor-integration components render there only \u2014 production builds ship none of them and behave like plain Next apps.\n const isDevServer = process.env.NODE_ENV === \"development\";\n\n return isDevServer ? (\n <>\n <DocumentReadyBeacon />\n {/* NOTE (Max, 2026-06-08): Outside ClientErrorBoundary on purpose \u2014 when\n the boundary catches a runtime error it swaps its children for a\n neutral cover, which would unmount the reporter and freeze it in the\n error state. It must stay mounted to observe Next's overlay across\n error <-> recover. */}\n <NextErrorReporter />\n <ClientErrorBoundary>\n <LinkInterceptor />\n <PostHogRelay />\n <EditorSelection />\n <AnnotationLayerMount />\n <DesignLibraryPreview />\n {children}\n </ClientErrorBoundary>\n </>\n ) : (\n children\n );\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport { AnnotationLayerMount } from \"./annotations/AnnotationLayerMount\";\nimport { ClientErrorBoundary } from \"./ClientErrorBoundary\";\nimport { DesignLibraryPreview } from \"./design-library-preview/DesignLibraryPreview\";\nimport { DocumentReadyBeacon } from \"./DocumentReadyBeacon\";\nimport LinkInterceptor from \"./LinkInterceptor\";\nimport { NavigationReceiver } from \"./NavigationReceiver\";\nimport { NextErrorReporter } from \"./NextErrorReporter\";\nimport PostHogRelay from \"./posthog-relay\";\nimport { EditorSelection } from \"./select-mode/EditorSelection\";\n\nexport function SandboxRuntime({ children }: React.PropsWithChildren) {\n // The editor only embeds dev servers (`next dev`), so editor-integration components render there only \u2014 production builds ship none of them and behave like plain Next apps.\n const isDevServer = process.env.NODE_ENV === \"development\";\n\n return isDevServer ? (\n <>\n <DocumentReadyBeacon />\n {/* NOTE (Max, 2026-06-08): Outside ClientErrorBoundary on purpose \u2014 when\n the boundary catches a runtime error it swaps its children for a\n neutral cover, which would unmount the reporter and freeze it in the\n error state. It must stay mounted to observe Next's overlay across\n error <-> recover. */}\n <NextErrorReporter />\n <ClientErrorBoundary>\n <LinkInterceptor />\n <NavigationReceiver />\n <PostHogRelay />\n <EditorSelection />\n <AnnotationLayerMount />\n <DesignLibraryPreview />\n {children}\n </ClientErrorBoundary>\n </>\n ) : (\n children\n );\n}\n"],
|
|
5
|
+
"mappings": ";AAiBI,mBACE,KAOA,YARF;AAfJ,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,OAAO,qBAAqB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,OAAO,kBAAkB;AACzB,SAAS,uBAAuB;AAEzB,SAAS,eAAe,EAAE,SAAS,GAA4B;AAEpE,QAAM,cAAc,QAAQ,IAAI,aAAa;AAE7C,SAAO,cACL,iCACE;AAAA,wBAAC,uBAAoB;AAAA,IAMrB,oBAAC,qBAAkB;AAAA,IACnB,qBAAC,uBACC;AAAA,0BAAC,mBAAgB;AAAA,MACjB,oBAAC,sBAAmB;AAAA,MACpB,oBAAC,gBAAa;AAAA,MACd,oBAAC,mBAAgB;AAAA,MACjB,oBAAC,wBAAqB;AAAA,MACtB,oBAAC,wBAAqB;AAAA,MACrB;AAAA,OACH;AAAA,KACF,IAEA;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,10 @@ import type { SelectedElement } from "../_vendor/schemas/generated/selectMode";
|
|
|
2
2
|
import type { IframeRpcChannelInputHandlers, IframeRpcChannelRemote } from "../_vendor/schemas/iframeRpcChannel";
|
|
3
3
|
import { canopyToWebsiteBuilderMethodConfig, websiteBuilderToCanopyMethodConfig } from "../_vendor/schemas/selectModeIframeRpc";
|
|
4
4
|
export type WebsiteBuilderRpcRemote = IframeRpcChannelRemote<typeof canopyToWebsiteBuilderMethodConfig>;
|
|
5
|
-
type SelectModeParentMessagingHandlers = Omit<IframeRpcChannelInputHandlers<typeof websiteBuilderToCanopyMethodConfig>, "symbolicateSelectedElement">;
|
|
5
|
+
type SelectModeParentMessagingHandlers = Omit<IframeRpcChannelInputHandlers<typeof websiteBuilderToCanopyMethodConfig>, "symbolicateSelectedElement" | "navigateToRoute">;
|
|
6
|
+
export declare function setNavigateToRouteHandler(handler: ((input: {
|
|
7
|
+
pathname: string;
|
|
8
|
+
}) => void) | null): void;
|
|
6
9
|
export declare function getSelectModeIframeRpcChannel(): import("../_vendor/schemas/iframeRpcChannel").IframeRpcChannel<{
|
|
7
10
|
requestInlineTextEdit: {
|
|
8
11
|
inputSchema: import("zod").ZodObject<{
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
} from "../_vendor/schemas/selectModeIframeRpc.mjs";
|
|
11
11
|
import { symbolicateSelectedElement } from "./symbolicate";
|
|
12
12
|
let messagingHandlers = null;
|
|
13
|
+
let navigateToRouteHandler = null;
|
|
14
|
+
function setNavigateToRouteHandler(handler) {
|
|
15
|
+
navigateToRouteHandler = handler;
|
|
16
|
+
}
|
|
13
17
|
function createSelectModeIframeRpcChannel() {
|
|
14
18
|
return createIframeRpcChannel({
|
|
15
19
|
subscriberWindow: window,
|
|
@@ -50,6 +54,9 @@ function createSelectModeIframeRpcChannel() {
|
|
|
50
54
|
},
|
|
51
55
|
symbolicateSelectedElement: (element) => {
|
|
52
56
|
return symbolicateSelectedElement(element);
|
|
57
|
+
},
|
|
58
|
+
navigateToRoute: (input) => {
|
|
59
|
+
navigateToRouteHandler?.(input);
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
62
|
});
|
|
@@ -87,6 +94,7 @@ export {
|
|
|
87
94
|
getSelectModeIframeRpcChannel,
|
|
88
95
|
getWebsiteBuilderRpc,
|
|
89
96
|
requestInlineTextEdit,
|
|
97
|
+
setNavigateToRouteHandler,
|
|
90
98
|
setSelectModeParentHandlers
|
|
91
99
|
};
|
|
92
100
|
//# sourceMappingURL=iframeRpcChannel.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../select-mode/iframeRpcChannel.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SelectedElement } from \"schemas/generated/selectMode\";\nimport type {\n IframeRpcChannelInputHandlers,\n IframeRpcChannelRemote,\n} from \"schemas/iframeRpcChannel\";\n\nimport {\n createIframeRpcChannel,\n createIframeRpcRemote,\n} from \"schemas/iframeRpcChannel\";\nimport {\n canopyToWebsiteBuilderMethodConfig,\n SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n websiteBuilderToCanopyMethodConfig,\n} from \"schemas/selectModeIframeRpc\";\n\nimport { symbolicateSelectedElement } from \"./symbolicate\";\n\nexport type WebsiteBuilderRpcRemote = IframeRpcChannelRemote<\n typeof canopyToWebsiteBuilderMethodConfig\n>;\n\ntype SelectModeParentMessagingHandlers = Omit<\n IframeRpcChannelInputHandlers<typeof websiteBuilderToCanopyMethodConfig>,\n \"symbolicateSelectedElement\"\n>;\n\n// Module-level handler pointers; `useParentMessaging` sets these on mount\n// and nulls them on unmount. Inbound void methods are dropped until then.\n// `symbolicateSelectedElement` is wired permanently on the channel.\nlet messagingHandlers: SelectModeParentMessagingHandlers | null = null;\n\nfunction createSelectModeIframeRpcChannel() {\n return createIframeRpcChannel({\n subscriberWindow: window,\n channelIdentifier: SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n version: SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n getTargetWindow: () => (window.parent === window ? null : window.parent),\n targetOrigin: \"*\",\n isExpectedMessage: (event) => event.source === window.parent,\n outgoingMethods: canopyToWebsiteBuilderMethodConfig,\n incomingMethods: websiteBuilderToCanopyMethodConfig,\n handlers: {\n setDisplayMode: (input) => {\n messagingHandlers?.setDisplayMode(input);\n },\n setSelectionType: (input) => {\n messagingHandlers?.setSelectionType(input);\n },\n applyOptimisticUpdate: (input) => {\n messagingHandlers?.applyOptimisticUpdate(input);\n },\n markCommitted: (input) => {\n messagingHandlers?.markCommitted(input);\n },\n resolveSessionOverrides: (input) => {\n messagingHandlers?.resolveSessionOverrides(input);\n },\n revertOverride: (input) => {\n messagingHandlers?.revertOverride(input);\n },\n enterEditMode: (input) => {\n messagingHandlers?.enterEditMode(input);\n },\n exitEditMode: (input) => {\n messagingHandlers?.exitEditMode(input);\n },\n formatCommand: (input) => {\n messagingHandlers?.formatCommand(input);\n },\n symbolicateSelectedElement: (element) => {\n return symbolicateSelectedElement(element);\n },\n },\n });\n}\n\nlet channel: ReturnType<typeof createSelectModeIframeRpcChannel> | null = null;\nlet websiteBuilderRpc: WebsiteBuilderRpcRemote | null = null;\n\nexport function getSelectModeIframeRpcChannel() {\n if (typeof window === \"undefined\") {\n return null;\n }\n channel ??= createSelectModeIframeRpcChannel();\n return channel;\n}\n\nexport function setSelectModeParentHandlers(\n nextHandlers: SelectModeParentMessagingHandlers | null,\n) {\n messagingHandlers = nextHandlers;\n}\n\nexport function getWebsiteBuilderRpc(): WebsiteBuilderRpcRemote | null {\n const currentChannel = getSelectModeIframeRpcChannel();\n if (!currentChannel) {\n return null;\n }\n websiteBuilderRpc ??= createIframeRpcRemote(currentChannel);\n return websiteBuilderRpc;\n}\n\nexport function requestInlineTextEdit(input: {\n editId: string;\n element: SelectedElement;\n}) {\n const remote = getWebsiteBuilderRpc();\n if (!remote) {\n return Promise.reject(\n new Error(\"Website Builder iframe RPC is unavailable\"),\n );\n }\n return remote.requestInlineTextEdit(input);\n}\n"],
|
|
5
|
-
"mappings": "AAMA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,kCAAkC;AAc3C,IAAI,oBAA8D;
|
|
4
|
+
"sourcesContent": ["import type { SelectedElement } from \"schemas/generated/selectMode\";\nimport type {\n IframeRpcChannelInputHandlers,\n IframeRpcChannelRemote,\n} from \"schemas/iframeRpcChannel\";\n\nimport {\n createIframeRpcChannel,\n createIframeRpcRemote,\n} from \"schemas/iframeRpcChannel\";\nimport {\n canopyToWebsiteBuilderMethodConfig,\n SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n websiteBuilderToCanopyMethodConfig,\n} from \"schemas/selectModeIframeRpc\";\n\nimport { symbolicateSelectedElement } from \"./symbolicate\";\n\nexport type WebsiteBuilderRpcRemote = IframeRpcChannelRemote<\n typeof canopyToWebsiteBuilderMethodConfig\n>;\n\ntype SelectModeParentMessagingHandlers = Omit<\n IframeRpcChannelInputHandlers<typeof websiteBuilderToCanopyMethodConfig>,\n \"symbolicateSelectedElement\" | \"navigateToRoute\"\n>;\n\n// Module-level handler pointers; `useParentMessaging` sets these on mount\n// and nulls them on unmount. Inbound void methods are dropped until then.\n// `symbolicateSelectedElement` is wired permanently on the channel.\nlet messagingHandlers: SelectModeParentMessagingHandlers | null = null;\n\n// Set by `NavigationReceiver` while a router is mounted; unhandled commands are dropped.\nlet navigateToRouteHandler: ((input: { pathname: string }) => void) | null =\n null;\n\nexport function setNavigateToRouteHandler(\n handler: ((input: { pathname: string }) => void) | null,\n) {\n navigateToRouteHandler = handler;\n}\n\nfunction createSelectModeIframeRpcChannel() {\n return createIframeRpcChannel({\n subscriberWindow: window,\n channelIdentifier: SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n version: SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n getTargetWindow: () => (window.parent === window ? null : window.parent),\n targetOrigin: \"*\",\n isExpectedMessage: (event) => event.source === window.parent,\n outgoingMethods: canopyToWebsiteBuilderMethodConfig,\n incomingMethods: websiteBuilderToCanopyMethodConfig,\n handlers: {\n setDisplayMode: (input) => {\n messagingHandlers?.setDisplayMode(input);\n },\n setSelectionType: (input) => {\n messagingHandlers?.setSelectionType(input);\n },\n applyOptimisticUpdate: (input) => {\n messagingHandlers?.applyOptimisticUpdate(input);\n },\n markCommitted: (input) => {\n messagingHandlers?.markCommitted(input);\n },\n resolveSessionOverrides: (input) => {\n messagingHandlers?.resolveSessionOverrides(input);\n },\n revertOverride: (input) => {\n messagingHandlers?.revertOverride(input);\n },\n enterEditMode: (input) => {\n messagingHandlers?.enterEditMode(input);\n },\n exitEditMode: (input) => {\n messagingHandlers?.exitEditMode(input);\n },\n formatCommand: (input) => {\n messagingHandlers?.formatCommand(input);\n },\n symbolicateSelectedElement: (element) => {\n return symbolicateSelectedElement(element);\n },\n navigateToRoute: (input) => {\n navigateToRouteHandler?.(input);\n },\n },\n });\n}\n\nlet channel: ReturnType<typeof createSelectModeIframeRpcChannel> | null = null;\nlet websiteBuilderRpc: WebsiteBuilderRpcRemote | null = null;\n\nexport function getSelectModeIframeRpcChannel() {\n if (typeof window === \"undefined\") {\n return null;\n }\n channel ??= createSelectModeIframeRpcChannel();\n return channel;\n}\n\nexport function setSelectModeParentHandlers(\n nextHandlers: SelectModeParentMessagingHandlers | null,\n) {\n messagingHandlers = nextHandlers;\n}\n\nexport function getWebsiteBuilderRpc(): WebsiteBuilderRpcRemote | null {\n const currentChannel = getSelectModeIframeRpcChannel();\n if (!currentChannel) {\n return null;\n }\n websiteBuilderRpc ??= createIframeRpcRemote(currentChannel);\n return websiteBuilderRpc;\n}\n\nexport function requestInlineTextEdit(input: {\n editId: string;\n element: SelectedElement;\n}) {\n const remote = getWebsiteBuilderRpc();\n if (!remote) {\n return Promise.reject(\n new Error(\"Website Builder iframe RPC is unavailable\"),\n );\n }\n return remote.requestInlineTextEdit(input);\n}\n"],
|
|
5
|
+
"mappings": "AAMA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,kCAAkC;AAc3C,IAAI,oBAA8D;AAGlE,IAAI,yBACF;AAEK,SAAS,0BACd,SACA;AACA,2BAAyB;AAC3B;AAEA,SAAS,mCAAmC;AAC1C,SAAO,uBAAuB;AAAA,IAC5B,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,SAAS;AAAA,IACT,iBAAiB,MAAO,OAAO,WAAW,SAAS,OAAO,OAAO;AAAA,IACjE,cAAc;AAAA,IACd,mBAAmB,CAAC,UAAU,MAAM,WAAW,OAAO;AAAA,IACtD,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,UAAU;AAAA,MACR,gBAAgB,CAAC,UAAU;AACzB,2BAAmB,eAAe,KAAK;AAAA,MACzC;AAAA,MACA,kBAAkB,CAAC,UAAU;AAC3B,2BAAmB,iBAAiB,KAAK;AAAA,MAC3C;AAAA,MACA,uBAAuB,CAAC,UAAU;AAChC,2BAAmB,sBAAsB,KAAK;AAAA,MAChD;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,yBAAyB,CAAC,UAAU;AAClC,2BAAmB,wBAAwB,KAAK;AAAA,MAClD;AAAA,MACA,gBAAgB,CAAC,UAAU;AACzB,2BAAmB,eAAe,KAAK;AAAA,MACzC;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,cAAc,CAAC,UAAU;AACvB,2BAAmB,aAAa,KAAK;AAAA,MACvC;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,4BAA4B,CAAC,YAAY;AACvC,eAAO,2BAA2B,OAAO;AAAA,MAC3C;AAAA,MACA,iBAAiB,CAAC,UAAU;AAC1B,iCAAyB,KAAK;AAAA,MAChC;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,IAAI,UAAsE;AAC1E,IAAI,oBAAoD;AAEjD,SAAS,gCAAgC;AAC9C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AACA,cAAY,iCAAiC;AAC7C,SAAO;AACT;AAEO,SAAS,4BACd,cACA;AACA,sBAAoB;AACtB;AAEO,SAAS,uBAAuD;AACrE,QAAM,iBAAiB,8BAA8B;AACrD,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,EACT;AACA,wBAAsB,sBAAsB,cAAc;AAC1D,SAAO;AACT;AAEO,SAAS,sBAAsB,OAGnC;AACD,QAAM,SAAS,qBAAqB;AACpC,MAAI,CAAC,QAAQ;AACX,WAAO,QAAQ;AAAA,MACb,IAAI,MAAM,2CAA2C;AAAA,IACvD;AAAA,EACF;AACA,SAAO,OAAO,sBAAsB,KAAK;AAC3C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|