@replohq/sandbox-runtime 1.19.5 → 1.20.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/PagePreviewHeightResponder.d.ts +1 -0
- package/PagePreviewHeightResponder.js +159 -0
- package/_vendor/schemas/pagePreviewHeight.d.ts +14 -0
- package/_vendor/schemas/pagePreviewHeight.mjs +18 -0
- package/buildMetadata.js +3 -3
- package/package.json +5 -4
- package/pinPreviewViewportUnits.d.ts +4 -0
- package/pinPreviewViewportUnits.js +76 -0
- package/sandbox-runtime.js +2 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function PagePreviewHeightResponder(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
pagePreviewHeightRequestSchema,
|
|
5
|
+
PAGE_PREVIEW_MAX_HEIGHT
|
|
6
|
+
} from "./_vendor/schemas/pagePreviewHeight.mjs";
|
|
7
|
+
import { pinPreviewViewportUnits } from "./pinPreviewViewportUnits";
|
|
8
|
+
function startResponder() {
|
|
9
|
+
let parentOrigin = null;
|
|
10
|
+
let scheduledFrame = 0;
|
|
11
|
+
let awaitingMeasurement = false;
|
|
12
|
+
let reportedHeight = null;
|
|
13
|
+
let baselineRootHeight = "auto";
|
|
14
|
+
const measurementStyle = new CSSStyleSheet();
|
|
15
|
+
document.adoptedStyleSheets = [
|
|
16
|
+
...document.adoptedStyleSheets,
|
|
17
|
+
measurementStyle
|
|
18
|
+
];
|
|
19
|
+
const measure = () => {
|
|
20
|
+
scheduledFrame = 0;
|
|
21
|
+
if (!parentOrigin) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const body = document.body;
|
|
25
|
+
pinPreviewViewportUnits({
|
|
26
|
+
width: window.innerWidth,
|
|
27
|
+
height: window.innerHeight
|
|
28
|
+
});
|
|
29
|
+
const height = Math.min(
|
|
30
|
+
PAGE_PREVIEW_MAX_HEIGHT,
|
|
31
|
+
Math.ceil(
|
|
32
|
+
Math.max(
|
|
33
|
+
body.getBoundingClientRect().height,
|
|
34
|
+
body.scrollHeight,
|
|
35
|
+
document.documentElement.scrollHeight
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
baselineRootHeight = getComputedStyle(document.documentElement).height;
|
|
40
|
+
awaitingMeasurement = false;
|
|
41
|
+
if (height > 0) {
|
|
42
|
+
reportedHeight = height;
|
|
43
|
+
window.parent.postMessage(
|
|
44
|
+
{ type: "replo:page-preview-height:update", height },
|
|
45
|
+
parentOrigin
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const schedule = () => {
|
|
50
|
+
if (!parentOrigin || awaitingMeasurement) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
awaitingMeasurement = true;
|
|
54
|
+
window.parent.postMessage(
|
|
55
|
+
{ type: "replo:page-preview-height:reset" },
|
|
56
|
+
parentOrigin
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
const observer = new ResizeObserver(() => {
|
|
60
|
+
if (Math.ceil(document.body.getBoundingClientRect().height) === reportedHeight) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
schedule();
|
|
64
|
+
});
|
|
65
|
+
const mutations = new MutationObserver(schedule);
|
|
66
|
+
const receive = (event) => {
|
|
67
|
+
if (event.source !== window.parent || event.origin === "null") {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const message = pagePreviewHeightRequestSchema.safeParse(event.data);
|
|
71
|
+
if (!message.success) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
parentOrigin = event.origin;
|
|
75
|
+
if (message.data.type === "replo:page-preview-height:subscribe") {
|
|
76
|
+
observer.observe(document.body);
|
|
77
|
+
mutations.observe(document.body, {
|
|
78
|
+
childList: true,
|
|
79
|
+
subtree: true,
|
|
80
|
+
attributes: true,
|
|
81
|
+
characterData: true
|
|
82
|
+
});
|
|
83
|
+
schedule();
|
|
84
|
+
} else {
|
|
85
|
+
cancelAnimationFrame(scheduledFrame);
|
|
86
|
+
scheduledFrame = requestAnimationFrame(measure);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
window.addEventListener("message", receive);
|
|
90
|
+
const measureInteraction = () => {
|
|
91
|
+
if (!parentOrigin || awaitingMeasurement) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
cancelAnimationFrame(scheduledFrame);
|
|
95
|
+
scheduledFrame = requestAnimationFrame(() => {
|
|
96
|
+
scheduledFrame = 0;
|
|
97
|
+
if (!parentOrigin) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
measurementStyle.replaceSync(
|
|
101
|
+
`:root { height: ${baselineRootHeight} !important; min-height: 0 !important; max-height: none !important; }`
|
|
102
|
+
);
|
|
103
|
+
let height;
|
|
104
|
+
try {
|
|
105
|
+
height = Math.min(
|
|
106
|
+
PAGE_PREVIEW_MAX_HEIGHT,
|
|
107
|
+
Math.ceil(
|
|
108
|
+
Math.max(
|
|
109
|
+
document.body.scrollHeight,
|
|
110
|
+
document.body.getBoundingClientRect().height
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
} finally {
|
|
115
|
+
measurementStyle.replaceSync("");
|
|
116
|
+
}
|
|
117
|
+
if (height > 0) {
|
|
118
|
+
reportedHeight = height;
|
|
119
|
+
window.parent.postMessage(
|
|
120
|
+
{ type: "replo:page-preview-height:update", height },
|
|
121
|
+
parentOrigin
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
const events = [
|
|
127
|
+
"pointerover",
|
|
128
|
+
"pointerout",
|
|
129
|
+
"focusin",
|
|
130
|
+
"focusout",
|
|
131
|
+
"transitionend",
|
|
132
|
+
"animationend"
|
|
133
|
+
];
|
|
134
|
+
for (const event of events) {
|
|
135
|
+
document.addEventListener(event, measureInteraction, true);
|
|
136
|
+
}
|
|
137
|
+
document.addEventListener("load", schedule, true);
|
|
138
|
+
document.addEventListener("toggle", schedule, true);
|
|
139
|
+
return () => {
|
|
140
|
+
cancelAnimationFrame(scheduledFrame);
|
|
141
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
|
|
142
|
+
(sheet) => sheet !== measurementStyle
|
|
143
|
+
);
|
|
144
|
+
observer.disconnect();
|
|
145
|
+
mutations.disconnect();
|
|
146
|
+
window.removeEventListener("message", receive);
|
|
147
|
+
document.removeEventListener("load", schedule, true);
|
|
148
|
+
document.removeEventListener("toggle", schedule, true);
|
|
149
|
+
for (const event of events) {
|
|
150
|
+
document.removeEventListener(event, measureInteraction, true);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function PagePreviewHeightResponder() {
|
|
155
|
+
return /* @__PURE__ */ jsx("template", { ref: startResponder });
|
|
156
|
+
}
|
|
157
|
+
export {
|
|
158
|
+
PagePreviewHeightResponder
|
|
159
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as z from "zod/mini";
|
|
2
|
+
export declare const PAGE_PREVIEW_MAX_HEIGHT = 100000;
|
|
3
|
+
export declare const pagePreviewHeightRequestSchema: z.ZodMiniObject<{
|
|
4
|
+
type: z.ZodMiniEnum<{
|
|
5
|
+
"replo:page-preview-height:subscribe": "replo:page-preview-height:subscribe";
|
|
6
|
+
"replo:page-preview-height:measure": "replo:page-preview-height:measure";
|
|
7
|
+
}>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
export declare const pagePreviewHeightResponseSchema: z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
|
|
10
|
+
type: z.ZodMiniLiteral<"replo:page-preview-height:update">;
|
|
11
|
+
height: z.ZodMiniNumber<number>;
|
|
12
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
13
|
+
type: z.ZodMiniLiteral<"replo:page-preview-height:reset">;
|
|
14
|
+
}, z.core.$strip>], "type">;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as z from 'zod/mini';
|
|
2
|
+
|
|
3
|
+
var PAGE_PREVIEW_MAX_HEIGHT = 1e5;
|
|
4
|
+
var pagePreviewHeightRequestSchema = z.object({
|
|
5
|
+
type: z.enum([
|
|
6
|
+
"replo:page-preview-height:subscribe",
|
|
7
|
+
"replo:page-preview-height:measure"
|
|
8
|
+
])
|
|
9
|
+
});
|
|
10
|
+
var pagePreviewHeightResponseSchema = z.discriminatedUnion("type", [
|
|
11
|
+
z.object({
|
|
12
|
+
type: z.literal("replo:page-preview-height:update"),
|
|
13
|
+
height: z.number().check(z.minimum(1), z.maximum(PAGE_PREVIEW_MAX_HEIGHT))
|
|
14
|
+
}),
|
|
15
|
+
z.object({ type: z.literal("replo:page-preview-height:reset") })
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
export { PAGE_PREVIEW_MAX_HEIGHT, pagePreviewHeightRequestSchema, pagePreviewHeightResponseSchema };
|
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.20.0",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-10-
|
|
5
|
+
"commit": "17c6d4e2e064b7d35efe5732361372f119e931b5",
|
|
6
|
+
"builtAt": "2026-10-29T03:14:43.608Z"
|
|
7
7
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sandbox-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sandbox-runtime",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.20.0",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-10-
|
|
8
|
+
"commit": "17c6d4e2e064b7d35efe5732361372f119e931b5",
|
|
9
|
+
"builtAt": "2026-10-29T03:14:43.608Z"
|
|
10
10
|
},
|
|
11
11
|
"description": "Replo sandbox runtime — editor integration for agent-built Next.js sites.",
|
|
12
12
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@tiptap/pm": "^2.25.0",
|
|
36
36
|
"@zumer/snapdom": "^3.0.0",
|
|
37
37
|
"async-retry": "^1.3.3",
|
|
38
|
+
"postcss-value-parser": "4.2.0",
|
|
38
39
|
"uuid": "^11.1.0",
|
|
39
40
|
"zod": "^4.3.6",
|
|
40
41
|
"zustand": "^4.5.7"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import valueParser from "postcss-value-parser";
|
|
2
|
+
function pinPreviewViewportUnits({
|
|
3
|
+
width,
|
|
4
|
+
height
|
|
5
|
+
}) {
|
|
6
|
+
const sizes = {
|
|
7
|
+
vh: height,
|
|
8
|
+
svh: height,
|
|
9
|
+
lvh: height,
|
|
10
|
+
dvh: height,
|
|
11
|
+
vmin: Math.min(width, height),
|
|
12
|
+
vmax: Math.max(width, height)
|
|
13
|
+
};
|
|
14
|
+
const pinDeclaration = (style) => {
|
|
15
|
+
for (const property of Array.from(style)) {
|
|
16
|
+
const value = style.getPropertyValue(property);
|
|
17
|
+
if (!/[0-9.](?:[sld]?vh|vmin|vmax)\b/iu.test(value)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const parsed = valueParser(value);
|
|
21
|
+
let changed = false;
|
|
22
|
+
parsed.walk((node) => {
|
|
23
|
+
if (node.type === "function" && node.value.toLowerCase() === "url") {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (node.type !== "word") {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const dimension = valueParser.unit(node.value);
|
|
30
|
+
if (!dimension || !Object.hasOwn(sizes, dimension.unit.toLowerCase())) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
node.value = `${Number(dimension.number) * sizes[dimension.unit.toLowerCase()] / 100}px`;
|
|
34
|
+
changed = true;
|
|
35
|
+
});
|
|
36
|
+
if (changed) {
|
|
37
|
+
style.setProperty(
|
|
38
|
+
property,
|
|
39
|
+
parsed.toString(),
|
|
40
|
+
style.getPropertyPriority(property)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const pinRules = (rules) => {
|
|
46
|
+
for (const rule of Array.from(rules)) {
|
|
47
|
+
if (rule instanceof CSSStyleRule) {
|
|
48
|
+
pinDeclaration(rule.style);
|
|
49
|
+
}
|
|
50
|
+
if (rule instanceof CSSGroupingRule) {
|
|
51
|
+
pinRules(rule.cssRules);
|
|
52
|
+
}
|
|
53
|
+
if (rule instanceof CSSImportRule && rule.styleSheet) {
|
|
54
|
+
pinSheet(rule.styleSheet);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const pinSheet = (sheet) => {
|
|
59
|
+
try {
|
|
60
|
+
pinRules(sheet.cssRules);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (!(error instanceof DOMException && error.name === "SecurityError")) {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
68
|
+
pinSheet(sheet);
|
|
69
|
+
}
|
|
70
|
+
for (const element of document.querySelectorAll("[style]")) {
|
|
71
|
+
pinDeclaration(element.style);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
pinPreviewViewportUnits
|
|
76
|
+
};
|
package/sandbox-runtime.js
CHANGED
|
@@ -9,6 +9,7 @@ import { HeatLayerMount } from "./heatmaps/HeatLayerMount";
|
|
|
9
9
|
import LinkInterceptor from "./LinkInterceptor";
|
|
10
10
|
import { NavigationReceiver } from "./NavigationReceiver";
|
|
11
11
|
import { PageCaptureResponder } from "./PageCaptureResponder";
|
|
12
|
+
import { PagePreviewHeightResponder } from "./PagePreviewHeightResponder";
|
|
12
13
|
import PostHogRelay from "./posthog-relay";
|
|
13
14
|
import { EditorSelection } from "./select-mode/EditorSelection";
|
|
14
15
|
function ViewportSnapshotResponder() {
|
|
@@ -25,6 +26,7 @@ function SandboxRuntime({ children }) {
|
|
|
25
26
|
/* @__PURE__ */ jsx(PostHogRelay, {}),
|
|
26
27
|
/* @__PURE__ */ jsx(ViewportSnapshotResponder, {}),
|
|
27
28
|
/* @__PURE__ */ jsx(PageCaptureResponder, {}),
|
|
29
|
+
/* @__PURE__ */ jsx(PagePreviewHeightResponder, {}),
|
|
28
30
|
/* @__PURE__ */ jsx(EditorSelection, {}),
|
|
29
31
|
/* @__PURE__ */ jsx(AnnotationLayerMount, {}),
|
|
30
32
|
/* @__PURE__ */ jsx(HeatLayerMount, {}),
|