@replohq/sandbox-runtime 1.16.2 → 1.18.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.
Files changed (56) hide show
  1. package/ClientErrorBoundary.js +26 -0
  2. package/DocumentReadyBeacon.js +5 -1
  3. package/_vendor/replo-utils/lib/historyKeys.d.ts +2 -0
  4. package/_vendor/replo-utils/lib/historyKeys.mjs +18 -0
  5. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +43 -0
  6. package/_vendor/schemas/iframeRpcChannel.mjs +3 -541
  7. package/_vendor/schemas/previewHealthIframeRpc.d.ts +159 -0
  8. package/_vendor/schemas/previewHealthIframeRpc.mjs +123 -0
  9. package/_vendor/schemas/selectModeIframeRpc.d.ts +149 -3
  10. package/_vendor/schemas/selectModeIframeRpc.mjs +72 -2
  11. package/buildMetadata.js +3 -3
  12. package/chunk-KRA4LUIR.mjs +541 -0
  13. package/nextErrorFeed.d.ts +30 -0
  14. package/nextErrorFeed.js +64 -0
  15. package/package.json +5 -12
  16. package/previewHealth.d.ts +25 -0
  17. package/previewHealth.js +431 -0
  18. package/sandbox-runtime.js +0 -2
  19. package/select-mode/EditorSelection.js +5 -1
  20. package/select-mode/fast-refresh-relay.js +82 -3
  21. package/select-mode/fiber.d.ts +6 -0
  22. package/select-mode/fiber.js +33 -0
  23. package/select-mode/hooks/useParentMessaging.js +10 -3
  24. package/select-mode/hooks/useSelectionHover.js +2 -1
  25. package/select-mode/hooks/useSelectionInteractions.js +10 -0
  26. package/select-mode/iframeRpcChannel.d.ts +46 -2
  27. package/select-mode/iframeRpcChannel.js +7 -0
  28. package/select-mode/section-canvas/SectionCanvas.d.ts +7 -0
  29. package/select-mode/section-canvas/SectionCanvas.js +599 -0
  30. package/select-mode/section-canvas/optimisticSectionMove.d.ts +39 -0
  31. package/select-mode/section-canvas/optimisticSectionMove.js +172 -0
  32. package/select-mode/section-canvas/sectionCanvasControls.d.ts +3 -0
  33. package/select-mode/section-canvas/sectionCanvasControls.js +8 -0
  34. package/select-mode/section-canvas/sectionCanvasStore.d.ts +71 -0
  35. package/select-mode/section-canvas/sectionCanvasStore.js +275 -0
  36. package/select-mode/section-canvas/sectionElements.d.ts +16 -0
  37. package/select-mode/section-canvas/sectionElements.js +94 -0
  38. package/select-mode/section-canvas/sectionGhost.d.ts +5 -0
  39. package/select-mode/section-canvas/sectionGhost.js +23 -0
  40. package/select-mode/symbolicate.d.ts +2 -0
  41. package/select-mode/symbolicate.js +18 -1
  42. package/NextErrorReporter.d.ts +0 -1
  43. package/NextErrorReporter.js +0 -131
  44. package/_vendor/schemas/componentPreview.d.ts +0 -43
  45. package/_vendor/schemas/componentPreview.mjs +0 -79
  46. package/_vendor/schemas/generated/componentPreview.d.ts +0 -5
  47. package/_vendor/schemas/generated/componentPreview.mjs +0 -1
  48. package/_vendor/schemas/loaderKeys.d.ts +0 -69
  49. package/next/component-preview-client.d.ts +0 -8
  50. package/next/component-preview-client.js +0 -227
  51. package/next/component-preview-href.d.ts +0 -5
  52. package/next/component-preview-href.js +0 -13
  53. package/next/component-preview-props.d.ts +0 -8
  54. package/next/component-preview-props.js +0 -35
  55. package/next/component-preview.d.ts +0 -11
  56. package/next/component-preview.js +0 -83
@@ -190,6 +190,22 @@ function applyResolved({
190
190
  componentName: original.componentName
191
191
  };
192
192
  }
