@replohq/sandbox-runtime 0.1.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/ClientErrorBoundary.d.ts +10 -0
- package/ClientErrorBoundary.js +61 -0
- package/ClientErrorBoundary.js.map +7 -0
- package/DocumentReadyBeacon.d.ts +1 -0
- package/DocumentReadyBeacon.js +9 -0
- package/DocumentReadyBeacon.js.map +7 -0
- package/LICENSE +11 -0
- package/LinkInterceptor.d.ts +1 -0
- package/LinkInterceptor.js +128 -0
- package/LinkInterceptor.js.map +7 -0
- package/NextErrorReporter.d.ts +1 -0
- package/NextErrorReporter.js +92 -0
- package/NextErrorReporter.js.map +7 -0
- package/_vendor/replo-utils/lib/crypto.d.ts +30 -0
- package/_vendor/replo-utils/lib/errors.d.ts +83 -0
- package/_vendor/replo-utils/lib/fonts.d.ts +49 -0
- package/_vendor/replo-utils/lib/fonts.mjs +221 -0
- package/_vendor/replo-utils/lib/geometry.d.ts +18 -0
- package/_vendor/replo-utils/lib/geometry.mjs +9 -0
- package/_vendor/replo-utils/lib/json.d.ts +6 -0
- package/_vendor/replo-utils/lib/log.d.ts +11 -0
- package/_vendor/replo-utils/lib/misc.d.ts +145 -0
- package/_vendor/replo-utils/lib/misc.mjs +2 -0
- package/_vendor/replo-utils/lib/object.d.ts +31 -0
- package/_vendor/replo-utils/lib/parse.d.ts +15 -0
- package/_vendor/replo-utils/lib/posthogReplay.d.ts +43 -0
- package/_vendor/replo-utils/lib/posthogReplay.mjs +121 -0
- package/_vendor/replo-utils/react/use-iframe-rpc-channel.d.ts +14 -0
- package/_vendor/replo-utils/react/use-iframe-rpc-channel.mjs +14 -0
- package/_vendor/schemas/designLibrary.d.ts +361 -0
- package/_vendor/schemas/designLibrary.mjs +126 -0
- package/_vendor/schemas/errors.d.ts +459 -0
- package/_vendor/schemas/generated/errors.d.ts +61 -0
- package/_vendor/schemas/generated/pageAnnotations.d.ts +48 -0
- package/_vendor/schemas/generated/pageAnnotations.mjs +1 -0
- package/_vendor/schemas/generated/selectMode.d.ts +119 -0
- package/_vendor/schemas/generated/selectMode.mjs +1 -0
- package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +100 -0
- package/_vendor/schemas/generated/selectModeIframeRpc.mjs +1 -0
- package/_vendor/schemas/iframeRpcChannel.d.ts +82 -0
- package/_vendor/schemas/iframeRpcChannel.mjs +520 -0
- package/_vendor/schemas/pageAnnotations.d.ts +134 -0
- package/_vendor/schemas/pageAnnotations.mjs +61 -0
- package/_vendor/schemas/savedStyles.d.ts +140 -0
- package/_vendor/schemas/selectMode.d.ts +522 -0
- package/_vendor/schemas/selectMode.mjs +3 -0
- package/_vendor/schemas/selectModeIframeRpc.d.ts +900 -0
- package/_vendor/schemas/selectModeIframeRpc.mjs +223 -0
- package/annotations/AnnotationLayerMount.d.ts +1 -0
- package/annotations/AnnotationLayerMount.js +13 -0
- package/annotations/AnnotationLayerMount.js.map +7 -0
- package/annotations/annotationController.d.ts +1 -0
- package/annotations/annotationController.js +384 -0
- package/annotations/annotationController.js.map +7 -0
- package/annotations/bridgeGate.d.ts +7 -0
- package/annotations/bridgeGate.js +22 -0
- package/annotations/bridgeGate.js.map +7 -0
- package/chunk-3UFG7XTQ.mjs +205 -0
- package/chunk-FNTGY7I5.mjs +68 -0
- package/chunk-N5EI2MOZ.mjs +1535 -0
- package/design-library-preview/DesignLibraryPreview.d.ts +1 -0
- package/design-library-preview/DesignLibraryPreview.js +93 -0
- package/design-library-preview/DesignLibraryPreview.js.map +7 -0
- package/package.json +41 -0
- package/posthog-relay.d.ts +11 -0
- package/posthog-relay.js +72 -0
- package/posthog-relay.js.map +7 -0
- package/sandbox-runtime.d.ts +1 -0
- package/sandbox-runtime.js +29 -0
- package/sandbox-runtime.js.map +7 -0
- package/select-mode/EditorSelection.d.ts +24 -0
- package/select-mode/EditorSelection.js +95 -0
- package/select-mode/EditorSelection.js.map +7 -0
- package/select-mode/annotationFrames.d.ts +33 -0
- package/select-mode/annotationFrames.js +119 -0
- package/select-mode/annotationFrames.js.map +7 -0
- package/select-mode/descriptor/elementDescriptor.d.ts +26 -0
- package/select-mode/descriptor/elementDescriptor.js +201 -0
- package/select-mode/descriptor/elementDescriptor.js.map +7 -0
- package/select-mode/descriptor/styleExtraction.d.ts +3 -0
- package/select-mode/descriptor/styleExtraction.js +271 -0
- package/select-mode/descriptor/styleExtraction.js.map +7 -0
- package/select-mode/displayModeStore.d.ts +10 -0
- package/select-mode/displayModeStore.js +47 -0
- package/select-mode/displayModeStore.js.map +7 -0
- package/select-mode/fast-refresh-relay.d.ts +3 -0
- package/select-mode/fast-refresh-relay.js +33 -0
- package/select-mode/fast-refresh-relay.js.map +7 -0
- package/select-mode/fiber.d.ts +49 -0
- package/select-mode/fiber.js +306 -0
- package/select-mode/fiber.js.map +7 -0
- package/select-mode/hooks/useCrosshairCursor.d.ts +12 -0
- package/select-mode/hooks/useCrosshairCursor.js +20 -0
- package/select-mode/hooks/useCrosshairCursor.js.map +7 -0
- package/select-mode/hooks/useEditModeStateMachine.d.ts +16 -0
- package/select-mode/hooks/useEditModeStateMachine.js +235 -0
- package/select-mode/hooks/useEditModeStateMachine.js.map +7 -0
- package/select-mode/hooks/useOptimisticOverrides.d.ts +17 -0
- package/select-mode/hooks/useOptimisticOverrides.js +283 -0
- package/select-mode/hooks/useOptimisticOverrides.js.map +7 -0
- package/select-mode/hooks/useParentMessaging.d.ts +36 -0
- package/select-mode/hooks/useParentMessaging.js +74 -0
- package/select-mode/hooks/useParentMessaging.js.map +7 -0
- package/select-mode/hooks/useSelectModeController.d.ts +8 -0
- package/select-mode/hooks/useSelectModeController.js +46 -0
- package/select-mode/hooks/useSelectModeController.js.map +7 -0
- package/select-mode/hooks/useSelectionHover.d.ts +22 -0
- package/select-mode/hooks/useSelectionHover.js +110 -0
- package/select-mode/hooks/useSelectionHover.js.map +7 -0
- package/select-mode/hooks/useSelectionInteractions.d.ts +37 -0
- package/select-mode/hooks/useSelectionInteractions.js +353 -0
- package/select-mode/hooks/useSelectionInteractions.js.map +7 -0
- package/select-mode/hooks/useSelectionScrollSync.d.ts +28 -0
- package/select-mode/hooks/useSelectionScrollSync.js +70 -0
- package/select-mode/hooks/useSelectionScrollSync.js.map +7 -0
- package/select-mode/hooks/useSiblingResolution.d.ts +6 -0
- package/select-mode/hooks/useSiblingResolution.js +59 -0
- package/select-mode/hooks/useSiblingResolution.js.map +7 -0
- package/select-mode/iframeRpcChannel.d.ts +356 -0
- package/select-mode/iframeRpcChannel.js +92 -0
- package/select-mode/iframeRpcChannel.js.map +7 -0
- package/select-mode/inlineTextMarks.d.ts +6 -0
- package/select-mode/inlineTextMarks.js +25 -0
- package/select-mode/inlineTextMarks.js.map +7 -0
- package/select-mode/interactions/selectionGeometry.d.ts +105 -0
- package/select-mode/interactions/selectionGeometry.js +192 -0
- package/select-mode/interactions/selectionGeometry.js.map +7 -0
- package/select-mode/selectModeSession.d.ts +21 -0
- package/select-mode/selectModeSession.js +7 -0
- package/select-mode/selectModeSession.js.map +7 -0
- package/select-mode/selectionFrame.d.ts +81 -0
- package/select-mode/selectionFrame.js +132 -0
- package/select-mode/selectionFrame.js.map +7 -0
- package/select-mode/symbolicate.d.ts +2 -0
- package/select-mode/symbolicate.js +200 -0
- package/select-mode/symbolicate.js.map +7 -0
- package/select-mode/tiptapInlineEditor.d.ts +23 -0
- package/select-mode/tiptapInlineEditor.js +120 -0
- package/select-mode/tiptapInlineEditor.js.map +7 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { DisplayMode, SelectModeSelectionType, SelectModeOptimisticUpdatePayload, SelectModeFormatCommand, SelectableData, SelectModeBoundingRect, SelectModeClickPosition, SelectModeSelectionRect, SelectModeTiptapActiveMarks } from "./selectMode.ts";
|
|
2
|
+
export type SelectModeParentMessage = {
|
|
3
|
+
method: "setDisplayMode";
|
|
4
|
+
data: {
|
|
5
|
+
displayMode: DisplayMode;
|
|
6
|
+
};
|
|
7
|
+
} | {
|
|
8
|
+
method: "setSelectionType";
|
|
9
|
+
data: {
|
|
10
|
+
selectionType: SelectModeSelectionType;
|
|
11
|
+
};
|
|
12
|
+
} | {
|
|
13
|
+
method: "applyOptimisticUpdate";
|
|
14
|
+
data: {
|
|
15
|
+
editId: string;
|
|
16
|
+
payload: SelectModeOptimisticUpdatePayload;
|
|
17
|
+
targetSelector: string;
|
|
18
|
+
targetMode: "primary" | "group";
|
|
19
|
+
};
|
|
20
|
+
} | {
|
|
21
|
+
method: "markCommitted";
|
|
22
|
+
data: {
|
|
23
|
+
editId: string;
|
|
24
|
+
sessionId: string;
|
|
25
|
+
};
|
|
26
|
+
} | {
|
|
27
|
+
method: "resolveSessionOverrides";
|
|
28
|
+
data: {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
outcome: "persisted" | "failed";
|
|
31
|
+
};
|
|
32
|
+
} | {
|
|
33
|
+
method: "revertOverride";
|
|
34
|
+
data: {
|
|
35
|
+
editId: string;
|
|
36
|
+
};
|
|
37
|
+
} | {
|
|
38
|
+
method: "enterEditMode";
|
|
39
|
+
} | {
|
|
40
|
+
method: "exitEditMode";
|
|
41
|
+
} | {
|
|
42
|
+
method: "formatCommand";
|
|
43
|
+
data: {
|
|
44
|
+
command: SelectModeFormatCommand;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export type SelectModeIframeMessage = {
|
|
48
|
+
method: "iframeReady";
|
|
49
|
+
} | {
|
|
50
|
+
method: "elementSelected";
|
|
51
|
+
data: {
|
|
52
|
+
data: SelectableData;
|
|
53
|
+
};
|
|
54
|
+
} | {
|
|
55
|
+
method: "hoverElement";
|
|
56
|
+
data: {
|
|
57
|
+
rect: SelectModeBoundingRect | null;
|
|
58
|
+
};
|
|
59
|
+
} | {
|
|
60
|
+
method: "selectedElementRectUpdate";
|
|
61
|
+
data: {
|
|
62
|
+
rect: SelectModeBoundingRect;
|
|
63
|
+
clickPosition: SelectModeClickPosition;
|
|
64
|
+
};
|
|
65
|
+
} | {
|
|
66
|
+
method: "selectedAreaRectUpdate";
|
|
67
|
+
data: {
|
|
68
|
+
rect: SelectModeBoundingRect;
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
method: "dragRectUpdated";
|
|
72
|
+
data: {
|
|
73
|
+
dragRect: SelectModeBoundingRect | null;
|
|
74
|
+
selectionRects: SelectModeSelectionRect[];
|
|
75
|
+
};
|
|
76
|
+
} | {
|
|
77
|
+
method: "areaSelected";
|
|
78
|
+
data: {
|
|
79
|
+
rect: SelectModeBoundingRect;
|
|
80
|
+
items: SelectableData[];
|
|
81
|
+
};
|
|
82
|
+
} | {
|
|
83
|
+
method: "textCommitted";
|
|
84
|
+
data: {
|
|
85
|
+
editId: string;
|
|
86
|
+
html: string;
|
|
87
|
+
json: {
|
|
88
|
+
[x: string]: unknown;
|
|
89
|
+
};
|
|
90
|
+
originalInnerHTML: string;
|
|
91
|
+
};
|
|
92
|
+
} | {
|
|
93
|
+
method: "editorStateUpdate";
|
|
94
|
+
data: {
|
|
95
|
+
activeMarks: SelectModeTiptapActiveMarks;
|
|
96
|
+
isEditing: boolean;
|
|
97
|
+
};
|
|
98
|
+
} | {
|
|
99
|
+
method: "fastRefreshComplete";
|
|
100
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export type IframeRpcChannelMethodConfig = Record<string, {
|
|
3
|
+
inputSchema: z.ZodType;
|
|
4
|
+
outputSchema: z.ZodType;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
}>;
|
|
7
|
+
type MethodInput<Config extends IframeRpcChannelMethodConfig, Method extends keyof Config> = z.input<Config[Method]["inputSchema"]>;
|
|
8
|
+
type MethodOutput<Config extends IframeRpcChannelMethodConfig, Method extends keyof Config> = z.output<Config[Method]["outputSchema"]>;
|
|
9
|
+
type IsVoidMethod<Config extends IframeRpcChannelMethodConfig, Method extends keyof Config> = MethodOutput<Config, Method> extends void ? true : false;
|
|
10
|
+
type CallResult<Config extends IframeRpcChannelMethodConfig, Method extends keyof Config> = IsVoidMethod<Config, Method> extends true ? void : Promise<MethodOutput<Config, Method>>;
|
|
11
|
+
type MethodArgs<Config extends IframeRpcChannelMethodConfig, Method extends keyof Config> = undefined extends MethodInput<Config, Method> ? [input?: MethodInput<Config, Method>] : [input: MethodInput<Config, Method>];
|
|
12
|
+
export type IframeRpcChannelRemote<Config extends IframeRpcChannelMethodConfig> = {
|
|
13
|
+
[Method in keyof Config]: (...args: MethodArgs<Config, Method>) => CallResult<Config, Method>;
|
|
14
|
+
};
|
|
15
|
+
export type IframeRpcChannelHandlerMeta<OutgoingMethods extends IframeRpcChannelMethodConfig> = {
|
|
16
|
+
channel: IframeRpcChannelRemote<OutgoingMethods>;
|
|
17
|
+
};
|
|
18
|
+
export type IframeRpcChannelHandlers<IncomingMethods extends IframeRpcChannelMethodConfig, OutgoingMethods extends IframeRpcChannelMethodConfig = IframeRpcChannelMethodConfig> = {
|
|
19
|
+
[Method in keyof IncomingMethods]: (input: z.output<IncomingMethods[Method]["inputSchema"]>, meta: IframeRpcChannelHandlerMeta<OutgoingMethods>) => IsVoidMethod<IncomingMethods, Method> extends true ? void : // Valued handlers stay `unknown` so callers can return domain/generated
|
|
20
|
+
unknown | Promise<unknown>;
|
|
21
|
+
};
|
|
22
|
+
export type IframeRpcChannelInputHandlers<IncomingMethods extends IframeRpcChannelMethodConfig> = {
|
|
23
|
+
[Method in keyof IncomingMethods]: (input: z.output<IncomingMethods[Method]["inputSchema"]>) => IsVoidMethod<IncomingMethods, Method> extends true ? void : unknown | Promise<unknown>;
|
|
24
|
+
};
|
|
25
|
+
export declare const iframeRpcCallSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
26
|
+
type: z.ZodLiteral<"notify">;
|
|
27
|
+
method: z.ZodString;
|
|
28
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
29
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
30
|
+
type: z.ZodLiteral<"request">;
|
|
31
|
+
id: z.ZodUUID;
|
|
32
|
+
method: z.ZodString;
|
|
33
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
34
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
35
|
+
type: z.ZodLiteral<"response">;
|
|
36
|
+
id: z.ZodUUID;
|
|
37
|
+
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
38
|
+
type: z.ZodLiteral<"success">;
|
|
39
|
+
data: z.ZodUnknown;
|
|
40
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
41
|
+
type: z.ZodLiteral<"error">;
|
|
42
|
+
errorMessage: z.ZodString;
|
|
43
|
+
}, z.core.$strip>], "type">;
|
|
44
|
+
}, z.core.$strip>], "type">;
|
|
45
|
+
export type IframeRpcCall = z.infer<typeof iframeRpcCallSchema>;
|
|
46
|
+
type SubscriberWindow = {
|
|
47
|
+
addEventListener: (type: "message", listener: (event: MessageEvent) => void) => void;
|
|
48
|
+
removeEventListener: (type: "message", listener: (event: MessageEvent) => void) => void;
|
|
49
|
+
};
|
|
50
|
+
type TargetIframeWindow = {
|
|
51
|
+
postMessage: (message: unknown, targetOrigin: string) => void;
|
|
52
|
+
};
|
|
53
|
+
type IframeRpcChannelOptions<OutgoingMethods extends IframeRpcChannelMethodConfig, IncomingMethods extends IframeRpcChannelMethodConfig> = {
|
|
54
|
+
subscriberWindow: SubscriberWindow;
|
|
55
|
+
channelIdentifier: string;
|
|
56
|
+
version: number;
|
|
57
|
+
getTargetWindow: () => TargetIframeWindow | null;
|
|
58
|
+
targetOrigin: string;
|
|
59
|
+
isExpectedMessage: (event: MessageEvent) => boolean;
|
|
60
|
+
outgoingMethods: OutgoingMethods;
|
|
61
|
+
incomingMethods: IncomingMethods;
|
|
62
|
+
handlers: IframeRpcChannelHandlers<IncomingMethods, OutgoingMethods>;
|
|
63
|
+
};
|
|
64
|
+
export type IframeRpcChannel<OutgoingMethods extends IframeRpcChannelMethodConfig = IframeRpcChannelMethodConfig> = {
|
|
65
|
+
subscribe: () => () => void;
|
|
66
|
+
call: <Method extends keyof OutgoingMethods & string>(input: {
|
|
67
|
+
method: Method;
|
|
68
|
+
input: MethodInput<OutgoingMethods, Method>;
|
|
69
|
+
}) => CallResult<OutgoingMethods, Method>;
|
|
70
|
+
outgoingMethods: OutgoingMethods;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Flat method-per-key facade over `channel.call`. Prefer this at call sites
|
|
74
|
+
* over hand-writing `useMemo(() => ({ foo: (input) => channel.call(...) }))`.
|
|
75
|
+
*
|
|
76
|
+
* Pass a channel directly, or a getter (plus its method config) when the
|
|
77
|
+
* channel is created lazily / may be unavailable (e.g. SSR).
|
|
78
|
+
*/
|
|
79
|
+
export declare function createIframeRpcRemote<OutgoingMethods extends IframeRpcChannelMethodConfig>(channel: IframeRpcChannel<OutgoingMethods>): IframeRpcChannelRemote<OutgoingMethods>;
|
|
80
|
+
export declare function createIframeRpcRemote<OutgoingMethods extends IframeRpcChannelMethodConfig>(getChannel: () => IframeRpcChannel<OutgoingMethods> | null, methods: OutgoingMethods): IframeRpcChannelRemote<OutgoingMethods>;
|
|
81
|
+
export declare function createIframeRpcChannel<OutgoingMethods extends IframeRpcChannelMethodConfig, IncomingMethods extends IframeRpcChannelMethodConfig>(options: IframeRpcChannelOptions<OutgoingMethods, IncomingMethods>): IframeRpcChannel<OutgoingMethods>;
|
|
82
|
+
export {};
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { isNullish } from '../../chunk-N5EI2MOZ.mjs';
|
|
2
|
+
import '../../chunk-FNTGY7I5.mjs';
|
|
3
|
+
import { v4 } from 'uuid';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
function randomUUID() {
|
|
7
|
+
return v4();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// ../replo-utils/lib/log.ts
|
|
11
|
+
var defaultLogger = {
|
|
12
|
+
info: console.log,
|
|
13
|
+
debug: console.debug,
|
|
14
|
+
error: console.error
|
|
15
|
+
};
|
|
16
|
+
var ReploError = class _ReploError extends Error {
|
|
17
|
+
config;
|
|
18
|
+
id;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
super(config.message);
|
|
21
|
+
this.message = config.message ?? this.constructor.name;
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.id = randomUUID();
|
|
24
|
+
const cause = config.cause;
|
|
25
|
+
if (cause) {
|
|
26
|
+
this.cause = cause;
|
|
27
|
+
if (cause instanceof _ReploError) {
|
|
28
|
+
this.config.additionalData = {
|
|
29
|
+
...this.config.additionalData,
|
|
30
|
+
...cause.config.additionalData
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var errorUserFacingDetailsMessageSchema = z.object({
|
|
37
|
+
type: z.enum([
|
|
38
|
+
"toast",
|
|
39
|
+
"fullPageModal",
|
|
40
|
+
"shopifyStorePassword",
|
|
41
|
+
"billing.addPublishedElements",
|
|
42
|
+
"billing.addShopifyThemeProject",
|
|
43
|
+
"billing.addReploSite",
|
|
44
|
+
// Agent Billing ONLY
|
|
45
|
+
"agentBilling.shopifyThemeBuilder.publishedElements.exceeded",
|
|
46
|
+
"agentBilling.shopifyThemeBuilder.projects.exceeded",
|
|
47
|
+
"agentBilling.sites.exceeded",
|
|
48
|
+
"agentBilling.credits.exceeded",
|
|
49
|
+
"agentBilling.upgradeRequired"
|
|
50
|
+
]),
|
|
51
|
+
message: z.string(),
|
|
52
|
+
isRecoverable: z.boolean().optional(),
|
|
53
|
+
// NOTE (Matt 2024-03-22): We support detail being an array of strings
|
|
54
|
+
// in FullPageModal only.
|
|
55
|
+
detail: z.array(z.string()).or(z.string()).optional(),
|
|
56
|
+
key: z.string(),
|
|
57
|
+
usage: z.object({
|
|
58
|
+
current: z.number(),
|
|
59
|
+
maximum: z.number()
|
|
60
|
+
}).optional(),
|
|
61
|
+
plan: z.string().optional(),
|
|
62
|
+
callToAction: z.discriminatedUnion("type", [
|
|
63
|
+
z.object({ type: z.literal("reload") }),
|
|
64
|
+
z.object({ type: z.literal("installApp") }),
|
|
65
|
+
z.object({ type: z.literal("goToHomepage") }),
|
|
66
|
+
z.object({ type: z.literal("navigateToProjectEditor") }),
|
|
67
|
+
z.object({ type: z.literal("closeModal") }),
|
|
68
|
+
z.object({
|
|
69
|
+
type: z.literal("navigateToLink"),
|
|
70
|
+
link: z.discriminatedUnion("type", [
|
|
71
|
+
z.object({ type: z.literal("errors.wrongJsonExtension") }),
|
|
72
|
+
z.object({ type: z.literal("errors.chunkingError") }),
|
|
73
|
+
z.object({ type: z.literal("errors.indexBackupError") }),
|
|
74
|
+
z.object({
|
|
75
|
+
type: z.literal("errors.shopifyIntegrationAlreadyAssigned")
|
|
76
|
+
}),
|
|
77
|
+
z.object({
|
|
78
|
+
type: z.literal("errors.shopifyIntegrationMissingAccessScopes"),
|
|
79
|
+
url: z.string()
|
|
80
|
+
}),
|
|
81
|
+
z.object({
|
|
82
|
+
type: z.literal("customLink"),
|
|
83
|
+
url: z.string()
|
|
84
|
+
}),
|
|
85
|
+
z.object({
|
|
86
|
+
type: z.literal(
|
|
87
|
+
"errors.projectConnectedToBillingIntegrationForShopifyWorkspace"
|
|
88
|
+
)
|
|
89
|
+
}),
|
|
90
|
+
z.object({ type: z.literal("errors.themeAssetSizeLimitExceeded") }),
|
|
91
|
+
z.object({ type: z.literal("errors.themeTotalSizeLimitExceeded") }),
|
|
92
|
+
z.object({
|
|
93
|
+
type: z.literal("errors.pageMetafieldDefinitionsChanged")
|
|
94
|
+
}),
|
|
95
|
+
z.object({ type: z.literal("settings.billing") })
|
|
96
|
+
])
|
|
97
|
+
})
|
|
98
|
+
]).optional()
|
|
99
|
+
}).describe("ErrorUserFacingDetailsWithMessage");
|
|
100
|
+
z.discriminatedUnion("type", [
|
|
101
|
+
/**
|
|
102
|
+
* Normal errors, show error UI depending on the type
|
|
103
|
+
*/
|
|
104
|
+
errorUserFacingDetailsMessageSchema,
|
|
105
|
+
/**
|
|
106
|
+
* Errors which should be ignored by the frontend. This is uncommon, usually
|
|
107
|
+
* you want to show an error in the UI, and if you don't want to then you catch
|
|
108
|
+
* the error in your route.
|
|
109
|
+
*/
|
|
110
|
+
z.object({
|
|
111
|
+
type: z.literal("uncommon_none"),
|
|
112
|
+
key: z.string(),
|
|
113
|
+
usage: z.object({
|
|
114
|
+
current: z.number(),
|
|
115
|
+
maximum: z.number()
|
|
116
|
+
}).optional(),
|
|
117
|
+
message: z.string().optional(),
|
|
118
|
+
isRecoverable: z.boolean().optional(),
|
|
119
|
+
detail: z.array(z.string()).or(z.string()).optional()
|
|
120
|
+
})
|
|
121
|
+
]).describe("ErrorUserFacingDetails");
|
|
122
|
+
var IframeRpcChannelError = class extends ReploError {
|
|
123
|
+
};
|
|
124
|
+
var IframeRpcChannelTimeoutError = class extends IframeRpcChannelError {
|
|
125
|
+
constructor({ method, timeoutMs }) {
|
|
126
|
+
super({
|
|
127
|
+
message: `RPC method '${method}' timed out after ${timeoutMs}ms`,
|
|
128
|
+
additionalData: { method, timeoutMs }
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var IframeRpcChannelRemoteError = class extends IframeRpcChannelError {
|
|
133
|
+
constructor({ method, message }) {
|
|
134
|
+
super({
|
|
135
|
+
message: `RPC method '${method}' failed: ${message}`,
|
|
136
|
+
additionalData: { method }
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var IframeRpcChannelUnsubscribedError = class extends IframeRpcChannelError {
|
|
141
|
+
constructor({ method }) {
|
|
142
|
+
super({
|
|
143
|
+
message: `RPC was unsubscribed while '${method}' was pending`,
|
|
144
|
+
additionalData: { method }
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var IframeRpcChannelUnknownMethodError = class extends IframeRpcChannelError {
|
|
149
|
+
constructor({ method }) {
|
|
150
|
+
super({
|
|
151
|
+
message: `Unknown RPC method '${method}'`,
|
|
152
|
+
additionalData: { method }
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var IframeRpcChannelConfigurationError = class extends IframeRpcChannelError {
|
|
157
|
+
constructor({ message }) {
|
|
158
|
+
super({ message });
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var IframeRpcChannelInvalidInputError = class extends IframeRpcChannelError {
|
|
162
|
+
constructor({ method, cause }) {
|
|
163
|
+
super({
|
|
164
|
+
message: `Invalid RPC input for '${method}': ${cause.message}`,
|
|
165
|
+
cause,
|
|
166
|
+
additionalData: { method }
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// ../schemas/iframeRpcChannel.ts
|
|
172
|
+
var iframeRpcCallResultSchema = z.discriminatedUnion("type", [
|
|
173
|
+
z.object({
|
|
174
|
+
type: z.literal("success"),
|
|
175
|
+
data: z.unknown()
|
|
176
|
+
}),
|
|
177
|
+
z.object({
|
|
178
|
+
type: z.literal("error"),
|
|
179
|
+
errorMessage: z.string()
|
|
180
|
+
})
|
|
181
|
+
]);
|
|
182
|
+
var iframeRpcCallSchema = z.discriminatedUnion("type", [
|
|
183
|
+
z.object({
|
|
184
|
+
type: z.literal("notify"),
|
|
185
|
+
method: z.string(),
|
|
186
|
+
data: z.unknown().optional()
|
|
187
|
+
}),
|
|
188
|
+
z.object({
|
|
189
|
+
type: z.literal("request"),
|
|
190
|
+
id: z.uuid(),
|
|
191
|
+
method: z.string(),
|
|
192
|
+
data: z.unknown().optional()
|
|
193
|
+
}),
|
|
194
|
+
z.object({
|
|
195
|
+
type: z.literal("response"),
|
|
196
|
+
id: z.uuid(),
|
|
197
|
+
result: iframeRpcCallResultSchema
|
|
198
|
+
})
|
|
199
|
+
]);
|
|
200
|
+
function isFireAndForgetOutputSchema(outputSchema) {
|
|
201
|
+
return outputSchema.type === "void" || outputSchema instanceof z.ZodVoid;
|
|
202
|
+
}
|
|
203
|
+
function isUndefinedInputSchema(inputSchema) {
|
|
204
|
+
return inputSchema.type === "undefined" || inputSchema instanceof z.ZodUndefined;
|
|
205
|
+
}
|
|
206
|
+
function coerceEmptyRpcInput({
|
|
207
|
+
input,
|
|
208
|
+
inputSchema
|
|
209
|
+
}) {
|
|
210
|
+
if (isNullish(input) && isUndefinedInputSchema(inputSchema)) {
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
return input;
|
|
214
|
+
}
|
|
215
|
+
function createIframeRpcRemote(channelOrGetChannel, methods) {
|
|
216
|
+
const getChannel = typeof channelOrGetChannel === "function" ? channelOrGetChannel : () => channelOrGetChannel;
|
|
217
|
+
const outgoingMethods = methods ?? getChannel()?.outgoingMethods ?? null;
|
|
218
|
+
if (!outgoingMethods) {
|
|
219
|
+
throw new IframeRpcChannelConfigurationError({
|
|
220
|
+
message: "createIframeRpcRemote requires methods when the channel may be null"
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return Object.fromEntries(
|
|
224
|
+
Object.keys(outgoingMethods).map(
|
|
225
|
+
(method) => {
|
|
226
|
+
return [
|
|
227
|
+
method,
|
|
228
|
+
(input) => {
|
|
229
|
+
const definition = outgoingMethods[method];
|
|
230
|
+
const channel = getChannel();
|
|
231
|
+
if (!channel) {
|
|
232
|
+
if (definition && isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
233
|
+
return void 0;
|
|
234
|
+
}
|
|
235
|
+
return Promise.reject(
|
|
236
|
+
new IframeRpcChannelUnsubscribedError({ method })
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
return channel.call({
|
|
240
|
+
method,
|
|
241
|
+
input
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
function createIframeRpcChannel(options) {
|
|
250
|
+
const {
|
|
251
|
+
subscriberWindow,
|
|
252
|
+
channelIdentifier,
|
|
253
|
+
version,
|
|
254
|
+
getTargetWindow,
|
|
255
|
+
targetOrigin,
|
|
256
|
+
isExpectedMessage,
|
|
257
|
+
outgoingMethods,
|
|
258
|
+
incomingMethods,
|
|
259
|
+
handlers
|
|
260
|
+
} = options;
|
|
261
|
+
const pendingRequests = /* @__PURE__ */ new Map();
|
|
262
|
+
let subscriberCount = 0;
|
|
263
|
+
let handlerMeta;
|
|
264
|
+
const postMessage = (call2) => {
|
|
265
|
+
getTargetWindow()?.postMessage(
|
|
266
|
+
{
|
|
267
|
+
channelIdentifier,
|
|
268
|
+
version,
|
|
269
|
+
...call2
|
|
270
|
+
},
|
|
271
|
+
targetOrigin
|
|
272
|
+
);
|
|
273
|
+
};
|
|
274
|
+
const respondWithError = ({
|
|
275
|
+
id,
|
|
276
|
+
errorMessage
|
|
277
|
+
}) => {
|
|
278
|
+
postMessage({
|
|
279
|
+
type: "response",
|
|
280
|
+
id,
|
|
281
|
+
result: { type: "error", errorMessage }
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
const handleRequest = async (message) => {
|
|
285
|
+
const definition = incomingMethods[message.method];
|
|
286
|
+
if (!definition || isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
287
|
+
respondWithError({
|
|
288
|
+
id: message.id,
|
|
289
|
+
errorMessage: `Unknown RPC method '${message.method}'`
|
|
290
|
+
});
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const parsedInput = definition.inputSchema.safeParse(
|
|
294
|
+
coerceEmptyRpcInput({
|
|
295
|
+
input: message.data,
|
|
296
|
+
inputSchema: definition.inputSchema
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
if (!parsedInput.success) {
|
|
300
|
+
respondWithError({
|
|
301
|
+
id: message.id,
|
|
302
|
+
errorMessage: `Invalid request payload for '${message.method}': ${parsedInput.error.message}`
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
const handler = handlers[
|
|
308
|
+
// eslint-disable-next-line replo/no-as-cast -- NOTE (Noah, 2026-07-25): The method existence check above narrows this dynamic wire string to the configured handler keys.
|
|
309
|
+
message.method
|
|
310
|
+
];
|
|
311
|
+
const result = await handler(parsedInput.data, handlerMeta);
|
|
312
|
+
const parsedOutput = definition.outputSchema.safeParse(result);
|
|
313
|
+
if (!parsedOutput.success) {
|
|
314
|
+
respondWithError({
|
|
315
|
+
id: message.id,
|
|
316
|
+
errorMessage: `Invalid response payload for '${message.method}': ${parsedOutput.error.message}`
|
|
317
|
+
});
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
postMessage({
|
|
321
|
+
type: "response",
|
|
322
|
+
id: message.id,
|
|
323
|
+
result: { type: "success", data: parsedOutput.data }
|
|
324
|
+
});
|
|
325
|
+
} catch (error) {
|
|
326
|
+
respondWithError({
|
|
327
|
+
id: message.id,
|
|
328
|
+
errorMessage: error instanceof Error ? error.message : String(error)
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
const handleNotification = (message) => {
|
|
333
|
+
const definition = incomingMethods[message.method];
|
|
334
|
+
if (!definition || !isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const parsedInput = definition.inputSchema.safeParse(
|
|
338
|
+
coerceEmptyRpcInput({
|
|
339
|
+
input: message.data,
|
|
340
|
+
inputSchema: definition.inputSchema
|
|
341
|
+
})
|
|
342
|
+
);
|
|
343
|
+
if (!parsedInput.success) {
|
|
344
|
+
defaultLogger.error(
|
|
345
|
+
`[iframeRpcChannel] Dropping invalid notify for '${message.method}': ${parsedInput.error.message}`
|
|
346
|
+
);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const handler = handlers[
|
|
350
|
+
// eslint-disable-next-line replo/no-as-cast -- NOTE (Noah, 2026-08-07): Method existence check narrows this wire string to configured handler keys.
|
|
351
|
+
message.method
|
|
352
|
+
];
|
|
353
|
+
handler(parsedInput.data, handlerMeta);
|
|
354
|
+
};
|
|
355
|
+
const handleResponse = (message) => {
|
|
356
|
+
const pendingRequest = pendingRequests.get(message.id);
|
|
357
|
+
if (!pendingRequest) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
clearTimeout(pendingRequest.timeoutId);
|
|
361
|
+
pendingRequests.delete(message.id);
|
|
362
|
+
if (message.result.type === "error") {
|
|
363
|
+
pendingRequest.reject(
|
|
364
|
+
new IframeRpcChannelRemoteError({
|
|
365
|
+
method: pendingRequest.method,
|
|
366
|
+
message: message.result.errorMessage
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const definition = outgoingMethods[pendingRequest.method];
|
|
372
|
+
const parsedOutput = definition?.outputSchema.safeParse(
|
|
373
|
+
message.result.data
|
|
374
|
+
);
|
|
375
|
+
if (!parsedOutput?.success) {
|
|
376
|
+
pendingRequest.reject(
|
|
377
|
+
new IframeRpcChannelRemoteError({
|
|
378
|
+
method: pendingRequest.method,
|
|
379
|
+
message: `Invalid response payload: ${parsedOutput?.error.message ?? "unknown method"}`
|
|
380
|
+
})
|
|
381
|
+
);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
pendingRequest.resolve(parsedOutput.data);
|
|
385
|
+
};
|
|
386
|
+
const handleMessage = (event) => {
|
|
387
|
+
if (!isExpectedMessage(event)) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const parsedMetadata = z.object({
|
|
391
|
+
channelIdentifier: z.literal(channelIdentifier),
|
|
392
|
+
version: z.literal(version)
|
|
393
|
+
}).safeParse(event.data);
|
|
394
|
+
if (!parsedMetadata.success) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const parsedCall = iframeRpcCallSchema.safeParse(event.data);
|
|
398
|
+
if (!parsedCall.success) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const message = parsedCall.data;
|
|
402
|
+
if (message.type === "notify") {
|
|
403
|
+
handleNotification(message);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (message.type === "request") {
|
|
407
|
+
void handleRequest(message);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
handleResponse(message);
|
|
411
|
+
};
|
|
412
|
+
const rejectPendingRequests = () => {
|
|
413
|
+
for (const pendingRequest of pendingRequests.values()) {
|
|
414
|
+
clearTimeout(pendingRequest.timeoutId);
|
|
415
|
+
pendingRequest.reject(
|
|
416
|
+
new IframeRpcChannelUnsubscribedError({
|
|
417
|
+
method: pendingRequest.method
|
|
418
|
+
})
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
pendingRequests.clear();
|
|
422
|
+
};
|
|
423
|
+
const subscribe = () => {
|
|
424
|
+
subscriberCount += 1;
|
|
425
|
+
if (subscriberCount === 1) {
|
|
426
|
+
subscriberWindow.addEventListener("message", handleMessage);
|
|
427
|
+
}
|
|
428
|
+
let isActive = true;
|
|
429
|
+
return () => {
|
|
430
|
+
if (!isActive) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
isActive = false;
|
|
434
|
+
subscriberCount -= 1;
|
|
435
|
+
if (subscriberCount === 0) {
|
|
436
|
+
subscriberWindow.removeEventListener("message", handleMessage);
|
|
437
|
+
rejectPendingRequests();
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
};
|
|
441
|
+
const call = ({
|
|
442
|
+
method,
|
|
443
|
+
input
|
|
444
|
+
}) => {
|
|
445
|
+
const definition = outgoingMethods[method];
|
|
446
|
+
if (!definition) {
|
|
447
|
+
return Promise.reject(
|
|
448
|
+
new IframeRpcChannelUnknownMethodError({ method })
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
const isFireAndForget = isFireAndForgetOutputSchema(
|
|
452
|
+
definition.outputSchema
|
|
453
|
+
);
|
|
454
|
+
const parsedInput = definition.inputSchema.safeParse(
|
|
455
|
+
coerceEmptyRpcInput({
|
|
456
|
+
input,
|
|
457
|
+
inputSchema: definition.inputSchema
|
|
458
|
+
})
|
|
459
|
+
);
|
|
460
|
+
if (!parsedInput.success) {
|
|
461
|
+
const error = new IframeRpcChannelInvalidInputError({
|
|
462
|
+
method,
|
|
463
|
+
cause: parsedInput.error
|
|
464
|
+
});
|
|
465
|
+
if (isFireAndForget) {
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
return Promise.reject(error);
|
|
469
|
+
}
|
|
470
|
+
if (isFireAndForget) {
|
|
471
|
+
postMessage({
|
|
472
|
+
type: "notify",
|
|
473
|
+
method,
|
|
474
|
+
data: parsedInput.data
|
|
475
|
+
});
|
|
476
|
+
return void 0;
|
|
477
|
+
}
|
|
478
|
+
if (subscriberCount === 0) {
|
|
479
|
+
return Promise.reject(
|
|
480
|
+
new IframeRpcChannelUnsubscribedError({ method })
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
const id = randomUUID();
|
|
484
|
+
const timeoutMs = definition.timeoutMs ?? 3e4;
|
|
485
|
+
return new Promise(
|
|
486
|
+
(resolve, reject) => {
|
|
487
|
+
const timeoutId = setTimeout(() => {
|
|
488
|
+
pendingRequests.delete(id);
|
|
489
|
+
reject(new IframeRpcChannelTimeoutError({ method, timeoutMs }));
|
|
490
|
+
}, timeoutMs);
|
|
491
|
+
pendingRequests.set(id, {
|
|
492
|
+
method,
|
|
493
|
+
// PendingRequest is shared across methods, so resolve is typed as
|
|
494
|
+
// unknown; handleResponse already validated against this method's
|
|
495
|
+
// outputSchema before calling it.
|
|
496
|
+
resolve: (value) => {
|
|
497
|
+
resolve(value);
|
|
498
|
+
},
|
|
499
|
+
reject,
|
|
500
|
+
timeoutId
|
|
501
|
+
});
|
|
502
|
+
postMessage({
|
|
503
|
+
type: "request",
|
|
504
|
+
id,
|
|
505
|
+
method,
|
|
506
|
+
data: parsedInput.data
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
);
|
|
510
|
+
};
|
|
511
|
+
const channel = {
|
|
512
|
+
subscribe,
|
|
513
|
+
call,
|
|
514
|
+
outgoingMethods
|
|
515
|
+
};
|
|
516
|
+
handlerMeta = { channel: createIframeRpcRemote(channel) };
|
|
517
|
+
return channel;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export { createIframeRpcChannel, createIframeRpcRemote, iframeRpcCallSchema };
|