@replohq/sandbox-runtime 1.17.0 → 1.18.1
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.js +26 -0
- package/DocumentReadyBeacon.js +5 -1
- package/_vendor/schemas/iframeRpcChannel.mjs +3 -541
- package/_vendor/schemas/previewHealthIframeRpc.d.ts +159 -0
- package/_vendor/schemas/previewHealthIframeRpc.mjs +123 -0
- package/_vendor/schemas/selectMode.d.ts +1 -1
- package/_vendor/schemas/selectModeIframeRpc.d.ts +5 -5
- package/buildMetadata.js +3 -3
- package/capturePage.js +5 -1
- package/chunk-KRA4LUIR.mjs +541 -0
- package/nextErrorFeed.d.ts +30 -0
- package/nextErrorFeed.js +64 -0
- package/package.json +5 -12
- package/previewHealth.d.ts +25 -0
- package/previewHealth.js +431 -0
- package/sandbox-runtime.js +0 -2
- package/select-mode/hooks/useSelectionHover.js +5 -0
- package/select-mode/iframeRpcChannel.d.ts +1 -1
- package/select-mode/section-canvas/SectionCanvas.js +80 -124
- package/select-mode/section-canvas/sectionCanvasStore.d.ts +0 -2
- package/select-mode/section-canvas/sectionCanvasStore.js +0 -15
- package/NextErrorReporter.d.ts +0 -1
- package/NextErrorReporter.js +0 -131
- package/_vendor/schemas/componentPreview.d.ts +0 -43
- package/_vendor/schemas/componentPreview.mjs +0 -79
- package/_vendor/schemas/generated/componentPreview.d.ts +0 -5
- package/_vendor/schemas/generated/componentPreview.mjs +0 -1
- package/_vendor/schemas/loaderKeys.d.ts +0 -69
- package/next/component-preview-client.d.ts +0 -8
- package/next/component-preview-client.js +0 -227
- package/next/component-preview-href.d.ts +0 -5
- package/next/component-preview-href.js +0 -13
- package/next/component-preview-props.d.ts +0 -8
- package/next/component-preview-props.js +0 -35
- package/next/component-preview.d.ts +0 -11
- package/next/component-preview.js +0 -83
- package/select-mode/section-canvas/sectionGhost.d.ts +0 -5
- package/select-mode/section-canvas/sectionGhost.js +0 -23
package/ClientErrorBoundary.js
CHANGED
|
@@ -1,17 +1,43 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
import { getPreviewHealthActions } from "./previewHealth";
|
|
4
6
|
class ErrorBoundary extends React.Component {
|
|
5
7
|
state = {
|
|
6
8
|
didCatch: false
|
|
7
9
|
};
|
|
10
|
+
boundaryId = uuidv4();
|
|
11
|
+
caughtError = null;
|
|
8
12
|
static getDerivedStateFromError() {
|
|
9
13
|
return { didCatch: true };
|
|
10
14
|
}
|
|
15
|
+
componentDidMount() {
|
|
16
|
+
if (!this.state.didCatch) {
|
|
17
|
+
getPreviewHealthActions()?.boundaryRendered(this.boundaryId);
|
|
18
|
+
} else if (this.caughtError) {
|
|
19
|
+
getPreviewHealthActions()?.boundaryCaughtError(
|
|
20
|
+
this.boundaryId,
|
|
21
|
+
this.caughtError
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
componentWillUnmount() {
|
|
26
|
+
getPreviewHealthActions()?.boundaryUnmounted(this.boundaryId);
|
|
27
|
+
}
|
|
11
28
|
componentDidCatch(error, info) {
|
|
29
|
+
this.caughtError = { error, componentStack: info.componentStack ?? null };
|
|
30
|
+
getPreviewHealthActions()?.boundaryCaughtError(
|
|
31
|
+
this.boundaryId,
|
|
32
|
+
this.caughtError
|
|
33
|
+
);
|
|
12
34
|
this.props.onError?.(error, info);
|
|
13
35
|
}
|
|
14
36
|
componentDidUpdate(previousProps, previousState) {
|
|
37
|
+
if (previousState.didCatch && !this.state.didCatch) {
|
|
38
|
+
this.caughtError = null;
|
|
39
|
+
getPreviewHealthActions()?.boundaryRendered(this.boundaryId);
|
|
40
|
+
}
|
|
15
41
|
if (this.state.didCatch && previousState.didCatch && !Object.is(previousProps.resetKey, this.props.resetKey)) {
|
|
16
42
|
this.setState({ didCatch: false });
|
|
17
43
|
}
|
package/DocumentReadyBeacon.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
2
|
+
import {
|
|
3
|
+
PREVIEW_HEALTH_IFRAME_RPC_CHANNEL_ID,
|
|
4
|
+
PREVIEW_HEALTH_IFRAME_RPC_CHANNEL_VERSION
|
|
5
|
+
} from "./_vendor/schemas/previewHealthIframeRpc.mjs";
|
|
6
|
+
const BEACON_SCRIPT = `if (window.parent !== window) { window.parent.postMessage({ channelIdentifier: ${JSON.stringify(PREVIEW_HEALTH_IFRAME_RPC_CHANNEL_ID)}, version: ${PREVIEW_HEALTH_IFRAME_RPC_CHANNEL_VERSION}, type: "notify", method: "documentArrived", data: { route: window.location.pathname } }, "*"); }`;
|
|
3
7
|
function DocumentReadyBeacon() {
|
|
4
8
|
return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: BEACON_SCRIPT } });
|
|
5
9
|
}
|
|
@@ -1,544 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
export { createIframeRpcChannel, createIframeRpcRemote, iframeRpcCallSchema } from '../../chunk-KRA4LUIR.mjs';
|
|
2
|
+
import '../../chunk-LIPH4O4F.mjs';
|
|
3
|
+
import '../../chunk-PH3S6LJI.mjs';
|
|
3
4
|
import '../../chunk-FLYEIRFK.mjs';
|
|
4
5
|
import '../../chunk-TESFJQID.mjs';
|
|
5
6
|
import '../../chunk-G3S6ZNPF.mjs';
|
|
6
|
-
import * as z from 'zod';
|
|
7
|
-
|
|
8
|
-
var defaultLogger = {
|
|
9
|
-
info: console.log,
|
|
10
|
-
debug: console.debug,
|
|
11
|
-
error: console.error
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
var ReploError = class _ReploError extends Error {
|
|
15
|
-
config;
|
|
16
|
-
id;
|
|
17
|
-
constructor(config) {
|
|
18
|
-
super(config.message);
|
|
19
|
-
this.message = config.message ?? this.constructor.name;
|
|
20
|
-
this.config = config;
|
|
21
|
-
this.id = randomUUID();
|
|
22
|
-
const cause = config.cause;
|
|
23
|
-
if (cause) {
|
|
24
|
-
this.cause = cause;
|
|
25
|
-
if (cause instanceof _ReploError) {
|
|
26
|
-
this.config.additionalData = {
|
|
27
|
-
...this.config.additionalData,
|
|
28
|
-
...cause.config.additionalData
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
var errorUserFacingDetailsMessageSchema = z.object({
|
|
36
|
-
type: z.enum([
|
|
37
|
-
"toast",
|
|
38
|
-
"fullPageModal",
|
|
39
|
-
"shopifyStorePassword",
|
|
40
|
-
"billing.addPublishedElements",
|
|
41
|
-
"billing.addShopifyThemeProject",
|
|
42
|
-
"billing.addReploSite",
|
|
43
|
-
"agentBilling.shopifyThemeBuilder.publishedElements.exceeded",
|
|
44
|
-
"agentBilling.shopifyThemeBuilder.projects.exceeded",
|
|
45
|
-
"agentBilling.sites.exceeded",
|
|
46
|
-
"agentBilling.credits.exceeded",
|
|
47
|
-
"agentBilling.upgradeRequired"
|
|
48
|
-
]),
|
|
49
|
-
message: z.string(),
|
|
50
|
-
isRecoverable: z.boolean().optional(),
|
|
51
|
-
detail: z.array(z.string()).or(z.string()).optional(),
|
|
52
|
-
key: z.string(),
|
|
53
|
-
details: z.record(z.string(), z.unknown()).optional(),
|
|
54
|
-
usage: z.object({
|
|
55
|
-
current: z.number(),
|
|
56
|
-
maximum: z.number()
|
|
57
|
-
}).optional(),
|
|
58
|
-
plan: z.string().optional(),
|
|
59
|
-
callToAction: z.discriminatedUnion("type", [
|
|
60
|
-
z.object({ type: z.literal("reload") }),
|
|
61
|
-
z.object({ type: z.literal("installApp") }),
|
|
62
|
-
z.object({ type: z.literal("goToHomepage") }),
|
|
63
|
-
z.object({ type: z.literal("navigateToProjectEditor") }),
|
|
64
|
-
z.object({ type: z.literal("closeModal") }),
|
|
65
|
-
z.object({
|
|
66
|
-
type: z.literal("navigateToLink"),
|
|
67
|
-
link: z.discriminatedUnion("type", [
|
|
68
|
-
z.object({ type: z.literal("errors.wrongJsonExtension") }),
|
|
69
|
-
z.object({ type: z.literal("errors.chunkingError") }),
|
|
70
|
-
z.object({ type: z.literal("errors.indexBackupError") }),
|
|
71
|
-
z.object({
|
|
72
|
-
type: z.literal("errors.shopifyIntegrationAlreadyAssigned")
|
|
73
|
-
}),
|
|
74
|
-
z.object({
|
|
75
|
-
type: z.literal("errors.shopifyIntegrationMissingAccessScopes"),
|
|
76
|
-
url: z.string()
|
|
77
|
-
}),
|
|
78
|
-
z.object({
|
|
79
|
-
type: z.literal("customLink"),
|
|
80
|
-
url: z.string()
|
|
81
|
-
}),
|
|
82
|
-
z.object({
|
|
83
|
-
type: z.literal(
|
|
84
|
-
"errors.projectConnectedToBillingIntegrationForShopifyWorkspace"
|
|
85
|
-
)
|
|
86
|
-
}),
|
|
87
|
-
z.object({ type: z.literal("errors.themeAssetSizeLimitExceeded") }),
|
|
88
|
-
z.object({ type: z.literal("errors.themeTotalSizeLimitExceeded") }),
|
|
89
|
-
z.object({
|
|
90
|
-
type: z.literal("errors.pageMetafieldDefinitionsChanged")
|
|
91
|
-
}),
|
|
92
|
-
z.object({ type: z.literal("settings.billing") })
|
|
93
|
-
])
|
|
94
|
-
})
|
|
95
|
-
]).optional()
|
|
96
|
-
}).describe("ErrorUserFacingDetailsWithMessage");
|
|
97
|
-
z.discriminatedUnion("type", [
|
|
98
|
-
errorUserFacingDetailsMessageSchema,
|
|
99
|
-
z.object({
|
|
100
|
-
type: z.literal("uncommon_none"),
|
|
101
|
-
key: z.string(),
|
|
102
|
-
usage: z.object({
|
|
103
|
-
current: z.number(),
|
|
104
|
-
maximum: z.number()
|
|
105
|
-
}).optional(),
|
|
106
|
-
message: z.string().optional(),
|
|
107
|
-
isRecoverable: z.boolean().optional(),
|
|
108
|
-
detail: z.array(z.string()).or(z.string()).optional()
|
|
109
|
-
})
|
|
110
|
-
]).describe("ErrorUserFacingDetails");
|
|
111
|
-
var IframeRpcChannelError = class extends ReploError {
|
|
112
|
-
};
|
|
113
|
-
var IframeRpcChannelTimeoutError = class extends IframeRpcChannelError {
|
|
114
|
-
constructor({ method, timeoutMs }) {
|
|
115
|
-
super({
|
|
116
|
-
message: `RPC method '${method}' timed out after ${timeoutMs}ms`,
|
|
117
|
-
additionalData: { method, timeoutMs }
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
var IframeRpcChannelTargetUnavailableError = class extends IframeRpcChannelError {
|
|
122
|
-
constructor({
|
|
123
|
-
callType,
|
|
124
|
-
method
|
|
125
|
-
}) {
|
|
126
|
-
super({
|
|
127
|
-
message: method ? `RPC target window was unavailable for '${method}'` : "RPC target window was unavailable for a response",
|
|
128
|
-
additionalData: { callType, method }
|
|
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
|
-
var iframeRpcCallResultSchema = z.discriminatedUnion("type", [
|
|
172
|
-
z.object({
|
|
173
|
-
type: z.literal("success"),
|
|
174
|
-
data: z.unknown()
|
|
175
|
-
}),
|
|
176
|
-
z.object({
|
|
177
|
-
type: z.literal("error"),
|
|
178
|
-
errorMessage: z.string()
|
|
179
|
-
})
|
|
180
|
-
]);
|
|
181
|
-
var iframeRpcCallSchema = z.discriminatedUnion("type", [
|
|
182
|
-
z.object({
|
|
183
|
-
type: z.literal("notify"),
|
|
184
|
-
method: z.string(),
|
|
185
|
-
data: z.unknown().optional()
|
|
186
|
-
}),
|
|
187
|
-
z.object({
|
|
188
|
-
type: z.literal("request"),
|
|
189
|
-
id: z.uuid(),
|
|
190
|
-
method: z.string(),
|
|
191
|
-
data: z.unknown().optional()
|
|
192
|
-
}),
|
|
193
|
-
z.object({
|
|
194
|
-
type: z.literal("response"),
|
|
195
|
-
id: z.uuid(),
|
|
196
|
-
result: iframeRpcCallResultSchema
|
|
197
|
-
})
|
|
198
|
-
]);
|
|
199
|
-
function isFireAndForgetOutputSchema(outputSchema) {
|
|
200
|
-
return outputSchema.type === "void" || outputSchema instanceof z.ZodVoid;
|
|
201
|
-
}
|
|
202
|
-
function isUndefinedInputSchema(inputSchema) {
|
|
203
|
-
return inputSchema.type === "undefined" || inputSchema instanceof z.ZodUndefined;
|
|
204
|
-
}
|
|
205
|
-
function coerceEmptyRpcInput({
|
|
206
|
-
input,
|
|
207
|
-
inputSchema
|
|
208
|
-
}) {
|
|
209
|
-
if (isNullish(input) && isUndefinedInputSchema(inputSchema)) {
|
|
210
|
-
return void 0;
|
|
211
|
-
}
|
|
212
|
-
return input;
|
|
213
|
-
}
|
|
214
|
-
function createIframeRpcRemote(channelOrGetChannel, methods) {
|
|
215
|
-
const getChannel = typeof channelOrGetChannel === "function" ? channelOrGetChannel : () => channelOrGetChannel;
|
|
216
|
-
const outgoingMethods = methods ?? getChannel()?.outgoingMethods ?? null;
|
|
217
|
-
if (!outgoingMethods) {
|
|
218
|
-
throw new IframeRpcChannelConfigurationError({
|
|
219
|
-
message: "createIframeRpcRemote requires methods when the channel may be null"
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
return Object.fromEntries(
|
|
223
|
-
Object.keys(outgoingMethods).map(
|
|
224
|
-
(method) => {
|
|
225
|
-
return [
|
|
226
|
-
method,
|
|
227
|
-
(input) => {
|
|
228
|
-
const definition = outgoingMethods[method];
|
|
229
|
-
const channel = getChannel();
|
|
230
|
-
if (!channel) {
|
|
231
|
-
if (definition && isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
232
|
-
return void 0;
|
|
233
|
-
}
|
|
234
|
-
return Promise.reject(
|
|
235
|
-
new IframeRpcChannelUnsubscribedError({ method })
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
return channel.call({
|
|
239
|
-
method,
|
|
240
|
-
input
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
)
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
function createIframeRpcChannel(options) {
|
|
249
|
-
const {
|
|
250
|
-
subscriberWindow,
|
|
251
|
-
channelIdentifier,
|
|
252
|
-
version,
|
|
253
|
-
getTargetWindow,
|
|
254
|
-
targetOrigin,
|
|
255
|
-
isExpectedMessage,
|
|
256
|
-
outgoingMethods,
|
|
257
|
-
incomingMethods,
|
|
258
|
-
handlers
|
|
259
|
-
} = options;
|
|
260
|
-
const pendingRequests = /* @__PURE__ */ new Map();
|
|
261
|
-
let subscriberCount = 0;
|
|
262
|
-
let handlerMeta;
|
|
263
|
-
const postMessage = (call2, targetWindow = getTargetWindow()) => {
|
|
264
|
-
targetWindow?.postMessage(
|
|
265
|
-
{
|
|
266
|
-
channelIdentifier,
|
|
267
|
-
version,
|
|
268
|
-
...call2
|
|
269
|
-
},
|
|
270
|
-
targetOrigin
|
|
271
|
-
);
|
|
272
|
-
};
|
|
273
|
-
const respondWithError = ({
|
|
274
|
-
id,
|
|
275
|
-
errorMessage
|
|
276
|
-
}) => {
|
|
277
|
-
postMessage({
|
|
278
|
-
type: "response",
|
|
279
|
-
id,
|
|
280
|
-
result: { type: "error", errorMessage }
|
|
281
|
-
});
|
|
282
|
-
};
|
|
283
|
-
const handleRequest = async (message) => {
|
|
284
|
-
const definition = incomingMethods[message.method];
|
|
285
|
-
if (!definition || isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
286
|
-
respondWithError({
|
|
287
|
-
id: message.id,
|
|
288
|
-
errorMessage: `Unknown RPC method '${message.method}'`
|
|
289
|
-
});
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
const parsedInput = definition.inputSchema.safeParse(
|
|
293
|
-
coerceEmptyRpcInput({
|
|
294
|
-
input: message.data,
|
|
295
|
-
inputSchema: definition.inputSchema
|
|
296
|
-
})
|
|
297
|
-
);
|
|
298
|
-
if (!parsedInput.success) {
|
|
299
|
-
respondWithError({
|
|
300
|
-
id: message.id,
|
|
301
|
-
errorMessage: `Invalid request payload for '${message.method}': ${parsedInput.error.message}`
|
|
302
|
-
});
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
try {
|
|
306
|
-
const handler = handlers[
|
|
307
|
-
message.method
|
|
308
|
-
];
|
|
309
|
-
const result = await handler(parsedInput.data, handlerMeta);
|
|
310
|
-
const parsedOutput = definition.outputSchema.safeParse(result);
|
|
311
|
-
if (!parsedOutput.success) {
|
|
312
|
-
respondWithError({
|
|
313
|
-
id: message.id,
|
|
314
|
-
errorMessage: `Invalid response payload for '${message.method}': ${parsedOutput.error.message}`
|
|
315
|
-
});
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
postMessage({
|
|
319
|
-
type: "response",
|
|
320
|
-
id: message.id,
|
|
321
|
-
result: { type: "success", data: parsedOutput.data }
|
|
322
|
-
});
|
|
323
|
-
} catch (error) {
|
|
324
|
-
respondWithError({
|
|
325
|
-
id: message.id,
|
|
326
|
-
errorMessage: error instanceof Error ? error.message : String(error)
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
const handleNotification = (message) => {
|
|
331
|
-
const definition = incomingMethods[message.method];
|
|
332
|
-
if (!definition || !isFireAndForgetOutputSchema(definition.outputSchema)) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
const parsedInput = definition.inputSchema.safeParse(
|
|
336
|
-
coerceEmptyRpcInput({
|
|
337
|
-
input: message.data,
|
|
338
|
-
inputSchema: definition.inputSchema
|
|
339
|
-
})
|
|
340
|
-
);
|
|
341
|
-
if (!parsedInput.success) {
|
|
342
|
-
defaultLogger.error(
|
|
343
|
-
`[iframeRpcChannel] Dropping invalid notify for '${message.method}': ${parsedInput.error.message}`
|
|
344
|
-
);
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
const handler = handlers[
|
|
348
|
-
message.method
|
|
349
|
-
];
|
|
350
|
-
handler(parsedInput.data, handlerMeta);
|
|
351
|
-
};
|
|
352
|
-
const handleResponse = (message) => {
|
|
353
|
-
const pendingRequest = pendingRequests.get(message.id);
|
|
354
|
-
if (!pendingRequest) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
clearTimeout(pendingRequest.timeoutId);
|
|
358
|
-
pendingRequests.delete(message.id);
|
|
359
|
-
if (message.result.type === "error") {
|
|
360
|
-
pendingRequest.reject(
|
|
361
|
-
new IframeRpcChannelRemoteError({
|
|
362
|
-
method: pendingRequest.method,
|
|
363
|
-
message: message.result.errorMessage
|
|
364
|
-
})
|
|
365
|
-
);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
const definition = outgoingMethods[pendingRequest.method];
|
|
369
|
-
const parsedOutput = definition?.outputSchema.safeParse(
|
|
370
|
-
message.result.data
|
|
371
|
-
);
|
|
372
|
-
if (!parsedOutput?.success) {
|
|
373
|
-
pendingRequest.reject(
|
|
374
|
-
new IframeRpcChannelRemoteError({
|
|
375
|
-
method: pendingRequest.method,
|
|
376
|
-
message: `Invalid response payload: ${parsedOutput?.error.message ?? "unknown method"}`
|
|
377
|
-
})
|
|
378
|
-
);
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
pendingRequest.resolve(parsedOutput.data);
|
|
382
|
-
};
|
|
383
|
-
const handleMessage = (event) => {
|
|
384
|
-
const parsedMetadata = z.object({
|
|
385
|
-
channelIdentifier: z.literal(channelIdentifier),
|
|
386
|
-
version: z.literal(version)
|
|
387
|
-
}).safeParse(event.data);
|
|
388
|
-
if (!parsedMetadata.success) {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (!isExpectedMessage(event)) {
|
|
392
|
-
const isSiblingFrame = typeof document !== "undefined" && Array.from(document.querySelectorAll("iframe")).some((frame) => {
|
|
393
|
-
return event.source !== null && frame.contentWindow === event.source;
|
|
394
|
-
});
|
|
395
|
-
if (isSiblingFrame) {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
defaultLogger.error("[iframeRpcChannel] Dropping unexpected message", {
|
|
399
|
-
channelIdentifier,
|
|
400
|
-
version,
|
|
401
|
-
origin: event.origin,
|
|
402
|
-
hasSource: Boolean(event.source)
|
|
403
|
-
});
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
const parsedCall = iframeRpcCallSchema.safeParse(event.data);
|
|
407
|
-
if (!parsedCall.success) {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
const message = parsedCall.data;
|
|
411
|
-
if (message.type === "notify") {
|
|
412
|
-
handleNotification(message);
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
if (message.type === "request") {
|
|
416
|
-
void handleRequest(message);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
handleResponse(message);
|
|
420
|
-
};
|
|
421
|
-
const rejectPendingRequests = () => {
|
|
422
|
-
for (const pendingRequest of pendingRequests.values()) {
|
|
423
|
-
clearTimeout(pendingRequest.timeoutId);
|
|
424
|
-
pendingRequest.reject(
|
|
425
|
-
new IframeRpcChannelUnsubscribedError({
|
|
426
|
-
method: pendingRequest.method
|
|
427
|
-
})
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
pendingRequests.clear();
|
|
431
|
-
};
|
|
432
|
-
const subscribe = () => {
|
|
433
|
-
subscriberCount += 1;
|
|
434
|
-
if (subscriberCount === 1) {
|
|
435
|
-
subscriberWindow.addEventListener("message", handleMessage);
|
|
436
|
-
}
|
|
437
|
-
let isActive = true;
|
|
438
|
-
return () => {
|
|
439
|
-
if (!isActive) {
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
isActive = false;
|
|
443
|
-
subscriberCount -= 1;
|
|
444
|
-
if (subscriberCount === 0) {
|
|
445
|
-
subscriberWindow.removeEventListener("message", handleMessage);
|
|
446
|
-
rejectPendingRequests();
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
};
|
|
450
|
-
const call = ({
|
|
451
|
-
method,
|
|
452
|
-
input
|
|
453
|
-
}) => {
|
|
454
|
-
const definition = outgoingMethods[method];
|
|
455
|
-
if (!definition) {
|
|
456
|
-
return Promise.reject(
|
|
457
|
-
new IframeRpcChannelUnknownMethodError({ method })
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
const isFireAndForget = isFireAndForgetOutputSchema(
|
|
461
|
-
definition.outputSchema
|
|
462
|
-
);
|
|
463
|
-
const parsedInput = definition.inputSchema.safeParse(
|
|
464
|
-
coerceEmptyRpcInput({
|
|
465
|
-
input,
|
|
466
|
-
inputSchema: definition.inputSchema
|
|
467
|
-
})
|
|
468
|
-
);
|
|
469
|
-
if (!parsedInput.success) {
|
|
470
|
-
const error = new IframeRpcChannelInvalidInputError({
|
|
471
|
-
method,
|
|
472
|
-
cause: parsedInput.error
|
|
473
|
-
});
|
|
474
|
-
if (isFireAndForget) {
|
|
475
|
-
throw error;
|
|
476
|
-
}
|
|
477
|
-
return Promise.reject(error);
|
|
478
|
-
}
|
|
479
|
-
if (isFireAndForget) {
|
|
480
|
-
postMessage({
|
|
481
|
-
type: "notify",
|
|
482
|
-
method,
|
|
483
|
-
data: parsedInput.data
|
|
484
|
-
});
|
|
485
|
-
return void 0;
|
|
486
|
-
}
|
|
487
|
-
if (subscriberCount === 0) {
|
|
488
|
-
return Promise.reject(
|
|
489
|
-
new IframeRpcChannelUnsubscribedError({ method })
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
const targetWindow = getTargetWindow();
|
|
493
|
-
if (!targetWindow) {
|
|
494
|
-
return Promise.reject(
|
|
495
|
-
new IframeRpcChannelTargetUnavailableError({
|
|
496
|
-
callType: "request",
|
|
497
|
-
method
|
|
498
|
-
})
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
const id = randomUUID();
|
|
502
|
-
const timeoutMs = definition.timeoutMs ?? 3e4;
|
|
503
|
-
return new Promise(
|
|
504
|
-
(resolve, reject) => {
|
|
505
|
-
const timeoutId = setTimeout(() => {
|
|
506
|
-
pendingRequests.delete(id);
|
|
507
|
-
reject(new IframeRpcChannelTimeoutError({ method, timeoutMs }));
|
|
508
|
-
}, timeoutMs);
|
|
509
|
-
pendingRequests.set(id, {
|
|
510
|
-
method,
|
|
511
|
-
resolve: (value) => {
|
|
512
|
-
resolve(value);
|
|
513
|
-
},
|
|
514
|
-
reject,
|
|
515
|
-
timeoutId
|
|
516
|
-
});
|
|
517
|
-
try {
|
|
518
|
-
postMessage(
|
|
519
|
-
{
|
|
520
|
-
type: "request",
|
|
521
|
-
id,
|
|
522
|
-
method,
|
|
523
|
-
data: parsedInput.data
|
|
524
|
-
},
|
|
525
|
-
targetWindow
|
|
526
|
-
);
|
|
527
|
-
} catch (error) {
|
|
528
|
-
clearTimeout(timeoutId);
|
|
529
|
-
pendingRequests.delete(id);
|
|
530
|
-
reject(error);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
);
|
|
534
|
-
};
|
|
535
|
-
const channel = {
|
|
536
|
-
subscribe,
|
|
537
|
-
call,
|
|
538
|
-
outgoingMethods
|
|
539
|
-
};
|
|
540
|
-
handlerMeta = { channel: createIframeRpcRemote(channel) };
|
|
541
|
-
return channel;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
export { createIframeRpcChannel, createIframeRpcRemote, iframeRpcCallSchema };
|