193
+ async function symbolicateSourceLocations(locations) {
194
+ const compiledIndices = locations.flatMap((location, index) => {
195
+ return isLikelyCompiledLocation(location) ? [index] : [];
196
+ });
197
+ const resolved = await symbolicateFrames(
198
+ compiledIndices.map((index) => toNextStackFrame(locations[index]))
199
+ );
200
+ const result = [...locations];
201
+ for (const [position, index] of compiledIndices.entries()) {
202
+ result[index] = applyResolved({
203
+ original: locations[index],
204
+ frame: extractResolvedFrame(resolved[position] ?? null)
205
+ });
206
+ }
207
+ return result;
208
+ }
193
209
  function isUserSourceLocation(location) {
194
210
  return Boolean(
195
211
  location && !isLikelyCompiledLocation(location) && !isDependencyOrInternalPath(location.filePath)
@@ -245,5 +261,6 @@ async function symbolicateSelectedElement(selectedElement) {
245
261
  export {
246
262
  invalidateSymbolicationCache,
247
263
  isUserSourceLocation,
248
- symbolicateSelectedElement
264
+ symbolicateSelectedElement,
265
+ symbolicateSourceLocations
249
266
  };
@@ -1 +0,0 @@
1
- export declare function NextErrorReporter(): null;
@@ -1,131 +0,0 @@
1
- "use client";
2
- import * as React from "react";
3
- import {
4
- isAllowedEditorMessage,
5
- isAllowedEditorOrigin
6
- } from "./annotations/bridgeGate";
7
- const ERRORED_BADGE_SELECTOR = '[data-next-badge][data-error="true"]';
8
- const COLLECTED_ISSUE_SELECTOR = "[data-nextjs-dialog]";
9
- const CLOSED_DIALOG_OVERLAY_SELECTOR = '[data-nextjs-dialog-overlay][data-rendered="false"]';
10
- const RED_CHROME_SELECTOR = `${ERRORED_BADGE_SELECTOR}, ${COLLECTED_ISSUE_SELECTOR}`;
11
- const STATUS_LATCH_MS = 500;
12
- function findInitialEditorOrigin() {
13
- if (window.self === window.top) {
14
- return null;
15
- }
16
- const ancestorOrigin = "ancestorOrigins" in window.location ? window.location.ancestorOrigins.item(0) : null;
17
- return [ancestorOrigin, getOriginOrNull(document.referrer)].find((origin) => {
18
- return origin !== null && isAllowedEditorOrigin(origin);
19
- }) ?? null;
20
- }
21
- function getOriginOrNull(url) {
22
- try {
23
- return new URL(url).origin;
24
- } catch {
25
- return null;
26
- }
27
- }
28
- function NextErrorReporter() {
29
- React.useEffect(() => {
30
- let editorOrigin = findInitialEditorOrigin();
31
- let lastStatus = null;
32
- let shadowObserver = null;
33
- let observedRoot = null;
34
- let pendingPost = null;
35
- const deliver = () => {
36
- if (editorOrigin === null || lastStatus === null) {
37
- return;
38
- }
39
- window.parent.postMessage(
40
- {
41
- type: "replo:preview:status",
42
- route: window.location.pathname,
43
- status: lastStatus
44
- },
45
- editorOrigin
46
- );
47
- };
48
- const postNow = (status) => {
49
- if (lastStatus === status) {
50
- return;
51
- }
52
- lastStatus = status;
53
- deliver();
54
- };
55
- const handleParentMessage = (event) => {
56
- if (event.source !== window.parent || !isAllowedEditorMessage(event)) {
57
- return;
58
- }
59
- if (event.origin === editorOrigin) {
60
- return;
61
- }
62
- editorOrigin = event.origin;
63
- deliver();
64
- };
65
- window.addEventListener("message", handleParentMessage);
66
- const post = (status) => {
67
- if (pendingPost) {
68
- if (pendingPost.status === status) {
69
- return;
70
- }
71
- window.clearTimeout(pendingPost.timeoutId);
72
- pendingPost = null;
73
- }
74
- if (lastStatus === status) {
75
- return;
76
- }
77
- if (lastStatus === null && status === "ok") {
78
- postNow(status);
79
- return;
80
- }
81
- const timeoutId = window.setTimeout(() => {
82
- pendingPost = null;
83
- postNow(status);
84
- }, STATUS_LATCH_MS);
85
- pendingPost = { status, timeoutId };
86
- };
87
- const syncOverlayState = () => {
88
- const portal = document.getElementsByTagName("nextjs-portal")[0];
89
- if (!(portal instanceof HTMLElement)) {
90
- post("ok");
91
- return;
92
- }
93
- const root = portal.shadowRoot;
94
- if (root && root !== observedRoot) {
95
- shadowObserver?.disconnect();
96
- shadowObserver = new MutationObserver(syncOverlayState);
97
- shadowObserver.observe(root, {
98
- childList: true,
99
- subtree: true,
100
- characterData: true,
101
- attributes: true,
102
- attributeFilter: ["data-error", "data-rendered"]
103
- });
104
- observedRoot = root;
105
- }
106
- portal.style.display = root?.querySelector(RED_CHROME_SELECTOR) ? "none" : "";
107
- const dialog = root?.querySelector(COLLECTED_ISSUE_SELECTOR) ?? null;
108
- post(
109
- dialog && !dialog.closest(CLOSED_DIALOG_OVERLAY_SELECTOR) ? "error" : "ok"
110
- );
111
- };
112
- const lightObserver = new MutationObserver(syncOverlayState);
113
- lightObserver.observe(document.documentElement, {
114
- childList: true,
115
- subtree: true
116
- });
117
- syncOverlayState();
118
- return () => {
119
- window.removeEventListener("message", handleParentMessage);
120
- lightObserver.disconnect();
121
- shadowObserver?.disconnect();
122
- if (pendingPost) {
123
- window.clearTimeout(pendingPost.timeoutId);
124
- }
125
- };
126
- }, []);
127
- return null;
128
- }
129
- export {
130
- NextErrorReporter
131
- };
@@ -1,43 +0,0 @@
1
- import * as z from "zod";
2
- export declare const MAX_COMPONENT_PREVIEW_PROPS_BYTES: number;
3
- export declare const componentPreviewPropNameSchema: z.ZodString;
4
- export declare const componentPreviewPropsSchema: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
5
- export declare const COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_ID: "replo:component-preview-iframe-rpc";
6
- export declare const COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_VERSION: 2;
7
- export declare const COMPONENT_PREVIEW_PARENT_ORIGIN_PARAM = "reploParentOrigin";
8
- export declare const websiteBuilderToComponentPreviewMethodConfig: {
9
- setProps: {
10
- inputSchema: z.ZodObject<{
11
- props: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
12
- sourceRevision: z.ZodString;
13
- }, z.core.$strip>;
14
- outputSchema: z.ZodObject<{
15
- mode: z.ZodEnum<{
16
- client: "client";
17
- navigation: "navigation";
18
- unchanged: "unchanged";
19
- }>;
20
- }, z.core.$strip>;
21
- timeoutMs: number;
22
- };
23
- };
24
- export declare const componentPreviewToWebsiteBuilderMethodConfig: {
25
- contentBoundsChanged: {
26
- inputSchema: z.ZodObject<{
27
- height: z.ZodNumber;
28
- }, z.core.$strip>;
29
- outputSchema: z.ZodVoid;
30
- };
31
- iframeReady: {
32
- inputSchema: z.ZodUndefined;
33
- outputSchema: z.ZodVoid;
34
- };
35
- };
36
- export declare const componentPreviewProductReferenceSchema: z.ZodObject<{
37
- type: z.ZodLiteral<"product">;
38
- loaderKey: z.ZodEnum<{
39
- "shopify_storefront.product": "shopify_storefront.product";
40
- "replo_products.product": "replo_products.product";
41
- }>;
42
- productId: z.ZodString;
43
- }, z.core.$strict>;
@@ -1,79 +0,0 @@
1
- import * as z2 from 'zod';
2
-
3
- var DATA_LOADER_KEYS = {
4
- SHOPIFY_INTEGRATION_DETAILS: "shopify_storefront.integration_details",
5
- SHOPIFY_PRODUCT: "shopify_storefront.product",
6
- SHOPIFY_COLLECTION: "shopify_storefront.collection",
7
- SHOPIFY_COLLECTION_PRODUCTS: "shopify_storefront.collection_products",
8
- SHOPIFY_METAOBJECT: "shopify_storefront.metaobject",
9
- SHOPIFY_METAOBJECTS: "shopify_storefront.metaobjects",
10
- SHOPIFY_KACHING_BUNDLES: "shopify_storefront.kaching_bundles",
11
- REPLO_PRODUCT: "replo_products.product",
12
- OKENDO_PRODUCT_REVIEWS: "okendo.product_reviews",
13
- OKENDO_PRODUCT_REVIEW_AGGREGATE: "okendo.product_review_aggregate",
14
- REBUY_RECOMMENDATIONS: "rebuy.recommendations",
15
- LEVANTA_PRODUCT: "levanta_products.product",
16
- SMILE_IO_VIP_TIERS: "smile_io.vip_tiers",
17
- SMILE_IO_EARNING_RULES: "smile_io.earning_rules",
18
- SMILE_IO_REWARDS: "smile_io.rewards",
19
- YOTPO_PRODUCT_REVIEWS: "yotpo.product_reviews",
20
- YOTPO_PRODUCT_REVIEW_AGGREGATE: "yotpo.product_review_aggregate",
21
- REVIEWS_IO_PRODUCT_REVIEWS: "reviews_io.product_reviews",
22
- REVIEWS_IO_PRODUCT_REVIEW_AGGREGATE: "reviews_io.product_review_aggregate",
23
- LOOX_PRODUCT_REVIEWS: "loox.product_reviews",
24
- LOOX_PRODUCT_REVIEW_AGGREGATE: "loox.product_review_aggregate",
25
- JUDGEME_PRODUCT_REVIEWS: "judgeme.product_reviews",
26
- JUDGEME_PRODUCT_REVIEW_AGGREGATE: "judgeme.product_review_aggregate",
27
- STATSIG_EXPERIMENT: "statsig.experiment",
28
- CONTENTFUL_ENTRY: "contentful.entry",
29
- CONTENTFUL_ENTRIES: "contentful.entries"
30
- };
31
- z2.enum(Object.values(DATA_LOADER_KEYS));
32
-
33
- var MAX_COMPONENT_PREVIEW_PROPS_BYTES = 16 * 1024;
34
- var componentPreviewPropNameSchema = z2.string().min(1).max(80).regex(/^[A-Za-z_$][\w$]*$/u).refine((name) => {
35
- return !["__proto__", "constructor", "dangerouslySetInnerHTML"].includes(
36
- name
37
- );
38
- }, "Unsafe prop name");
39
- var componentPreviewPropsSchema = z2.record(
40
- componentPreviewPropNameSchema,
41
- z2.json()
42
- );
43
- var COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_ID = "replo:component-preview-iframe-rpc";
44
- var COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_VERSION = 2;
45
- var COMPONENT_PREVIEW_PARENT_ORIGIN_PARAM = "reploParentOrigin";
46
- var websiteBuilderToComponentPreviewMethodConfig = {
47
- setProps: {
48
- inputSchema: z2.object({
49
- props: componentPreviewPropsSchema,
50
- sourceRevision: z2.string().min(1)
51
- }),
52
- outputSchema: z2.object({
53
- mode: z2.enum(["client", "navigation", "unchanged"])
54
- }),
55
- timeoutMs: 1e4
56
- }
57
- };
58
- var componentPreviewToWebsiteBuilderMethodConfig = {
59
- contentBoundsChanged: {
60
- inputSchema: z2.object({
61
- height: z2.number().finite().min(0).max(1e5)
62
- }),
63
- outputSchema: z2.void()
64
- },
65
- iframeReady: {
66
- inputSchema: z2.undefined(),
67
- outputSchema: z2.void()
68
- }
69
- };
70
- var componentPreviewProductReferenceSchema = z2.object({
71
- type: z2.literal("product"),
72
- loaderKey: z2.enum([
73
- DATA_LOADER_KEYS.SHOPIFY_PRODUCT,
74
- DATA_LOADER_KEYS.REPLO_PRODUCT
75
- ]),
76
- productId: z2.string().min(1)
77
- }).strict().describe("ComponentPreviewProductReference");
78
-
79
- export { COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_ID, COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_VERSION, COMPONENT_PREVIEW_PARENT_ORIGIN_PARAM, MAX_COMPONENT_PREVIEW_PROPS_BYTES, componentPreviewProductReferenceSchema, componentPreviewPropNameSchema, componentPreviewPropsSchema, componentPreviewToWebsiteBuilderMethodConfig, websiteBuilderToComponentPreviewMethodConfig };
@@ -1,5 +0,0 @@
1
- export type ComponentPreviewProductReference = {
2
- type: "product";
3
- loaderKey: "shopify_storefront.product" | "replo_products.product";
4
- productId: string;
5
- };
@@ -1,69 +0,0 @@
1
- import * as z from "zod";
2
- /**
3
- * Shared data-loader key constants. Both the integration registry and the
4
- * dependency resolver import from here so the strings are never duplicated.
5
- *
6
- * These keys serve double duty: they identify which backend loader to invoke
7
- * AND are used as React Query cache key prefixes. Loader components
8
- * internally construct queryKey as `[loaderKey, args]`.
9
- *
10
- * Naming convention: `<integration>.<objectType>` or
11
- * `<integration>.<objectType>_<qualifier>`.
12
- */
13
- export declare const DATA_LOADER_KEYS: {
14
- readonly SHOPIFY_INTEGRATION_DETAILS: "shopify_storefront.integration_details";
15
- readonly SHOPIFY_PRODUCT: "shopify_storefront.product";
16
- readonly SHOPIFY_COLLECTION: "shopify_storefront.collection";
17
- readonly SHOPIFY_COLLECTION_PRODUCTS: "shopify_storefront.collection_products";
18
- readonly SHOPIFY_METAOBJECT: "shopify_storefront.metaobject";
19
- readonly SHOPIFY_METAOBJECTS: "shopify_storefront.metaobjects";
20
- readonly SHOPIFY_KACHING_BUNDLES: "shopify_storefront.kaching_bundles";
21
- readonly REPLO_PRODUCT: "replo_products.product";
22
- readonly OKENDO_PRODUCT_REVIEWS: "okendo.product_reviews";
23
- readonly OKENDO_PRODUCT_REVIEW_AGGREGATE: "okendo.product_review_aggregate";
24
- readonly REBUY_RECOMMENDATIONS: "rebuy.recommendations";
25
- readonly LEVANTA_PRODUCT: "levanta_products.product";
26
- readonly SMILE_IO_VIP_TIERS: "smile_io.vip_tiers";
27
- readonly SMILE_IO_EARNING_RULES: "smile_io.earning_rules";
28
- readonly SMILE_IO_REWARDS: "smile_io.rewards";
29
- readonly YOTPO_PRODUCT_REVIEWS: "yotpo.product_reviews";
30
- readonly YOTPO_PRODUCT_REVIEW_AGGREGATE: "yotpo.product_review_aggregate";
31
- readonly REVIEWS_IO_PRODUCT_REVIEWS: "reviews_io.product_reviews";
32
- readonly REVIEWS_IO_PRODUCT_REVIEW_AGGREGATE: "reviews_io.product_review_aggregate";
33
- readonly LOOX_PRODUCT_REVIEWS: "loox.product_reviews";
34
- readonly LOOX_PRODUCT_REVIEW_AGGREGATE: "loox.product_review_aggregate";
35
- readonly JUDGEME_PRODUCT_REVIEWS: "judgeme.product_reviews";
36
- readonly JUDGEME_PRODUCT_REVIEW_AGGREGATE: "judgeme.product_review_aggregate";
37
- readonly STATSIG_EXPERIMENT: "statsig.experiment";
38
- readonly CONTENTFUL_ENTRY: "contentful.entry";
39
- readonly CONTENTFUL_ENTRIES: "contentful.entries";
40
- };
41
- export type DataLoaderKey = (typeof DATA_LOADER_KEYS)[keyof typeof DATA_LOADER_KEYS];
42
- export declare const dataLoaderKeySchema: z.ZodEnum<{
43
- "shopify_storefront.integration_details": "shopify_storefront.integration_details";
44
- "shopify_storefront.product": "shopify_storefront.product";
45
- "shopify_storefront.collection": "shopify_storefront.collection";
46
- "shopify_storefront.collection_products": "shopify_storefront.collection_products";
47
- "shopify_storefront.metaobject": "shopify_storefront.metaobject";
48
- "shopify_storefront.metaobjects": "shopify_storefront.metaobjects";
49
- "shopify_storefront.kaching_bundles": "shopify_storefront.kaching_bundles";
50
- "replo_products.product": "replo_products.product";
51
- "okendo.product_reviews": "okendo.product_reviews";
52
- "okendo.product_review_aggregate": "okendo.product_review_aggregate";
53
- "rebuy.recommendations": "rebuy.recommendations";
54
- "levanta_products.product": "levanta_products.product";
55
- "smile_io.vip_tiers": "smile_io.vip_tiers";
56
- "smile_io.earning_rules": "smile_io.earning_rules";
57
- "smile_io.rewards": "smile_io.rewards";
58
- "yotpo.product_reviews": "yotpo.product_reviews";
59
- "yotpo.product_review_aggregate": "yotpo.product_review_aggregate";
60
- "reviews_io.product_reviews": "reviews_io.product_reviews";
61
- "reviews_io.product_review_aggregate": "reviews_io.product_review_aggregate";
62
- "loox.product_reviews": "loox.product_reviews";
63
- "loox.product_review_aggregate": "loox.product_review_aggregate";
64
- "judgeme.product_reviews": "judgeme.product_reviews";
65
- "judgeme.product_review_aggregate": "judgeme.product_review_aggregate";
66
- "statsig.experiment": "statsig.experiment";
67
- "contentful.entry": "contentful.entry";
68
- "contentful.entries": "contentful.entries";
69
- }>;
@@ -1,8 +0,0 @@
1
- import type { ComponentType } from "react";
2
- export declare function ComponentPreviewNavigation(): null;
3
- export declare function ComponentPreviewStage({ Component, initialProps, initialRawProps, initialSourceRevision, }: {
4
- Component: ComponentType<Record<string, unknown>>;
5
- initialProps: Record<string, unknown>;
6
- initialRawProps: Record<string, unknown>;
7
- initialSourceRevision: string;
8
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,227 +0,0 @@
1
- "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { useEffect, useMemo, useRef, useState, useTransition } from "react";
4
- import { useRouter } from "next/navigation";
5
- import { useIframeRpcChannel } from "../_vendor/replo-utils/react/use-iframe-rpc-channel.mjs";
6
- import {
7
- COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_ID,
8
- COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_VERSION,
9
- COMPONENT_PREVIEW_PARENT_ORIGIN_PARAM,
10
- componentPreviewToWebsiteBuilderMethodConfig,
11
- websiteBuilderToComponentPreviewMethodConfig
12
- } from "../_vendor/schemas/componentPreview.mjs";
13
- import {
14
- createIframeRpcChannel,
15
- createIframeRpcRemote
16
- } from "../_vendor/schemas/iframeRpcChannel.mjs";
17
- import { PREVIEW_RENDERED_EVENT } from "../select-mode/previewRendered";
18
- import { getComponentPreviewHref } from "./component-preview-href";
19
- import {
20
- mergeClientProps,
21
- productReferencesChanged
22
- } from "./component-preview-props";
23
- function getParentOrigin() {
24
- const fromQuery = new URLSearchParams(window.location.search).get(
25
- COMPONENT_PREVIEW_PARENT_ORIGIN_PARAM
26
- );
27
- if (fromQuery) {
28
- try {
29
- return new URL(fromQuery).origin;
30
- } catch {
31
- return null;
32
- }
33
- }
34
- return document.referrer ? new URL(document.referrer).origin : null;
35
- }
36
- function getCurrentHref() {
37
- return `${window.location.pathname}${window.location.search}${window.location.hash}`;
38
- }
39
- function useComponentPreviewChannel(onSetProps) {
40
- const onSetPropsRef = useRef(onSetProps);
41
- onSetPropsRef.current = onSetProps;
42
- const pendingUpdates = useRef(Promise.resolve());
43
- useIframeRpcChannel(
44
- useMemo(() => {
45
- if (typeof window === "undefined") {
46
- return null;
47
- }
48
- const parentOrigin = getParentOrigin();
49
- if (!parentOrigin) {
50
- return null;
51
- }
52
- const rpcChannel = createIframeRpcChannel({
53
- subscriberWindow: window,
54
- channelIdentifier: COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_ID,
55
- version: COMPONENT_PREVIEW_IFRAME_RPC_CHANNEL_VERSION,
56
- getTargetWindow: () => {
57
- return window.parent === window ? null : window.parent;
58
- },
59
- targetOrigin: parentOrigin,
60
- isExpectedMessage: (event) => {
61
- return event.source === window.parent && event.origin === parentOrigin;
62
- },
63
- outgoingMethods: componentPreviewToWebsiteBuilderMethodConfig,
64
- incomingMethods: websiteBuilderToComponentPreviewMethodConfig,
65
- handlers: {
66
- setProps: (input) => {
67
- const result = pendingUpdates.current.then(async () => {
68
- const result2 = await onSetPropsRef.current(input);
69
- window.dispatchEvent(new Event(PREVIEW_RENDERED_EVENT));
70
- return result2;
71
- });
72
- pendingUpdates.current = result.then(
73
- () => {
74
- },
75
- () => {
76
- }
77
- );
78
- return result;
79
- }
80
- }
81
- });
82
- return {
83
- ...rpcChannel,
84
- subscribe() {
85
- const unsubscribe = rpcChannel.subscribe();
86
- const remote = createIframeRpcRemote(rpcChannel);
87
- remote.iframeReady();
88
- const content = document.querySelector(
89
- "[data-replo-component-preview]"
90
- );
91
- let timeout;
92
- let lastHeight = -1;
93
- const measure = () => {
94
- clearTimeout(timeout);
95
- timeout = setTimeout(() => {
96
- if (!content) {
97
- return;
98
- }
99
- const bounds = content.getBoundingClientRect();
100
- const height = Math.min(
101
- 1e5,
102
- Math.ceil(
103
- bounds.height + Math.max(0, bounds.top + window.scrollY)
104
- )
105
- );
106
- if (height !== lastHeight) {
107
- lastHeight = height;
108
- remote.contentBoundsChanged({ height });
109
- }
110
- }, 100);
111
- };
112
- const observer = new ResizeObserver(measure);
113
- if (content) {
114
- observer.observe(content);
115
- }
116
- measure();
117
- return () => {
118
- clearTimeout(timeout);
119
- observer.disconnect();
120
- unsubscribe();
121
- };
122
- }
123
- };
124
- }, [])
125
- );
126
- }
127
- function useCommitPreviewUpdate() {
128
- const [isUpdatePending, startUpdate] = useTransition();
129
- const settleResolvers = useRef([]);
130
- useEffect(() => {
131
- if (!isUpdatePending) {
132
- const resolvers = settleResolvers.current;
133
- settleResolvers.current = [];
134
- for (const resolve of resolvers) {
135
- resolve();
136
- }
137
- }
138
- }, [isUpdatePending]);
139
- return (update) => {
140
- return new Promise((resolve) => {
141
- settleResolvers.current.push(resolve);
142
- startUpdate(update);
143
- });
144
- };
145
- }
146
- function ComponentPreviewNavigation() {
147
- const router = useRouter();
148
- const commitPreviewUpdate = useCommitPreviewUpdate();
149
- useComponentPreviewChannel(
150
- async ({ props, sourceRevision }) => {
151
- const nextHref = getComponentPreviewHref({
152
- currentUrl: window.location.href,
153
- props,
154
- sourceRevision
155
- });
156
- if (nextHref === getCurrentHref()) {
157
- return { mode: "unchanged" };
158
- }
159
- await commitPreviewUpdate(() => {
160
- return router.replace(nextHref, { scroll: false });
161
- });
162
- return { mode: "navigation" };
163
- }
164
- );
165
- return null;
166
- }
167
- function ComponentPreviewStage({
168
- Component,
169
- initialProps,
170
- initialRawProps,
171
- initialSourceRevision
172
- }) {
173
- const [props, setProps] = useState(initialProps);
174
- const [lastInitialProps, setLastInitialProps] = useState(initialProps);
175
- if (initialProps !== lastInitialProps) {
176
- setLastInitialProps(initialProps);
177
- setProps(initialProps);
178
- }
179
- const propsRef = useRef(props);
180
- propsRef.current = props;
181
- const lastRawPropsRef = useRef(initialRawProps);
182
- const lastSourceRevisionRef = useRef(initialSourceRevision);
183
- const router = useRouter();
184
- const commitPreviewUpdate = useCommitPreviewUpdate();
185
- useComponentPreviewChannel(
186
- async ({
187
- props: nextRawProps,
188
- sourceRevision
189
- }) => {
190
- const nextHref = getComponentPreviewHref({
191
- currentUrl: window.location.href,
192
- props: nextRawProps,
193
- sourceRevision
194
- });
195
- if (nextHref === getCurrentHref()) {
196
- return { mode: "unchanged" };
197
- }
198
- if (sourceRevision !== lastSourceRevisionRef.current || productReferencesChanged({
199
- previous: lastRawPropsRef.current,
200
- next: nextRawProps
201
- })) {
202
- await commitPreviewUpdate(() => {
203
- return router.replace(nextHref, { scroll: false });
204
- });
205
- lastRawPropsRef.current = nextRawProps;
206
- lastSourceRevisionRef.current = sourceRevision;
207
- return { mode: "navigation" };
208
- }
209
- await commitPreviewUpdate(() => {
210
- return setProps(
211
- mergeClientProps({
212
- currentResolved: propsRef.current,
213
- nextRaw: nextRawProps
214
- })
215
- );
216
- });
217
- lastRawPropsRef.current = nextRawProps;
218
- window.history.replaceState(null, "", nextHref);
219
- return { mode: "client" };
220
- }
221
- );
222
- return /* @__PURE__ */ jsx("div", { "data-replo-component-preview": true, style: { display: "flow-root" }, children: /* @__PURE__ */ jsx(Component, { ...props }) });
223
- }
224
- export {
225
- ComponentPreviewNavigation,
226
- ComponentPreviewStage
227
- };
@@ -1,5 +0,0 @@
1
- export declare function getComponentPreviewHref({ currentUrl, props, sourceRevision, }: {
2
- currentUrl: string;
3
- props: Record<string, unknown>;
4
- sourceRevision: string;
5
- }): string;
@@ -1,13 +0,0 @@
1
- function getComponentPreviewHref({
2
- currentUrl,
3
- props,
4
- sourceRevision
5
- }) {
6
- const url = new URL(currentUrl);
7
- url.searchParams.set("props", JSON.stringify(props));
8
- url.searchParams.set("sourceRevision", sourceRevision);
9
- return `${url.pathname}${url.search}${url.hash}`;
10
- }
11
- export {
12
- getComponentPreviewHref
13
- };
@@ -1,8 +0,0 @@
1
- export declare function productReferencesChanged({ previous, next, }: {
2
- previous: Record<string, unknown>;
3
- next: Record<string, unknown>;
4
- }): boolean;
5
- export declare function mergeClientProps({ currentResolved, nextRaw, }: {
6
- currentResolved: Record<string, unknown>;
7
- nextRaw: Record<string, unknown>;
8
- }): Record<string, unknown>;
@@ -1,35 +0,0 @@
1
- import { componentPreviewProductReferenceSchema } from "../_vendor/schemas/componentPreview.mjs";
2
- function isProductReference(value) {
3
- return componentPreviewProductReferenceSchema.safeParse(value).success;
4
- }
5
- function productReferencesChanged({
6
- previous,
7
- next
8
- }) {
9
- const names = /* @__PURE__ */ new Set([...Object.keys(previous), ...Object.keys(next)]);
10
- for (const name of names) {
11
- const previousIsReference = isProductReference(previous[name]);
12
- const nextIsReference = isProductReference(next[name]);
13
- if (!previousIsReference && !nextIsReference) {
14
- continue;
15
- }
16
- if (previousIsReference !== nextIsReference || JSON.stringify(previous[name]) !== JSON.stringify(next[name])) {
17
- return true;
18
- }
19
- }
20
- return false;
21
- }
22
- function mergeClientProps({
23
- currentResolved,
24
- nextRaw
25
- }) {
26
- return Object.fromEntries(
27
- Object.entries(nextRaw).map(([name, value]) => {
28
- return isProductReference(value) ? [name, currentResolved[name]] : [name, value];
29
- })
30
- );
31
- }
32
- export {
33
- mergeClientProps,
34
- productReferencesChanged
35
- };
@@ -1,11 +0,0 @@
1
- import type { ComponentType } from "react";
2
- import type { ComponentPreviewProductReference } from "../_vendor/schemas/generated/componentPreview";
3
- export declare function createComponentPreviewPage(Component: ComponentType<Record<string, unknown>>, options?: {
4
- getProduct?: (reference: ComponentPreviewProductReference) => Promise<unknown>;
5
- interactive?: boolean;
6
- }): ({ searchParams, }: {
7
- searchParams: Promise<{
8
- props?: string | string[];
9
- sourceRevision?: string | string[];
10
- }>;
11
- }) => Promise<import("react/jsx-runtime").JSX.Element>;