@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.
@@ -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.19.5",
3
+ "version": "1.20.0",
4
4
  "branch": "HEAD",
5
- "commit": "925967a151b3e53a1891d5d57b0cf956b0f64ffe",
6
- "builtAt": "2026-10-28T00:16:14.622Z"
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.19.5",
3
+ "version": "1.20.0",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sandbox-runtime",
6
- "version": "1.19.5",
6
+ "version": "1.20.0",
7
7
  "branch": "HEAD",
8
- "commit": "925967a151b3e53a1891d5d57b0cf956b0f64ffe",
9
- "builtAt": "2026-10-28T00:16:14.622Z"
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,4 @@
1
+ export declare function pinPreviewViewportUnits({ width, height, }: {
2
+ width: number;
3
+ height: number;
4
+ }): void;
@@ -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
+ };
@@ -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, {}),