@replohq/sandbox-runtime 1.7.6 → 1.7.8
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/ClientErrorBoundary.d.ts +3 -1
- package/ClientErrorBoundary.js +10 -2
- package/_vendor/schemas/componentPreview.mjs +1 -0
- package/_vendor/schemas/loaderKeys.d.ts +2 -0
- package/buildMetadata.js +3 -3
- package/package.json +4 -4
- package/sandbox-runtime.js +1 -1
- package/select-mode/EditorSelection.js +103 -49
- package/select-mode/fast-refresh-relay.d.ts +5 -0
- package/select-mode/fast-refresh-relay.js +6 -19
- package/select-mode/symbolicate.d.ts +2 -1
- package/select-mode/symbolicate.js +7 -1
package/ClientErrorBoundary.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ import * as React from "react";
|
|
|
7
7
|
* vs. an actionable error screen); the embedder reloads the iframe once the error
|
|
8
8
|
* clears.
|
|
9
9
|
*/
|
|
10
|
-
export declare function ClientErrorBoundary({ children }: React.PropsWithChildren
|
|
10
|
+
export declare function ClientErrorBoundary({ children, resetKey, }: React.PropsWithChildren<{
|
|
11
|
+
resetKey: React.ReactNode;
|
|
12
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
package/ClientErrorBoundary.js
CHANGED
|
@@ -11,6 +11,11 @@ class ErrorBoundary extends React.Component {
|
|
|
11
11
|
componentDidCatch(error, info) {
|
|
12
12
|
this.props.onError?.(error, info);
|
|
13
13
|
}
|
|
14
|
+
componentDidUpdate(previousProps, previousState) {
|
|
15
|
+
if (this.state.didCatch && previousState.didCatch && !Object.is(previousProps.resetKey, this.props.resetKey)) {
|
|
16
|
+
this.setState({ didCatch: false });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
14
19
|
render() {
|
|
15
20
|
if (this.state.didCatch) {
|
|
16
21
|
return /* @__PURE__ */ jsx(
|
|
@@ -28,7 +33,10 @@ class ErrorBoundary extends React.Component {
|
|
|
28
33
|
return this.props.children;
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
|
-
function ClientErrorBoundary({
|
|
36
|
+
function ClientErrorBoundary({
|
|
37
|
+
children,
|
|
38
|
+
resetKey
|
|
39
|
+
}) {
|
|
32
40
|
const handleError = React.useCallback(
|
|
33
41
|
(error, errorInfo) => {
|
|
34
42
|
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
@@ -49,7 +57,7 @@ function ClientErrorBoundary({ children }) {
|
|
|
49
57
|
},
|
|
50
58
|
[]
|
|
51
59
|
);
|
|
52
|
-
return /* @__PURE__ */ jsx(ErrorBoundary, { onError: handleError, children });
|
|
60
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, { onError: handleError, resetKey, children });
|
|
53
61
|
}
|
|
54
62
|
export {
|
|
55
63
|
ClientErrorBoundary
|
|
@@ -6,6 +6,7 @@ var DATA_LOADER_KEYS = {
|
|
|
6
6
|
SHOPIFY_COLLECTION_PRODUCTS: "shopify_storefront.collection_products",
|
|
7
7
|
SHOPIFY_METAOBJECT: "shopify_storefront.metaobject",
|
|
8
8
|
SHOPIFY_METAOBJECTS: "shopify_storefront.metaobjects",
|
|
9
|
+
SHOPIFY_KACHING_BUNDLES: "shopify_storefront.kaching_bundles",
|
|
9
10
|
REPLO_PRODUCT: "replo_products.product",
|
|
10
11
|
OKENDO_PRODUCT_REVIEWS: "okendo.product_reviews",
|
|
11
12
|
OKENDO_PRODUCT_REVIEW_AGGREGATE: "okendo.product_review_aggregate",
|
|
@@ -16,6 +16,7 @@ export declare const DATA_LOADER_KEYS: {
|
|
|
16
16
|
readonly SHOPIFY_COLLECTION_PRODUCTS: "shopify_storefront.collection_products";
|
|
17
17
|
readonly SHOPIFY_METAOBJECT: "shopify_storefront.metaobject";
|
|
18
18
|
readonly SHOPIFY_METAOBJECTS: "shopify_storefront.metaobjects";
|
|
19
|
+
readonly SHOPIFY_KACHING_BUNDLES: "shopify_storefront.kaching_bundles";
|
|
19
20
|
readonly REPLO_PRODUCT: "replo_products.product";
|
|
20
21
|
readonly OKENDO_PRODUCT_REVIEWS: "okendo.product_reviews";
|
|
21
22
|
readonly OKENDO_PRODUCT_REVIEW_AGGREGATE: "okendo.product_review_aggregate";
|
|
@@ -43,6 +44,7 @@ export declare const dataLoaderKeySchema: z.ZodEnum<{
|
|
|
43
44
|
"shopify_storefront.collection_products": "shopify_storefront.collection_products";
|
|
44
45
|
"shopify_storefront.metaobject": "shopify_storefront.metaobject";
|
|
45
46
|
"shopify_storefront.metaobjects": "shopify_storefront.metaobjects";
|
|
47
|
+
"shopify_storefront.kaching_bundles": "shopify_storefront.kaching_bundles";
|
|
46
48
|
"replo_products.product": "replo_products.product";
|
|
47
49
|
"okendo.product_reviews": "okendo.product_reviews";
|
|
48
50
|
"okendo.product_review_aggregate": "okendo.product_review_aggregate";
|
package/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sandbox-runtime",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-09-
|
|
5
|
+
"commit": "3373cb130518e3250ca842e09a47b68ec42c48c0",
|
|
6
|
+
"builtAt": "2026-09-19T01:22:45.241Z"
|
|
7
7
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sandbox-runtime",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sandbox-runtime",
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.8",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-09-
|
|
8
|
+
"commit": "3373cb130518e3250ca842e09a47b68ec42c48c0",
|
|
9
|
+
"builtAt": "2026-09-19T01:22:45.241Z"
|
|
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
|
@@ -19,7 +19,7 @@ function SandboxRuntime({ children }) {
|
|
|
19
19
|
return isDevServer ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20
20
|
/* @__PURE__ */ jsx(DocumentReadyBeacon, {}),
|
|
21
21
|
/* @__PURE__ */ jsx(NextErrorReporter, {}),
|
|
22
|
-
/* @__PURE__ */ jsxs(ClientErrorBoundary, { children: [
|
|
22
|
+
/* @__PURE__ */ jsxs(ClientErrorBoundary, { resetKey: children, children: [
|
|
23
23
|
/* @__PURE__ */ jsx(LinkInterceptor, {}),
|
|
24
24
|
/* @__PURE__ */ jsx(NavigationReceiver, {}),
|
|
25
25
|
/* @__PURE__ */ jsx(PostHogRelay, {}),
|
|
@@ -19,7 +19,10 @@ import { getDocumentScrollOffset } from "./interactions/selectionGeometry";
|
|
|
19
19
|
import { PREVIEW_RENDERED_EVENT } from "./previewRendered";
|
|
20
20
|
import { showElementSelectionFrames } from "./selectionFrame";
|
|
21
21
|
import { getConnectedSelectedElement } from "./selectModeSession";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
isUserSourceLocation,
|
|
24
|
+
symbolicateSelectedElement
|
|
25
|
+
} from "./symbolicate";
|
|
23
26
|
function EditorSelection() {
|
|
24
27
|
const {
|
|
25
28
|
displayMode,
|
|
@@ -38,66 +41,117 @@ function EditorSelection() {
|
|
|
38
41
|
resolveSessionOverrides,
|
|
39
42
|
revertOverride
|
|
40
43
|
} = useOptimisticOverrides();
|
|
41
|
-
const postSelectedElementSnapshot = useCallback(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
const postSelectedElementSnapshot = useCallback(
|
|
45
|
+
({ clearMissing = false } = {}) => {
|
|
46
|
+
const session = interactionSessionRef.current;
|
|
47
|
+
if (session.type !== "element") {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
const element = getConnectedSelectedElement(session);
|
|
51
|
+
if (!element) {
|
|
52
|
+
if (!clearMissing) return false;
|
|
53
|
+
setSelectionType({ selectionType: "none" });
|
|
54
|
+
getWebsiteBuilderRpc()?.areaSelected({
|
|
55
|
+
rect: session.data.rect,
|
|
56
|
+
items: []
|
|
57
|
+
});
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
const siblingElements = getRepetitionSiblingElements({ element });
|
|
61
|
+
const descriptor = buildElementDescriptor({
|
|
62
|
+
element,
|
|
63
|
+
clickPosition: session.clickPosition ?? (session.data.kind === "react-element" ? session.data.clickPosition : { x: 0, y: 0 }),
|
|
64
|
+
siblingSelectors: siblingElements.map(buildSelector)
|
|
52
65
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if (descriptor.kind !== "react-element") {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
const refreshedSession = {
|
|
70
|
+
...session,
|
|
71
|
+
element,
|
|
72
|
+
siblingElements,
|
|
73
|
+
data: session.data
|
|
74
|
+
};
|
|
75
|
+
interactionSessionRef.current = refreshedSession;
|
|
76
|
+
showElementSelectionFrames({
|
|
77
|
+
elements: [element, ...siblingElements],
|
|
78
|
+
scrollOffset: getDocumentScrollOffset()
|
|
79
|
+
});
|
|
80
|
+
void symbolicateSelectedElement(descriptor).then((symbolicated) => {
|
|
81
|
+
if (interactionSessionRef.current !== refreshedSession) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (symbolicated.sourceLocation && !isUserSourceLocation(symbolicated.sourceLocation)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
refreshedSession.data = symbolicated;
|
|
88
|
+
getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });
|
|
89
|
+
});
|
|
90
|
+
return true;
|
|
91
|
+
},
|
|
92
|
+
[interactionSessionRef, setSelectionType]
|
|
93
|
+
);
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
let refreshTimeout;
|
|
96
|
+
let missingTimeout;
|
|
97
|
+
let observationTimeout;
|
|
98
|
+
const scheduleSnapshot = () => {
|
|
99
|
+
clearTimeout(refreshTimeout);
|
|
100
|
+
refreshTimeout = setTimeout(() => {
|
|
101
|
+
if (editingElementRef.current) return;
|
|
102
|
+
if (postSelectedElementSnapshot()) {
|
|
103
|
+
clearTimeout(missingTimeout);
|
|
104
|
+
missingTimeout = void 0;
|
|
105
|
+
} else if (!missingTimeout) {
|
|
106
|
+
const missingSession = interactionSessionRef.current;
|
|
107
|
+
missingTimeout = setTimeout(() => {
|
|
108
|
+
missingTimeout = void 0;
|
|
109
|
+
if (interactionSessionRef.current === missingSession) {
|
|
110
|
+
postSelectedElementSnapshot({ clearMissing: true });
|
|
111
|
+
}
|
|
112
|
+
}, 5e3);
|
|
113
|
+
}
|
|
114
|
+
}, 250);
|
|
69
115
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
void symbolicateSelectedElement(descriptor).then((symbolicated) => {
|
|
76
|
-
if (interactionSessionRef.current !== refreshedSession) {
|
|
77
|
-
return;
|
|
116
|
+
const observer = new MutationObserver((records) => {
|
|
117
|
+
const session = interactionSessionRef.current;
|
|
118
|
+
if (editingElementRef.current || session.type !== "element") return;
|
|
119
|
+
if (!session.element.isConnected || records.some((record) => session.element.contains(record.target))) {
|
|
120
|
+
scheduleSnapshot();
|
|
78
121
|
}
|
|
79
|
-
getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });
|
|
80
122
|
});
|
|
81
|
-
|
|
82
|
-
|
|
123
|
+
const watchRender = () => {
|
|
124
|
+
if (editingElementRef.current || interactionSessionRef.current.type !== "element")
|
|
125
|
+
return;
|
|
126
|
+
clearTimeout(observationTimeout);
|
|
127
|
+
observer.observe(document.body, {
|
|
128
|
+
subtree: true,
|
|
129
|
+
childList: true
|
|
130
|
+
});
|
|
131
|
+
observationTimeout = setTimeout(() => observer.disconnect(), 5e3);
|
|
132
|
+
scheduleSnapshot();
|
|
133
|
+
};
|
|
83
134
|
installFastRefreshRelay({
|
|
84
135
|
onComplete: () => {
|
|
85
136
|
reapplyOverrides({ skipElement: editingElementRef.current });
|
|
86
|
-
|
|
137
|
+
watchRender();
|
|
87
138
|
}
|
|
88
139
|
});
|
|
89
|
-
window.addEventListener(
|
|
90
|
-
PREVIEW_RENDERED_EVENT,
|
|
91
|
-
postSelectedElementSnapshot
|
|
92
|
-
);
|
|
140
|
+
window.addEventListener(PREVIEW_RENDERED_EVENT, watchRender);
|
|
93
141
|
return () => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
142
|
+
clearTimeout(refreshTimeout);
|
|
143
|
+
clearTimeout(missingTimeout);
|
|
144
|
+
clearTimeout(observationTimeout);
|
|
145
|
+
observer.disconnect();
|
|
146
|
+
window.removeEventListener(PREVIEW_RENDERED_EVENT, watchRender);
|
|
98
147
|
installFastRefreshRelay();
|
|
99
148
|
};
|
|
100
|
-
}, [
|
|
149
|
+
}, [
|
|
150
|
+
editingElementRef,
|
|
151
|
+
interactionSessionRef,
|
|
152
|
+
postSelectedElementSnapshot,
|
|
153
|
+
reapplyOverrides
|
|
154
|
+
]);
|
|
101
155
|
useParentMessaging({
|
|
102
156
|
applyOptimisticUpdate,
|
|
103
157
|
markCommitted,
|
|
@@ -10,25 +10,12 @@ function installFastRefreshRelay({
|
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
hasInstalledFastRefreshRelay = true;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
if (message.includes("[Fast Refresh] done")) {
|
|
21
|
-
getWebsiteBuilderRpc()?.fastRefreshComplete(void 0);
|
|
22
|
-
onFastRefreshComplete?.();
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
console.log = (...args) => {
|
|
26
|
-
relayIfFastRefreshComplete(...args);
|
|
27
|
-
originalLog(...args);
|
|
28
|
-
};
|
|
29
|
-
console.info = (...args) => {
|
|
30
|
-
relayIfFastRefreshComplete(...args);
|
|
31
|
-
originalInfo(...args);
|
|
13
|
+
const originalCallback = window.__NEXT_HMR_LATENCY_CB;
|
|
14
|
+
window.__NEXT_HMR_LATENCY_CB = (latencyMs) => {
|
|
15
|
+
invalidateSymbolicationCache();
|
|
16
|
+
getWebsiteBuilderRpc()?.fastRefreshComplete(void 0);
|
|
17
|
+
onFastRefreshComplete?.();
|
|
18
|
+
originalCallback?.(latencyMs);
|
|
32
19
|
};
|
|
33
20
|
}
|
|
34
21
|
export {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { SelectedElement } from "../_vendor/schemas/generated/selectMode";
|
|
1
|
+
import type { SelectedElement, SelectModeSourceLocation } from "../_vendor/schemas/generated/selectMode";
|
|
2
2
|
export declare function invalidateSymbolicationCache(): void;
|
|
3
|
+
export declare function isUserSourceLocation(location: SelectModeSourceLocation | undefined): boolean;
|
|
3
4
|
export declare function symbolicateSelectedElement(selectedElement: SelectedElement): Promise<SelectedElement>;
|
|
@@ -186,9 +186,14 @@ function applyResolved({
|
|
|
186
186
|
componentName: original.componentName
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
+
function isUserSourceLocation(location) {
|
|
190
|
+
return Boolean(
|
|
191
|
+
location && !isLikelyCompiledLocation(location) && !isDependencyOrInternalPath(location.filePath)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
189
194
|
function findUserSourceLocation(fiberChain) {
|
|
190
195
|
return fiberChain.find((entry) => {
|
|
191
|
-
return
|
|
196
|
+
return isUserSourceLocation(entry.sourceLocation);
|
|
192
197
|
})?.sourceLocation;
|
|
193
198
|
}
|
|
194
199
|
async function symbolicateSelectedElement(selectedElement) {
|
|
@@ -235,5 +240,6 @@ async function symbolicateSelectedElement(selectedElement) {
|
|
|
235
240
|
}
|
|
236
241
|
export {
|
|
237
242
|
invalidateSymbolicationCache,
|
|
243
|
+
isUserSourceLocation,
|
|
238
244
|
symbolicateSelectedElement
|
|
239
245
|
};
|