@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.
@@ -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): import("react/jsx-runtime").JSX.Element;
10
+ export declare function ClientErrorBoundary({ children, resetKey, }: React.PropsWithChildren<{
11
+ resetKey: React.ReactNode;
12
+ }>): import("react/jsx-runtime").JSX.Element;
@@ -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({ children }) {
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.6",
3
+ "version": "1.7.8",
4
4
  "branch": "HEAD",
5
- "commit": "eebf20f7ddeeb977a292b14a7abe974b07255b14",
6
- "builtAt": "2026-09-18T20:52:15.073Z"
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.6",
3
+ "version": "1.7.8",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sandbox-runtime",
6
- "version": "1.7.6",
6
+ "version": "1.7.8",
7
7
  "branch": "HEAD",
8
- "commit": "eebf20f7ddeeb977a292b14a7abe974b07255b14",
9
- "builtAt": "2026-09-18T20:52:15.073Z"
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",
@@ -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 { symbolicateSelectedElement } from "./symbolicate";
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
- const session = interactionSessionRef.current;
43
- if (session.type !== "element") {
44
- return;
45
- }
46
- const element = getConnectedSelectedElement(session);
47
- if (!element) {
48
- setSelectionType({ selectionType: "none" });
49
- getWebsiteBuilderRpc()?.areaSelected({
50
- rect: session.data.rect,
51
- items: []
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
- return;
54
- }
55
- const siblingElements = getRepetitionSiblingElements({ element });
56
- const descriptor = buildElementDescriptor({
57
- element,
58
- clickPosition: session.clickPosition ?? (session.data.kind === "react-element" ? session.data.clickPosition : { x: 0, y: 0 }),
59
- siblingSelectors: siblingElements.map(buildSelector)
60
- });
61
- if (descriptor.kind !== "react-element") {
62
- return;
63
- }
64
- const refreshedSession = {
65
- ...session,
66
- element,
67
- siblingElements,
68
- data: descriptor
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
- interactionSessionRef.current = refreshedSession;
71
- showElementSelectionFrames({
72
- elements: [element, ...siblingElements],
73
- scrollOffset: getDocumentScrollOffset()
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
- }, [interactionSessionRef, setSelectionType]);
82
- useEffect(() => {
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
- postSelectedElementSnapshot();
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
- window.removeEventListener(
95
- PREVIEW_RENDERED_EVENT,
96
- postSelectedElementSnapshot
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
- }, [editingElementRef, postSelectedElementSnapshot, reapplyOverrides]);
149
+ }, [
150
+ editingElementRef,
151
+ interactionSessionRef,
152
+ postSelectedElementSnapshot,
153
+ reapplyOverrides
154
+ ]);
101
155
  useParentMessaging({
102
156
  applyOptimisticUpdate,
103
157
  markCommitted,
@@ -1,3 +1,8 @@
1
+ declare global {
2
+ interface Window {
3
+ __NEXT_HMR_LATENCY_CB: ((latencyMs: number) => void) | undefined;
4
+ }
5
+ }
1
6
  export declare function installFastRefreshRelay({ onComplete, }?: {
2
7
  onComplete?: () => void;
3
8
  }): void;
@@ -10,25 +10,12 @@ function installFastRefreshRelay({
10
10
  return;
11
11
  }
12
12
  hasInstalledFastRefreshRelay = true;
13
- const originalLog = console.log;
14
- const originalInfo = console.info;
15
- const relayIfFastRefreshComplete = (...args) => {
16
- const message = args.join(" ");
17
- if (message.includes("[Fast Refresh] rebuilding") || message.includes("[Fast Refresh] done")) {
18
- invalidateSymbolicationCache();
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 !isLikelyCompiledLocation(entry.sourceLocation) && !isDependencyOrInternalPath(entry.sourceLocation.filePath);
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
  };