forgeframe 1.0.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/dist/communication/bridge.d.ts +167 -0
- package/dist/communication/index.d.ts +12 -0
- package/dist/communication/messenger.d.ts +142 -0
- package/dist/communication/protocol.d.ts +75 -0
- package/dist/constants.d.ts +202 -0
- package/dist/core/child.d.ts +223 -0
- package/dist/core/component.d.ts +135 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/parent.d.ts +262 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/react.d.ts +225 -0
- package/dist/events/emitter.d.ts +150 -0
- package/dist/forgeframe.js +2419 -0
- package/dist/index.d.ts +169 -0
- package/dist/props/definitions.d.ts +72 -0
- package/dist/props/index.d.ts +11 -0
- package/dist/props/normalize.d.ts +59 -0
- package/dist/props/serialize.d.ts +60 -0
- package/dist/render/iframe.d.ts +213 -0
- package/dist/render/index.d.ts +38 -0
- package/dist/render/popup.d.ts +215 -0
- package/dist/render/templates.d.ts +202 -0
- package/dist/types.d.ts +906 -0
- package/dist/utils/cleanup.d.ts +122 -0
- package/dist/utils/dimension.d.ts +50 -0
- package/dist/utils/index.d.ts +37 -0
- package/dist/utils/promise.d.ts +155 -0
- package/dist/utils/uid.d.ts +60 -0
- package/dist/window/helpers.d.ts +316 -0
- package/dist/window/index.d.ts +13 -0
- package/dist/window/name-payload.d.ts +188 -0
- package/dist/window/proxy.d.ts +168 -0
- package/package.json +45 -0
|
@@ -0,0 +1,2419 @@
|
|
|
1
|
+
const h = {
|
|
2
|
+
/** String prop type */
|
|
3
|
+
STRING: "string",
|
|
4
|
+
/** Object prop type */
|
|
5
|
+
OBJECT: "object",
|
|
6
|
+
/** Function prop type - serialized for cross-domain calls */
|
|
7
|
+
FUNCTION: "function",
|
|
8
|
+
/** Boolean prop type */
|
|
9
|
+
BOOLEAN: "boolean",
|
|
10
|
+
/** Number prop type */
|
|
11
|
+
NUMBER: "number",
|
|
12
|
+
/** Array prop type */
|
|
13
|
+
ARRAY: "array"
|
|
14
|
+
}, f = {
|
|
15
|
+
/** Render component in an iframe */
|
|
16
|
+
IFRAME: "iframe",
|
|
17
|
+
/** Render component in a popup window */
|
|
18
|
+
POPUP: "popup"
|
|
19
|
+
}, p = {
|
|
20
|
+
/** Emitted when rendering starts */
|
|
21
|
+
RENDER: "render",
|
|
22
|
+
/** Emitted when component is fully rendered and initialized */
|
|
23
|
+
RENDERED: "rendered",
|
|
24
|
+
/** Emitted when prerender (loading) phase starts */
|
|
25
|
+
PRERENDER: "prerender",
|
|
26
|
+
/** Emitted when prerender phase completes */
|
|
27
|
+
PRERENDERED: "prerendered",
|
|
28
|
+
/** Emitted when component becomes visible */
|
|
29
|
+
DISPLAY: "display",
|
|
30
|
+
/** Emitted when an error occurs */
|
|
31
|
+
ERROR: "error",
|
|
32
|
+
/** Emitted when component is closing */
|
|
33
|
+
CLOSE: "close",
|
|
34
|
+
/** Emitted when component is destroyed */
|
|
35
|
+
DESTROY: "destroy",
|
|
36
|
+
/** Emitted when props are updated */
|
|
37
|
+
PROPS: "props",
|
|
38
|
+
/** Emitted when component is resized */
|
|
39
|
+
RESIZE: "resize",
|
|
40
|
+
/** Emitted when component receives focus */
|
|
41
|
+
FOCUS: "focus"
|
|
42
|
+
}, I = {
|
|
43
|
+
/** Default JSON serialization */
|
|
44
|
+
JSON: "json",
|
|
45
|
+
/** Base64 encoding for binary or large data */
|
|
46
|
+
BASE64: "base64",
|
|
47
|
+
/** Dot notation for nested objects (e.g., "a.b.c=value") */
|
|
48
|
+
DOTIFY: "dotify"
|
|
49
|
+
}, T = {
|
|
50
|
+
/** Request message expecting a response */
|
|
51
|
+
REQUEST: "request",
|
|
52
|
+
/** Response to a previous request */
|
|
53
|
+
RESPONSE: "response"
|
|
54
|
+
}, l = {
|
|
55
|
+
/** Child initialization complete */
|
|
56
|
+
INIT: "forgeframe_init",
|
|
57
|
+
/** Props update from parent to child */
|
|
58
|
+
PROPS: "forgeframe_props",
|
|
59
|
+
/** Close request from child */
|
|
60
|
+
CLOSE: "forgeframe_close",
|
|
61
|
+
/** Resize request from child */
|
|
62
|
+
RESIZE: "forgeframe_resize",
|
|
63
|
+
/** Focus request from child */
|
|
64
|
+
FOCUS: "forgeframe_focus",
|
|
65
|
+
/** Show request from child */
|
|
66
|
+
SHOW: "forgeframe_show",
|
|
67
|
+
/** Hide request from child */
|
|
68
|
+
HIDE: "forgeframe_hide",
|
|
69
|
+
/** Error report from child */
|
|
70
|
+
ERROR: "forgeframe_error",
|
|
71
|
+
/** Data export from child to parent */
|
|
72
|
+
EXPORT: "forgeframe_export",
|
|
73
|
+
/** Cross-domain function call */
|
|
74
|
+
CALL: "forgeframe_call",
|
|
75
|
+
/** Parent export from child context */
|
|
76
|
+
PARENT_EXPORT: "forgeframe_parent_export",
|
|
77
|
+
/** Get sibling components request */
|
|
78
|
+
GET_SIBLINGS: "forgeframe_get_siblings"
|
|
79
|
+
}, N = "__forgeframe__", re = "1.0.0";
|
|
80
|
+
class ne {
|
|
81
|
+
/**
|
|
82
|
+
* Internal storage for event listeners mapped by event name.
|
|
83
|
+
* @internal
|
|
84
|
+
*/
|
|
85
|
+
listeners = /* @__PURE__ */ new Map();
|
|
86
|
+
/**
|
|
87
|
+
* Subscribes a handler to a specific event.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam T - The type of data expected by the event handler
|
|
90
|
+
* @param event - The name of the event to subscribe to
|
|
91
|
+
* @param handler - The callback function to invoke when the event is emitted
|
|
92
|
+
* @returns A function that, when called, unsubscribes the handler from the event
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const unsubscribe = emitter.on<{ userId: string }>('login', (data) => {
|
|
97
|
+
* console.log('User logged in:', data.userId);
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @public
|
|
102
|
+
*/
|
|
103
|
+
on(e, r) {
|
|
104
|
+
return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(r), () => this.off(e, r);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Subscribes a handler to an event that will automatically unsubscribe after the first invocation.
|
|
108
|
+
*
|
|
109
|
+
* @typeParam T - The type of data expected by the event handler
|
|
110
|
+
* @param event - The name of the event to subscribe to
|
|
111
|
+
* @param handler - The callback function to invoke once when the event is emitted
|
|
112
|
+
* @returns A function that, when called, unsubscribes the handler before it fires
|
|
113
|
+
*
|
|
114
|
+
* @remarks
|
|
115
|
+
* This is useful for one-time event handling, such as waiting for an initialization
|
|
116
|
+
* event or a single response.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* emitter.once('ready', () => {
|
|
121
|
+
* console.log('Component is ready!');
|
|
122
|
+
* });
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @public
|
|
126
|
+
*/
|
|
127
|
+
once(e, r) {
|
|
128
|
+
const n = (i) => (this.off(e, n), r(i));
|
|
129
|
+
return this.on(e, n);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Emits an event, invoking all registered handlers with the provided data.
|
|
133
|
+
*
|
|
134
|
+
* @typeParam T - The type of data to pass to event handlers
|
|
135
|
+
* @param event - The name of the event to emit
|
|
136
|
+
* @param data - Optional data to pass to all registered handlers
|
|
137
|
+
*
|
|
138
|
+
* @remarks
|
|
139
|
+
* Handlers are invoked synchronously in the order they were registered.
|
|
140
|
+
* If a handler throws an error, it is caught and logged to the console,
|
|
141
|
+
* allowing subsequent handlers to still execute.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* emitter.emit('userAction', { action: 'click', target: 'button' });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
emit(e, r) {
|
|
151
|
+
const n = this.listeners.get(e);
|
|
152
|
+
if (n)
|
|
153
|
+
for (const i of n)
|
|
154
|
+
try {
|
|
155
|
+
const s = i(r);
|
|
156
|
+
s && typeof s == "object" && "catch" in s && typeof s.catch == "function" && s.catch((o) => {
|
|
157
|
+
console.error(`Error in async event handler for "${e}":`, o);
|
|
158
|
+
});
|
|
159
|
+
} catch (s) {
|
|
160
|
+
console.error(`Error in event handler for "${e}":`, s);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Unsubscribes a handler from an event, or removes all handlers for the event.
|
|
165
|
+
*
|
|
166
|
+
* @param event - The name of the event to unsubscribe from
|
|
167
|
+
* @param handler - The specific handler to remove. If not provided, all handlers for the event are removed.
|
|
168
|
+
*
|
|
169
|
+
* @remarks
|
|
170
|
+
* When a specific handler is removed and it was the last handler for that event,
|
|
171
|
+
* the event entry is cleaned up from the internal map.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // Remove a specific handler
|
|
176
|
+
* emitter.off('message', myHandler);
|
|
177
|
+
*
|
|
178
|
+
* // Remove all handlers for an event
|
|
179
|
+
* emitter.off('message');
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @public
|
|
183
|
+
*/
|
|
184
|
+
off(e, r) {
|
|
185
|
+
if (!r) {
|
|
186
|
+
this.listeners.delete(e);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const n = this.listeners.get(e);
|
|
190
|
+
n && (n.delete(r), n.size === 0 && this.listeners.delete(e));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Removes all event listeners from the emitter.
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* This method is typically called during component cleanup or disposal
|
|
197
|
+
* to ensure no memory leaks from lingering event subscriptions.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Clean up all listeners when component is destroyed
|
|
202
|
+
* emitter.removeAllListeners();
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* @public
|
|
206
|
+
*/
|
|
207
|
+
removeAllListeners() {
|
|
208
|
+
this.listeners.clear();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Returns the number of listeners registered for a specific event.
|
|
212
|
+
*
|
|
213
|
+
* @param event - The name of the event to check
|
|
214
|
+
* @returns The number of handlers currently subscribed to the event
|
|
215
|
+
*
|
|
216
|
+
* @remarks
|
|
217
|
+
* This method is primarily useful for debugging and testing purposes
|
|
218
|
+
* to verify that subscriptions are being properly managed.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* console.log(`Active listeners: ${emitter.listenerCount('message')}`);
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @public
|
|
226
|
+
*/
|
|
227
|
+
listenerCount(e) {
|
|
228
|
+
return this.listeners.get(e)?.size ?? 0;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function we() {
|
|
232
|
+
const t = Date.now().toString(36), e = Math.random().toString(36).slice(2, 11);
|
|
233
|
+
return `${t}_${e}`;
|
|
234
|
+
}
|
|
235
|
+
function v() {
|
|
236
|
+
return Math.random().toString(36).slice(2, 11);
|
|
237
|
+
}
|
|
238
|
+
class Ee {
|
|
239
|
+
/**
|
|
240
|
+
* Array of registered cleanup tasks awaiting execution.
|
|
241
|
+
* @internal
|
|
242
|
+
*/
|
|
243
|
+
tasks = [];
|
|
244
|
+
/**
|
|
245
|
+
* Flag indicating whether cleanup has already been performed.
|
|
246
|
+
* @internal
|
|
247
|
+
*/
|
|
248
|
+
cleaned = !1;
|
|
249
|
+
/**
|
|
250
|
+
* Registers a cleanup task to be executed when {@link cleanup} is called.
|
|
251
|
+
*
|
|
252
|
+
* @param task - The cleanup function to register
|
|
253
|
+
*
|
|
254
|
+
* @remarks
|
|
255
|
+
* If cleanup has already been performed, the task is executed immediately
|
|
256
|
+
* rather than being registered. This ensures late-registered tasks are
|
|
257
|
+
* still handled appropriately.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* cleanup.register(() => {
|
|
262
|
+
* eventEmitter.removeAllListeners();
|
|
263
|
+
* });
|
|
264
|
+
*
|
|
265
|
+
* cleanup.register(async () => {
|
|
266
|
+
* await database.close();
|
|
267
|
+
* });
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* @public
|
|
271
|
+
*/
|
|
272
|
+
register(e) {
|
|
273
|
+
if (this.cleaned) {
|
|
274
|
+
try {
|
|
275
|
+
e();
|
|
276
|
+
} catch (r) {
|
|
277
|
+
console.error("Error in cleanup task:", r);
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.tasks.push(e);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Executes all registered cleanup tasks in LIFO order.
|
|
285
|
+
*
|
|
286
|
+
* @returns A Promise that resolves when all cleanup tasks have completed
|
|
287
|
+
*
|
|
288
|
+
* @remarks
|
|
289
|
+
* Tasks are executed in reverse order of registration (LIFO pattern).
|
|
290
|
+
* Each task is awaited individually, and errors are caught and logged
|
|
291
|
+
* to prevent one failing task from blocking subsequent cleanup operations.
|
|
292
|
+
* Calling this method multiple times has no effect after the first call.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* // In a component's destroy lifecycle
|
|
297
|
+
* async destroy() {
|
|
298
|
+
* await this.cleanupManager.cleanup();
|
|
299
|
+
* }
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
* @public
|
|
303
|
+
*/
|
|
304
|
+
async cleanup() {
|
|
305
|
+
if (this.cleaned) return;
|
|
306
|
+
this.cleaned = !0;
|
|
307
|
+
const e = this.tasks.reverse();
|
|
308
|
+
this.tasks = [];
|
|
309
|
+
for (const r of e)
|
|
310
|
+
try {
|
|
311
|
+
await r();
|
|
312
|
+
} catch (n) {
|
|
313
|
+
console.error("Error in cleanup task:", n);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Checks whether cleanup has already been performed.
|
|
318
|
+
*
|
|
319
|
+
* @returns `true` if {@link cleanup} has been called, `false` otherwise
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* if (!cleanupManager.isCleaned()) {
|
|
324
|
+
* // Safe to register more tasks
|
|
325
|
+
* cleanupManager.register(myTask);
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
328
|
+
*
|
|
329
|
+
* @public
|
|
330
|
+
*/
|
|
331
|
+
isCleaned() {
|
|
332
|
+
return this.cleaned;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Resets the manager to its initial state, allowing it to be reused.
|
|
336
|
+
*
|
|
337
|
+
* @remarks
|
|
338
|
+
* This method clears all registered tasks and resets the cleaned flag.
|
|
339
|
+
* It is primarily intended for testing scenarios or cases where the
|
|
340
|
+
* manager needs to be reused after cleanup.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```typescript
|
|
344
|
+
* // In a test teardown
|
|
345
|
+
* afterEach(() => {
|
|
346
|
+
* cleanupManager.reset();
|
|
347
|
+
* });
|
|
348
|
+
* ```
|
|
349
|
+
*
|
|
350
|
+
* @public
|
|
351
|
+
*/
|
|
352
|
+
reset() {
|
|
353
|
+
this.tasks = [], this.cleaned = !1;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function ie() {
|
|
357
|
+
let t, e;
|
|
358
|
+
return { promise: new Promise((n, i) => {
|
|
359
|
+
t = n, e = i;
|
|
360
|
+
}), resolve: t, reject: e };
|
|
361
|
+
}
|
|
362
|
+
function Ce(t, e, r = "Operation timed out") {
|
|
363
|
+
return new Promise((n, i) => {
|
|
364
|
+
const s = setTimeout(() => {
|
|
365
|
+
i(new Error(`${r} (${e}ms)`));
|
|
366
|
+
}, e);
|
|
367
|
+
t.then((o) => {
|
|
368
|
+
clearTimeout(s), n(o);
|
|
369
|
+
}).catch((o) => {
|
|
370
|
+
clearTimeout(s), i(o);
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
const A = "forgeframe:";
|
|
375
|
+
function F(t) {
|
|
376
|
+
return A + JSON.stringify(t);
|
|
377
|
+
}
|
|
378
|
+
function Pe(t) {
|
|
379
|
+
if (typeof t != "string" || !t.startsWith(A)) return null;
|
|
380
|
+
try {
|
|
381
|
+
const e = t.slice(A.length), r = JSON.parse(e);
|
|
382
|
+
return !r.id || !r.type || !r.name || !r.source ? null : r;
|
|
383
|
+
} catch {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function X(t, e, r, n) {
|
|
388
|
+
return {
|
|
389
|
+
id: t,
|
|
390
|
+
type: T.REQUEST,
|
|
391
|
+
name: e,
|
|
392
|
+
data: r,
|
|
393
|
+
source: n
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function Re(t, e, r, n) {
|
|
397
|
+
return {
|
|
398
|
+
id: t,
|
|
399
|
+
type: T.RESPONSE,
|
|
400
|
+
name: "response",
|
|
401
|
+
data: e,
|
|
402
|
+
source: r,
|
|
403
|
+
error: n ? {
|
|
404
|
+
message: n.message,
|
|
405
|
+
stack: n.stack
|
|
406
|
+
} : void 0
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
class se {
|
|
410
|
+
/**
|
|
411
|
+
* Creates a new Messenger instance.
|
|
412
|
+
*
|
|
413
|
+
* @param uid - Unique identifier for this messenger
|
|
414
|
+
* @param win - The window to listen for messages on
|
|
415
|
+
* @param domain - The origin domain of this messenger
|
|
416
|
+
* @param trustedDomains - Optional domains to trust for incoming messages
|
|
417
|
+
*/
|
|
418
|
+
constructor(e, r = window, n = window.location.origin, i) {
|
|
419
|
+
this.uid = e, this.win = r, this.domain = n, this.allowedOrigins.add(n), i && this.addTrustedDomain(i), this.setupListener();
|
|
420
|
+
}
|
|
421
|
+
/** @internal */
|
|
422
|
+
pending = /* @__PURE__ */ new Map();
|
|
423
|
+
/** @internal */
|
|
424
|
+
handlers = /* @__PURE__ */ new Map();
|
|
425
|
+
/** @internal */
|
|
426
|
+
listener = null;
|
|
427
|
+
/** @internal */
|
|
428
|
+
destroyed = !1;
|
|
429
|
+
/** @internal */
|
|
430
|
+
allowedOrigins = /* @__PURE__ */ new Set();
|
|
431
|
+
/** @internal */
|
|
432
|
+
allowedOriginPatterns = [];
|
|
433
|
+
/**
|
|
434
|
+
* Adds a trusted domain that can send messages to this messenger.
|
|
435
|
+
*
|
|
436
|
+
* @param domain - Domain pattern to trust (string, RegExp, or array)
|
|
437
|
+
*/
|
|
438
|
+
addTrustedDomain(e) {
|
|
439
|
+
if (Array.isArray(e))
|
|
440
|
+
for (const r of e)
|
|
441
|
+
this.allowedOrigins.add(r);
|
|
442
|
+
else e instanceof RegExp ? this.allowedOriginPatterns.push(e) : this.allowedOrigins.add(e);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Checks if an origin is trusted.
|
|
446
|
+
*
|
|
447
|
+
* @param origin - The origin to check
|
|
448
|
+
* @returns True if the origin is trusted
|
|
449
|
+
* @internal
|
|
450
|
+
*/
|
|
451
|
+
isOriginTrusted(e) {
|
|
452
|
+
if (this.allowedOrigins.has(e))
|
|
453
|
+
return !0;
|
|
454
|
+
for (const r of this.allowedOriginPatterns)
|
|
455
|
+
if (r.test(e))
|
|
456
|
+
return !0;
|
|
457
|
+
return !1;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Sends a message and waits for a response.
|
|
461
|
+
*
|
|
462
|
+
* @typeParam T - The data type being sent
|
|
463
|
+
* @typeParam R - The expected response type
|
|
464
|
+
* @param targetWin - The target window to send to
|
|
465
|
+
* @param targetDomain - The target origin domain
|
|
466
|
+
* @param name - The message name/type
|
|
467
|
+
* @param data - Optional data payload
|
|
468
|
+
* @param timeout - Timeout in milliseconds (default: 10000)
|
|
469
|
+
* @returns Promise resolving to the response data
|
|
470
|
+
* @throws Error if messenger is destroyed or timeout occurs
|
|
471
|
+
*/
|
|
472
|
+
async send(e, r, n, i, s = 1e4) {
|
|
473
|
+
if (this.destroyed)
|
|
474
|
+
throw new Error("Messenger has been destroyed");
|
|
475
|
+
const o = v(), a = X(o, n, i, {
|
|
476
|
+
uid: this.uid,
|
|
477
|
+
domain: this.domain
|
|
478
|
+
}), c = ie(), d = setTimeout(() => {
|
|
479
|
+
this.pending.delete(o), c.reject(new Error(`Message "${n}" timed out after ${s}ms`));
|
|
480
|
+
}, s);
|
|
481
|
+
this.pending.set(o, {
|
|
482
|
+
deferred: c,
|
|
483
|
+
timeout: d
|
|
484
|
+
});
|
|
485
|
+
try {
|
|
486
|
+
e.postMessage(F(a), r);
|
|
487
|
+
} catch (u) {
|
|
488
|
+
throw this.pending.delete(o), clearTimeout(d), u;
|
|
489
|
+
}
|
|
490
|
+
return c.promise;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Sends a one-way message without waiting for a response.
|
|
494
|
+
*
|
|
495
|
+
* @typeParam T - The data type being sent
|
|
496
|
+
* @param targetWin - The target window to send to
|
|
497
|
+
* @param targetDomain - The target origin domain
|
|
498
|
+
* @param name - The message name/type
|
|
499
|
+
* @param data - Optional data payload
|
|
500
|
+
* @throws Error if messenger is destroyed
|
|
501
|
+
*/
|
|
502
|
+
post(e, r, n, i) {
|
|
503
|
+
if (this.destroyed)
|
|
504
|
+
throw new Error("Messenger has been destroyed");
|
|
505
|
+
const s = v(), o = X(s, n, i, {
|
|
506
|
+
uid: this.uid,
|
|
507
|
+
domain: this.domain
|
|
508
|
+
});
|
|
509
|
+
e.postMessage(F(o), r);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Registers a handler for incoming messages of a specific type.
|
|
513
|
+
*
|
|
514
|
+
* @typeParam T - The expected data type of incoming messages
|
|
515
|
+
* @typeParam R - The return type of the handler
|
|
516
|
+
* @param name - The message name/type to handle
|
|
517
|
+
* @param handler - The handler function
|
|
518
|
+
* @returns Function to unregister the handler
|
|
519
|
+
*/
|
|
520
|
+
on(e, r) {
|
|
521
|
+
return this.handlers.set(e, r), () => this.handlers.delete(e);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Sets up the postMessage event listener.
|
|
525
|
+
* @internal
|
|
526
|
+
*/
|
|
527
|
+
setupListener() {
|
|
528
|
+
this.listener = (e) => {
|
|
529
|
+
if (e.source === this.win || !this.isOriginTrusted(e.origin))
|
|
530
|
+
return;
|
|
531
|
+
const r = Pe(e.data);
|
|
532
|
+
r && this.handleMessage(r, e.source, e.origin);
|
|
533
|
+
}, this.win.addEventListener("message", this.listener);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Processes a received message.
|
|
537
|
+
* @internal
|
|
538
|
+
*/
|
|
539
|
+
async handleMessage(e, r, n) {
|
|
540
|
+
if (e.type === T.RESPONSE) {
|
|
541
|
+
const i = this.pending.get(e.id);
|
|
542
|
+
if (i)
|
|
543
|
+
if (this.pending.delete(e.id), clearTimeout(i.timeout), e.error) {
|
|
544
|
+
const s = new Error(e.error.message);
|
|
545
|
+
s.stack = e.error.stack, i.deferred.reject(s);
|
|
546
|
+
} else
|
|
547
|
+
i.deferred.resolve(e.data);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
if (e.type === T.REQUEST) {
|
|
551
|
+
const i = this.handlers.get(e.name);
|
|
552
|
+
if (!i)
|
|
553
|
+
return;
|
|
554
|
+
let s, o;
|
|
555
|
+
try {
|
|
556
|
+
s = await i(e.data, e.source);
|
|
557
|
+
} catch (c) {
|
|
558
|
+
o = c instanceof Error ? c : new Error(String(c));
|
|
559
|
+
}
|
|
560
|
+
const a = Re(
|
|
561
|
+
e.id,
|
|
562
|
+
s,
|
|
563
|
+
{ uid: this.uid, domain: this.domain },
|
|
564
|
+
o
|
|
565
|
+
);
|
|
566
|
+
try {
|
|
567
|
+
r.postMessage(F(a), n);
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Cleans up the messenger and releases resources.
|
|
574
|
+
*
|
|
575
|
+
* @remarks
|
|
576
|
+
* Removes the message listener, rejects all pending requests,
|
|
577
|
+
* and clears all handlers.
|
|
578
|
+
*/
|
|
579
|
+
destroy() {
|
|
580
|
+
if (!this.destroyed) {
|
|
581
|
+
this.destroyed = !0, this.listener && (this.win.removeEventListener("message", this.listener), this.listener = null);
|
|
582
|
+
for (const e of this.pending.values())
|
|
583
|
+
clearTimeout(e.timeout), e.deferred.reject(new Error("Messenger destroyed"));
|
|
584
|
+
this.pending.clear(), this.handlers.clear();
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Checks if the messenger has been destroyed.
|
|
589
|
+
*
|
|
590
|
+
* @returns True if destroy() has been called
|
|
591
|
+
*/
|
|
592
|
+
isDestroyed() {
|
|
593
|
+
return this.destroyed;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
const J = 500;
|
|
597
|
+
class $ {
|
|
598
|
+
/**
|
|
599
|
+
* Creates a new FunctionBridge instance.
|
|
600
|
+
*
|
|
601
|
+
* @param messenger - The messenger to use for cross-domain calls
|
|
602
|
+
*/
|
|
603
|
+
constructor(e) {
|
|
604
|
+
this.messenger = e, this.setupCallHandler();
|
|
605
|
+
}
|
|
606
|
+
/** @internal */
|
|
607
|
+
localFunctions = /* @__PURE__ */ new Map();
|
|
608
|
+
/** @internal */
|
|
609
|
+
remoteFunctions = /* @__PURE__ */ new Map();
|
|
610
|
+
/**
|
|
611
|
+
* Tracks function IDs from the current serialization batch.
|
|
612
|
+
* Used for cleanup of stale references when props are updated.
|
|
613
|
+
* @internal
|
|
614
|
+
*/
|
|
615
|
+
currentBatchIds = /* @__PURE__ */ new Set();
|
|
616
|
+
/**
|
|
617
|
+
* Serializes a local function to a transferable reference.
|
|
618
|
+
*
|
|
619
|
+
* @param fn - The function to serialize
|
|
620
|
+
* @param name - Optional name for debugging
|
|
621
|
+
* @returns A function reference that can be sent across domains
|
|
622
|
+
*/
|
|
623
|
+
serialize(e, r) {
|
|
624
|
+
if (this.localFunctions.size >= J) {
|
|
625
|
+
const i = this.localFunctions.keys().next().value;
|
|
626
|
+
i && this.localFunctions.delete(i);
|
|
627
|
+
}
|
|
628
|
+
const n = v();
|
|
629
|
+
return this.localFunctions.set(n, e), this.currentBatchIds.add(n), {
|
|
630
|
+
__type__: "function",
|
|
631
|
+
__id__: n,
|
|
632
|
+
__name__: r || e.name || "anonymous"
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Deserializes a function reference to a callable wrapper.
|
|
637
|
+
*
|
|
638
|
+
* @remarks
|
|
639
|
+
* The returned function, when called, will invoke the original function
|
|
640
|
+
* in the remote window via postMessage and return the result.
|
|
641
|
+
*
|
|
642
|
+
* @param ref - The function reference to deserialize
|
|
643
|
+
* @param targetWin - The window containing the original function
|
|
644
|
+
* @param targetDomain - The origin of the target window
|
|
645
|
+
* @returns A callable wrapper function
|
|
646
|
+
*/
|
|
647
|
+
deserialize(e, r, n) {
|
|
648
|
+
const i = `${e.__id__}`, s = this.remoteFunctions.get(i);
|
|
649
|
+
if (s) return s;
|
|
650
|
+
if (this.remoteFunctions.size >= J) {
|
|
651
|
+
const a = this.remoteFunctions.keys().next().value;
|
|
652
|
+
a && this.remoteFunctions.delete(a);
|
|
653
|
+
}
|
|
654
|
+
const o = async (...a) => this.messenger.send(r, n, l.CALL, {
|
|
655
|
+
id: e.__id__,
|
|
656
|
+
args: a
|
|
657
|
+
});
|
|
658
|
+
return Object.defineProperty(o, "name", {
|
|
659
|
+
value: e.__name__,
|
|
660
|
+
configurable: !0
|
|
661
|
+
}), this.remoteFunctions.set(i, o), o;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Type guard to check if a value is a function reference.
|
|
665
|
+
*
|
|
666
|
+
* @param value - The value to check
|
|
667
|
+
* @returns True if the value is a FunctionRef
|
|
668
|
+
*/
|
|
669
|
+
static isFunctionRef(e) {
|
|
670
|
+
return typeof e == "object" && e !== null && e.__type__ === "function" && typeof e.__id__ == "string";
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Sets up the handler for incoming function call messages.
|
|
674
|
+
* @internal
|
|
675
|
+
*/
|
|
676
|
+
setupCallHandler() {
|
|
677
|
+
this.messenger.on(
|
|
678
|
+
l.CALL,
|
|
679
|
+
async ({ id: e, args: r }) => {
|
|
680
|
+
const n = this.localFunctions.get(e);
|
|
681
|
+
if (!n)
|
|
682
|
+
throw new Error(`Function with id "${e}" not found`);
|
|
683
|
+
return n(...r);
|
|
684
|
+
}
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Removes a local function reference.
|
|
689
|
+
*
|
|
690
|
+
* @param id - The function reference ID to remove
|
|
691
|
+
*/
|
|
692
|
+
removeLocal(e) {
|
|
693
|
+
this.localFunctions.delete(e);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Starts a new serialization batch.
|
|
697
|
+
*
|
|
698
|
+
* @remarks
|
|
699
|
+
* Call this before serializing a new set of props. After serialization,
|
|
700
|
+
* call {@link finishBatch} to clean up functions from previous batches.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* ```typescript
|
|
704
|
+
* bridge.startBatch();
|
|
705
|
+
* const serialized = serializeFunctions(props, bridge);
|
|
706
|
+
* bridge.finishBatch();
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
startBatch() {
|
|
710
|
+
this.currentBatchIds.clear();
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Finishes the current batch and removes functions not in this batch.
|
|
714
|
+
*
|
|
715
|
+
* @remarks
|
|
716
|
+
* This cleans up function references from previous prop updates that
|
|
717
|
+
* are no longer needed, preventing memory leaks.
|
|
718
|
+
*
|
|
719
|
+
* @param keepPrevious - If true, keeps previous batch functions (default: false)
|
|
720
|
+
*/
|
|
721
|
+
finishBatch(e = !1) {
|
|
722
|
+
if (e) {
|
|
723
|
+
this.currentBatchIds.clear();
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
for (const r of this.localFunctions.keys())
|
|
727
|
+
this.currentBatchIds.has(r) || this.localFunctions.delete(r);
|
|
728
|
+
this.currentBatchIds.clear();
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Clears all remote function references.
|
|
732
|
+
*
|
|
733
|
+
* @remarks
|
|
734
|
+
* Call this when the remote window is no longer accessible
|
|
735
|
+
* (e.g., closed or navigated away).
|
|
736
|
+
*/
|
|
737
|
+
clearRemote() {
|
|
738
|
+
this.remoteFunctions.clear();
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Returns the current number of registered local functions.
|
|
742
|
+
* Useful for debugging and monitoring.
|
|
743
|
+
*/
|
|
744
|
+
get localFunctionCount() {
|
|
745
|
+
return this.localFunctions.size;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Returns the current number of cached remote functions.
|
|
749
|
+
* Useful for debugging and monitoring.
|
|
750
|
+
*/
|
|
751
|
+
get remoteFunctionCount() {
|
|
752
|
+
return this.remoteFunctions.size;
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Cleans up all function references.
|
|
756
|
+
*/
|
|
757
|
+
destroy() {
|
|
758
|
+
this.localFunctions.clear(), this.remoteFunctions.clear(), this.currentBatchIds.clear();
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
function k(t, e, r = /* @__PURE__ */ new WeakSet()) {
|
|
762
|
+
if (typeof t == "function")
|
|
763
|
+
return e.serialize(t);
|
|
764
|
+
if (Array.isArray(t)) {
|
|
765
|
+
if (r.has(t))
|
|
766
|
+
throw new Error("Circular reference detected in props - arrays cannot contain circular references");
|
|
767
|
+
return r.add(t), t.map((n) => k(n, e, r));
|
|
768
|
+
}
|
|
769
|
+
if (typeof t == "object" && t !== null) {
|
|
770
|
+
if (r.has(t))
|
|
771
|
+
throw new Error("Circular reference detected in props - objects cannot contain circular references");
|
|
772
|
+
r.add(t);
|
|
773
|
+
const n = {};
|
|
774
|
+
for (const [i, s] of Object.entries(t))
|
|
775
|
+
n[i] = k(s, e, r);
|
|
776
|
+
return n;
|
|
777
|
+
}
|
|
778
|
+
return t;
|
|
779
|
+
}
|
|
780
|
+
function z(t, e, r, n, i = /* @__PURE__ */ new WeakSet()) {
|
|
781
|
+
if ($.isFunctionRef(t))
|
|
782
|
+
return e.deserialize(t, r, n);
|
|
783
|
+
if (Array.isArray(t)) {
|
|
784
|
+
if (i.has(t))
|
|
785
|
+
throw new Error("Circular reference detected in serialized props");
|
|
786
|
+
return i.add(t), t.map(
|
|
787
|
+
(s) => z(s, e, r, n, i)
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
if (typeof t == "object" && t !== null) {
|
|
791
|
+
if (i.has(t))
|
|
792
|
+
throw new Error("Circular reference detected in serialized props");
|
|
793
|
+
i.add(t);
|
|
794
|
+
const s = {};
|
|
795
|
+
for (const [o, a] of Object.entries(t))
|
|
796
|
+
s[o] = z(a, e, r, n, i);
|
|
797
|
+
return s;
|
|
798
|
+
}
|
|
799
|
+
return t;
|
|
800
|
+
}
|
|
801
|
+
function W(t = window) {
|
|
802
|
+
try {
|
|
803
|
+
return t.location.origin;
|
|
804
|
+
} catch {
|
|
805
|
+
return "";
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function oe(t, e = window) {
|
|
809
|
+
try {
|
|
810
|
+
return t.location.origin === e.location.origin;
|
|
811
|
+
} catch {
|
|
812
|
+
return !1;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
function ae(t, e) {
|
|
816
|
+
return typeof t == "string" ? t === "*" ? !0 : t === e : t instanceof RegExp ? t.test(e) : Array.isArray(t) ? t.some((r) => ae(r, e)) : !1;
|
|
817
|
+
}
|
|
818
|
+
function ce(t) {
|
|
819
|
+
if (!t) return !0;
|
|
820
|
+
try {
|
|
821
|
+
return t.closed;
|
|
822
|
+
} catch {
|
|
823
|
+
return !0;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
function Oe(t = window) {
|
|
827
|
+
try {
|
|
828
|
+
return t.opener;
|
|
829
|
+
} catch {
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
function be(t = window) {
|
|
834
|
+
try {
|
|
835
|
+
const e = t.parent;
|
|
836
|
+
return e && e !== t ? e : null;
|
|
837
|
+
} catch {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function _e(t = window) {
|
|
842
|
+
try {
|
|
843
|
+
return t.parent !== t;
|
|
844
|
+
} catch {
|
|
845
|
+
return !0;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function Ie(t = window) {
|
|
849
|
+
try {
|
|
850
|
+
return t.opener !== null && t.opener !== void 0;
|
|
851
|
+
} catch {
|
|
852
|
+
return !1;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const G = 32 * 1024;
|
|
856
|
+
function Te(t) {
|
|
857
|
+
const e = Ne(t);
|
|
858
|
+
return `${N}${e}`;
|
|
859
|
+
}
|
|
860
|
+
function le(t) {
|
|
861
|
+
if (!t || !t.startsWith(N))
|
|
862
|
+
return null;
|
|
863
|
+
const e = t.slice(N.length);
|
|
864
|
+
return Se(e);
|
|
865
|
+
}
|
|
866
|
+
function de(t = window) {
|
|
867
|
+
try {
|
|
868
|
+
return t.name.startsWith(N);
|
|
869
|
+
} catch {
|
|
870
|
+
return !1;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function Y(t, e = window) {
|
|
874
|
+
return le(e.name)?.tag === t;
|
|
875
|
+
}
|
|
876
|
+
function Ne(t) {
|
|
877
|
+
try {
|
|
878
|
+
const e = JSON.stringify(t), r = btoa(encodeURIComponent(e)), n = new Blob([r]).size;
|
|
879
|
+
if (n > G)
|
|
880
|
+
throw new Error(
|
|
881
|
+
`Payload size (${Math.round(n / 1024)}KB) exceeds maximum allowed size (${G / 1024}KB). Consider reducing the amount of data passed via props.`
|
|
882
|
+
);
|
|
883
|
+
return r;
|
|
884
|
+
} catch (e) {
|
|
885
|
+
throw e instanceof Error && e.message.includes("Payload size") ? e : new Error(`Failed to encode payload: ${e}`);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function Se(t) {
|
|
889
|
+
try {
|
|
890
|
+
const e = decodeURIComponent(atob(t));
|
|
891
|
+
return JSON.parse(e);
|
|
892
|
+
} catch {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function xe(t) {
|
|
897
|
+
return {
|
|
898
|
+
uid: t.uid,
|
|
899
|
+
tag: t.tag,
|
|
900
|
+
version: re,
|
|
901
|
+
context: t.context,
|
|
902
|
+
parentDomain: t.parentDomain,
|
|
903
|
+
props: t.props,
|
|
904
|
+
exports: t.exports,
|
|
905
|
+
children: t.children
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function De(t = window) {
|
|
909
|
+
return le(t.name);
|
|
910
|
+
}
|
|
911
|
+
const V = 100, y = /* @__PURE__ */ new Map();
|
|
912
|
+
function Fe() {
|
|
913
|
+
const t = [];
|
|
914
|
+
for (const [e, r] of y.entries())
|
|
915
|
+
ce(r) && t.push(e);
|
|
916
|
+
for (const e of t)
|
|
917
|
+
y.delete(e);
|
|
918
|
+
}
|
|
919
|
+
function ve(t, e) {
|
|
920
|
+
if (y.size >= V && Fe(), y.size >= V) {
|
|
921
|
+
const r = y.keys().next().value;
|
|
922
|
+
r && y.delete(r);
|
|
923
|
+
}
|
|
924
|
+
y.set(t, e);
|
|
925
|
+
}
|
|
926
|
+
function Ae(t) {
|
|
927
|
+
y.delete(t);
|
|
928
|
+
}
|
|
929
|
+
const E = {
|
|
930
|
+
uid: {
|
|
931
|
+
type: h.STRING,
|
|
932
|
+
required: !1,
|
|
933
|
+
sendToChild: !0
|
|
934
|
+
},
|
|
935
|
+
tag: {
|
|
936
|
+
type: h.STRING,
|
|
937
|
+
required: !1,
|
|
938
|
+
sendToChild: !0
|
|
939
|
+
},
|
|
940
|
+
dimensions: {
|
|
941
|
+
type: h.OBJECT,
|
|
942
|
+
required: !1,
|
|
943
|
+
sendToChild: !1,
|
|
944
|
+
default: () => ({ width: "100%", height: "100%" })
|
|
945
|
+
},
|
|
946
|
+
timeout: {
|
|
947
|
+
type: h.NUMBER,
|
|
948
|
+
required: !1,
|
|
949
|
+
sendToChild: !1,
|
|
950
|
+
default: () => 1e4
|
|
951
|
+
},
|
|
952
|
+
cspNonce: {
|
|
953
|
+
type: h.STRING,
|
|
954
|
+
required: !1,
|
|
955
|
+
sendToChild: !0
|
|
956
|
+
},
|
|
957
|
+
// Lifecycle callbacks - functions sent to child
|
|
958
|
+
onDisplay: {
|
|
959
|
+
type: h.FUNCTION,
|
|
960
|
+
required: !1,
|
|
961
|
+
sendToChild: !1
|
|
962
|
+
},
|
|
963
|
+
onRendered: {
|
|
964
|
+
type: h.FUNCTION,
|
|
965
|
+
required: !1,
|
|
966
|
+
sendToChild: !1
|
|
967
|
+
},
|
|
968
|
+
onRender: {
|
|
969
|
+
type: h.FUNCTION,
|
|
970
|
+
required: !1,
|
|
971
|
+
sendToChild: !1
|
|
972
|
+
},
|
|
973
|
+
onPrerendered: {
|
|
974
|
+
type: h.FUNCTION,
|
|
975
|
+
required: !1,
|
|
976
|
+
sendToChild: !1
|
|
977
|
+
},
|
|
978
|
+
onPrerender: {
|
|
979
|
+
type: h.FUNCTION,
|
|
980
|
+
required: !1,
|
|
981
|
+
sendToChild: !1
|
|
982
|
+
},
|
|
983
|
+
onClose: {
|
|
984
|
+
type: h.FUNCTION,
|
|
985
|
+
required: !1,
|
|
986
|
+
sendToChild: !1
|
|
987
|
+
},
|
|
988
|
+
onDestroy: {
|
|
989
|
+
type: h.FUNCTION,
|
|
990
|
+
required: !1,
|
|
991
|
+
sendToChild: !1
|
|
992
|
+
},
|
|
993
|
+
onResize: {
|
|
994
|
+
type: h.FUNCTION,
|
|
995
|
+
required: !1,
|
|
996
|
+
sendToChild: !1
|
|
997
|
+
},
|
|
998
|
+
onFocus: {
|
|
999
|
+
type: h.FUNCTION,
|
|
1000
|
+
required: !1,
|
|
1001
|
+
sendToChild: !1
|
|
1002
|
+
},
|
|
1003
|
+
onError: {
|
|
1004
|
+
type: h.FUNCTION,
|
|
1005
|
+
required: !1,
|
|
1006
|
+
sendToChild: !1
|
|
1007
|
+
},
|
|
1008
|
+
onProps: {
|
|
1009
|
+
type: h.FUNCTION,
|
|
1010
|
+
required: !1,
|
|
1011
|
+
sendToChild: !1
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
function Z(t, e, r) {
|
|
1015
|
+
const n = {
|
|
1016
|
+
...E,
|
|
1017
|
+
...e
|
|
1018
|
+
}, i = {};
|
|
1019
|
+
for (const [s, o] of Object.entries(n)) {
|
|
1020
|
+
const a = o;
|
|
1021
|
+
let c;
|
|
1022
|
+
const d = a.alias, u = s in t, g = d && d in t;
|
|
1023
|
+
u ? c = t[s] : g ? c = t[d] : a.value ? c = a.value(r) : a.default !== void 0 && (c = typeof a.default == "function" ? a.default(r) : a.default), c !== void 0 && a.decorate && (c = a.decorate({ value: c, props: i })), i[s] = c;
|
|
1024
|
+
}
|
|
1025
|
+
return i;
|
|
1026
|
+
}
|
|
1027
|
+
function ke(t, e) {
|
|
1028
|
+
const r = {
|
|
1029
|
+
...E,
|
|
1030
|
+
...e
|
|
1031
|
+
};
|
|
1032
|
+
for (const [n, i] of Object.entries(r)) {
|
|
1033
|
+
const s = i, o = t[n];
|
|
1034
|
+
if (s.required && o === void 0)
|
|
1035
|
+
throw new Error(`Prop "${n}" is required but was not provided`);
|
|
1036
|
+
if (o !== void 0) {
|
|
1037
|
+
if (!ze(o, s.type))
|
|
1038
|
+
throw new Error(
|
|
1039
|
+
`Prop "${n}" expected type "${s.type}" but got "${typeof o}"`
|
|
1040
|
+
);
|
|
1041
|
+
s.validate && s.validate({ value: o, props: t });
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function ze(t, e) {
|
|
1046
|
+
switch (e) {
|
|
1047
|
+
case h.STRING:
|
|
1048
|
+
return typeof t == "string";
|
|
1049
|
+
case h.NUMBER:
|
|
1050
|
+
return typeof t == "number";
|
|
1051
|
+
case h.BOOLEAN:
|
|
1052
|
+
return typeof t == "boolean";
|
|
1053
|
+
case h.FUNCTION:
|
|
1054
|
+
return typeof t == "function";
|
|
1055
|
+
case h.ARRAY:
|
|
1056
|
+
return Array.isArray(t);
|
|
1057
|
+
case h.OBJECT:
|
|
1058
|
+
return typeof t == "object" && t !== null && !Array.isArray(t);
|
|
1059
|
+
default:
|
|
1060
|
+
return !0;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
function K(t, e, r, n) {
|
|
1064
|
+
const i = {
|
|
1065
|
+
...E,
|
|
1066
|
+
...e
|
|
1067
|
+
}, s = {};
|
|
1068
|
+
for (const [o, a] of Object.entries(i)) {
|
|
1069
|
+
const c = a, d = t[o];
|
|
1070
|
+
if (c.sendToChild === !1 || c.sameDomain && !n) continue;
|
|
1071
|
+
if (c.trustedDomains) {
|
|
1072
|
+
const g = c.trustedDomains;
|
|
1073
|
+
if (!ae(g, r)) continue;
|
|
1074
|
+
}
|
|
1075
|
+
let u = d;
|
|
1076
|
+
c.childDecorate && d !== void 0 && (u = c.childDecorate({ value: d, props: t })), s[o] = u;
|
|
1077
|
+
}
|
|
1078
|
+
return s;
|
|
1079
|
+
}
|
|
1080
|
+
function We(t, e) {
|
|
1081
|
+
const r = new URLSearchParams(), n = {
|
|
1082
|
+
...E,
|
|
1083
|
+
...e
|
|
1084
|
+
};
|
|
1085
|
+
for (const [i, s] of Object.entries(n)) {
|
|
1086
|
+
const o = s, a = t[i];
|
|
1087
|
+
if (a === void 0 || o.type === h.FUNCTION || !o.queryParam) continue;
|
|
1088
|
+
const c = typeof o.queryParam == "string" ? o.queryParam : i;
|
|
1089
|
+
let d;
|
|
1090
|
+
typeof o.queryParam == "function" ? d = o.queryParam({ value: a }) : typeof a == "object" ? d = JSON.stringify(a) : d = String(a), r.set(c, d);
|
|
1091
|
+
}
|
|
1092
|
+
return r;
|
|
1093
|
+
}
|
|
1094
|
+
function he(t, e = "") {
|
|
1095
|
+
const r = [];
|
|
1096
|
+
for (const [n, i] of Object.entries(t)) {
|
|
1097
|
+
const s = e ? `${e}.${n}` : n;
|
|
1098
|
+
if (i !== null && typeof i == "object" && !Array.isArray(i))
|
|
1099
|
+
r.push(he(i, s));
|
|
1100
|
+
else {
|
|
1101
|
+
const o = encodeURIComponent(JSON.stringify(i));
|
|
1102
|
+
r.push(`${s}=${o}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return r.filter(Boolean).join("&");
|
|
1106
|
+
}
|
|
1107
|
+
function $e(t) {
|
|
1108
|
+
const e = {};
|
|
1109
|
+
if (!t) return e;
|
|
1110
|
+
const r = t.split("&");
|
|
1111
|
+
for (const n of r) {
|
|
1112
|
+
const [i, s] = n.split("=");
|
|
1113
|
+
if (!i || s === void 0) continue;
|
|
1114
|
+
let o;
|
|
1115
|
+
try {
|
|
1116
|
+
o = JSON.parse(decodeURIComponent(s));
|
|
1117
|
+
} catch {
|
|
1118
|
+
o = decodeURIComponent(s);
|
|
1119
|
+
}
|
|
1120
|
+
const a = i.split(".");
|
|
1121
|
+
let c = e;
|
|
1122
|
+
for (let d = 0; d < a.length - 1; d++) {
|
|
1123
|
+
const u = a[d];
|
|
1124
|
+
(!(u in c) || typeof c[u] != "object") && (c[u] = {}), c = c[u];
|
|
1125
|
+
}
|
|
1126
|
+
c[a[a.length - 1]] = o;
|
|
1127
|
+
}
|
|
1128
|
+
return e;
|
|
1129
|
+
}
|
|
1130
|
+
function Me(t) {
|
|
1131
|
+
return typeof t == "object" && t !== null && t.__type__ === "dotify" && typeof t.__value__ == "string";
|
|
1132
|
+
}
|
|
1133
|
+
function Q(t, e, r) {
|
|
1134
|
+
const n = {
|
|
1135
|
+
...E,
|
|
1136
|
+
...e
|
|
1137
|
+
}, i = {};
|
|
1138
|
+
for (const [s, o] of Object.entries(t)) {
|
|
1139
|
+
if (o === void 0) continue;
|
|
1140
|
+
const a = n[s];
|
|
1141
|
+
i[s] = Ue(o, a, r);
|
|
1142
|
+
}
|
|
1143
|
+
return i;
|
|
1144
|
+
}
|
|
1145
|
+
function Ue(t, e, r) {
|
|
1146
|
+
if (typeof t == "function")
|
|
1147
|
+
return r.serialize(t);
|
|
1148
|
+
const n = e?.serialization ?? I.JSON;
|
|
1149
|
+
if (n === I.BASE64 && typeof t == "object") {
|
|
1150
|
+
const i = JSON.stringify(t);
|
|
1151
|
+
return {
|
|
1152
|
+
__type__: "base64",
|
|
1153
|
+
__value__: btoa(encodeURIComponent(i))
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
return n === I.DOTIFY && typeof t == "object" && t !== null && !Array.isArray(t) ? {
|
|
1157
|
+
__type__: "dotify",
|
|
1158
|
+
__value__: he(t)
|
|
1159
|
+
} : k(t, r);
|
|
1160
|
+
}
|
|
1161
|
+
function ee(t, e, r, n, i, s) {
|
|
1162
|
+
const o = {
|
|
1163
|
+
...E,
|
|
1164
|
+
...e
|
|
1165
|
+
}, a = {};
|
|
1166
|
+
for (const [c, d] of Object.entries(t)) {
|
|
1167
|
+
const u = o[c];
|
|
1168
|
+
a[c] = Le(
|
|
1169
|
+
d,
|
|
1170
|
+
u,
|
|
1171
|
+
r,
|
|
1172
|
+
n,
|
|
1173
|
+
i,
|
|
1174
|
+
s
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
return a;
|
|
1178
|
+
}
|
|
1179
|
+
function Le(t, e, r, n, i, s) {
|
|
1180
|
+
if (qe(t))
|
|
1181
|
+
try {
|
|
1182
|
+
const o = decodeURIComponent(atob(t.__value__));
|
|
1183
|
+
return JSON.parse(o);
|
|
1184
|
+
} catch {
|
|
1185
|
+
return t;
|
|
1186
|
+
}
|
|
1187
|
+
if (Me(t))
|
|
1188
|
+
try {
|
|
1189
|
+
return $e(t.__value__);
|
|
1190
|
+
} catch {
|
|
1191
|
+
return t;
|
|
1192
|
+
}
|
|
1193
|
+
return z(t, n, i, s);
|
|
1194
|
+
}
|
|
1195
|
+
function qe(t) {
|
|
1196
|
+
return typeof t == "object" && t !== null && t.__type__ === "base64" && typeof t.__value__ == "string";
|
|
1197
|
+
}
|
|
1198
|
+
function w(t, e = "100%") {
|
|
1199
|
+
return t === void 0 ? e : typeof t == "number" ? `${t}px` : t;
|
|
1200
|
+
}
|
|
1201
|
+
function S(t, e) {
|
|
1202
|
+
if (t === void 0) return e;
|
|
1203
|
+
if (typeof t == "number") return t;
|
|
1204
|
+
const r = parseInt(t, 10);
|
|
1205
|
+
return isNaN(r) ? e : r;
|
|
1206
|
+
}
|
|
1207
|
+
function Be(t) {
|
|
1208
|
+
try {
|
|
1209
|
+
t.src = "about:blank", t.parentNode?.removeChild(t);
|
|
1210
|
+
} catch {
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function je(t, e) {
|
|
1214
|
+
Je(t, e);
|
|
1215
|
+
}
|
|
1216
|
+
function He(t) {
|
|
1217
|
+
t.style.display = "", t.style.visibility = "visible";
|
|
1218
|
+
}
|
|
1219
|
+
function te(t) {
|
|
1220
|
+
t.style.display = "none", t.style.visibility = "hidden";
|
|
1221
|
+
}
|
|
1222
|
+
function Xe(t) {
|
|
1223
|
+
try {
|
|
1224
|
+
t.focus(), t.contentWindow?.focus();
|
|
1225
|
+
} catch {
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function Je(t, e) {
|
|
1229
|
+
e.width !== void 0 && (t.style.width = w(e.width)), e.height !== void 0 && (t.style.height = w(e.height));
|
|
1230
|
+
}
|
|
1231
|
+
class ue extends Error {
|
|
1232
|
+
constructor(e = "Popup blocked by browser") {
|
|
1233
|
+
super(e), this.name = "PopupOpenError";
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
function Ge(t) {
|
|
1237
|
+
const { url: e, name: r, dimensions: n } = t, i = S(n.width, 500), s = S(n.height, 500), o = Math.floor(window.screenX + (window.outerWidth - i) / 2), a = Math.floor(window.screenY + (window.outerHeight - s) / 2), c = [
|
|
1238
|
+
`width=${i}`,
|
|
1239
|
+
`height=${s}`,
|
|
1240
|
+
`left=${o}`,
|
|
1241
|
+
`top=${a}`,
|
|
1242
|
+
"menubar=no",
|
|
1243
|
+
"toolbar=no",
|
|
1244
|
+
"location=yes",
|
|
1245
|
+
// Required for security
|
|
1246
|
+
"status=no",
|
|
1247
|
+
"resizable=yes",
|
|
1248
|
+
"scrollbars=yes"
|
|
1249
|
+
].join(","), d = window.open(e, r, c);
|
|
1250
|
+
if (!d || Ze(d))
|
|
1251
|
+
throw new ue();
|
|
1252
|
+
return d;
|
|
1253
|
+
}
|
|
1254
|
+
function Ye(t) {
|
|
1255
|
+
try {
|
|
1256
|
+
t.closed || t.close();
|
|
1257
|
+
} catch {
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function Ve(t) {
|
|
1261
|
+
try {
|
|
1262
|
+
t.closed || t.focus();
|
|
1263
|
+
} catch {
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
function Ze(t) {
|
|
1267
|
+
if (!t) return !0;
|
|
1268
|
+
try {
|
|
1269
|
+
return !!(t.closed || t.innerHeight === 0 || t.innerWidth === 0);
|
|
1270
|
+
} catch {
|
|
1271
|
+
return !0;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
function Ke(t, e, r = {}) {
|
|
1275
|
+
const {
|
|
1276
|
+
initialInterval: n = 100,
|
|
1277
|
+
// Start fast to catch quick closes
|
|
1278
|
+
maxInterval: i = 2e3,
|
|
1279
|
+
// Cap at 2 seconds
|
|
1280
|
+
multiplier: s = 1.5
|
|
1281
|
+
// Exponential backoff multiplier
|
|
1282
|
+
} = r;
|
|
1283
|
+
let o = n, a, c = !1;
|
|
1284
|
+
const d = () => {
|
|
1285
|
+
try {
|
|
1286
|
+
e();
|
|
1287
|
+
} catch (g) {
|
|
1288
|
+
console.error("Error in popup close callback:", g);
|
|
1289
|
+
}
|
|
1290
|
+
}, u = () => {
|
|
1291
|
+
if (!c) {
|
|
1292
|
+
try {
|
|
1293
|
+
if (t.closed) {
|
|
1294
|
+
d();
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
} catch {
|
|
1298
|
+
d();
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
o = Math.min(o * s, i), a = setTimeout(u, o);
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
return a = setTimeout(u, o), () => {
|
|
1305
|
+
c = !0, clearTimeout(a);
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function Qe(t, e) {
|
|
1309
|
+
try {
|
|
1310
|
+
const r = S(e.width, t.outerWidth), n = S(
|
|
1311
|
+
e.height,
|
|
1312
|
+
t.outerHeight
|
|
1313
|
+
);
|
|
1314
|
+
t.resizeTo(r, n);
|
|
1315
|
+
} catch {
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
function et(t) {
|
|
1319
|
+
const { doc: e, dimensions: r, uid: n, tag: i } = t, s = e.createElement("div");
|
|
1320
|
+
return s.id = `forgeframe-container-${n}`, s.setAttribute("data-forgeframe-tag", i), Object.assign(s.style, {
|
|
1321
|
+
display: "inline-block",
|
|
1322
|
+
position: "relative",
|
|
1323
|
+
width: w(r.width),
|
|
1324
|
+
height: w(r.height),
|
|
1325
|
+
overflow: "hidden"
|
|
1326
|
+
}), s;
|
|
1327
|
+
}
|
|
1328
|
+
function tt(t) {
|
|
1329
|
+
const { doc: e, dimensions: r, cspNonce: n } = t, i = e.createElement("div");
|
|
1330
|
+
Object.assign(i.style, {
|
|
1331
|
+
display: "flex",
|
|
1332
|
+
alignItems: "center",
|
|
1333
|
+
justifyContent: "center",
|
|
1334
|
+
width: w(r.width),
|
|
1335
|
+
height: w(r.height),
|
|
1336
|
+
backgroundColor: "#f5f5f5",
|
|
1337
|
+
position: "absolute",
|
|
1338
|
+
top: "0",
|
|
1339
|
+
left: "0",
|
|
1340
|
+
zIndex: "100"
|
|
1341
|
+
});
|
|
1342
|
+
const s = e.createElement("div");
|
|
1343
|
+
Object.assign(s.style, {
|
|
1344
|
+
width: "40px",
|
|
1345
|
+
height: "40px",
|
|
1346
|
+
border: "3px solid #e0e0e0",
|
|
1347
|
+
borderTopColor: "#3498db",
|
|
1348
|
+
borderRadius: "50%",
|
|
1349
|
+
animation: "forgeframe-spin 1s linear infinite"
|
|
1350
|
+
});
|
|
1351
|
+
const o = e.createElement("style");
|
|
1352
|
+
return n && o.setAttribute("nonce", n), o.textContent = `
|
|
1353
|
+
@keyframes forgeframe-spin {
|
|
1354
|
+
to { transform: rotate(360deg); }
|
|
1355
|
+
}
|
|
1356
|
+
`, i.appendChild(o), i.appendChild(s), i;
|
|
1357
|
+
}
|
|
1358
|
+
function rt(t, e = 200) {
|
|
1359
|
+
return new Promise((r) => {
|
|
1360
|
+
t.style.opacity = "0", t.style.transition = `opacity ${e}ms ease-in`, t.offsetHeight, t.style.opacity = "1", setTimeout(r, e);
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
function nt(t, e = 200) {
|
|
1364
|
+
return new Promise((r) => {
|
|
1365
|
+
t.style.transition = `opacity ${e}ms ease-out`, t.style.opacity = "0", setTimeout(r, e);
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
async function it(t, e, r) {
|
|
1369
|
+
e && (await nt(e, 150), e.remove()), r.style.display = "", r.style.visibility = "visible", r.style.opacity = "0", await rt(r, 150);
|
|
1370
|
+
}
|
|
1371
|
+
class M {
|
|
1372
|
+
/** Event emitter for lifecycle events. */
|
|
1373
|
+
event;
|
|
1374
|
+
/** Arbitrary state storage for the component instance. */
|
|
1375
|
+
state = {};
|
|
1376
|
+
/** Data exported by the child component. */
|
|
1377
|
+
exports;
|
|
1378
|
+
/** Data exported from the parent by the child. */
|
|
1379
|
+
parentExports;
|
|
1380
|
+
/** @internal */
|
|
1381
|
+
_uid;
|
|
1382
|
+
/**
|
|
1383
|
+
* Unique instance identifier.
|
|
1384
|
+
* @readonly
|
|
1385
|
+
*/
|
|
1386
|
+
get uid() {
|
|
1387
|
+
return this._uid;
|
|
1388
|
+
}
|
|
1389
|
+
/** @internal */
|
|
1390
|
+
options;
|
|
1391
|
+
/** @internal */
|
|
1392
|
+
props;
|
|
1393
|
+
/** @internal */
|
|
1394
|
+
context;
|
|
1395
|
+
/** @internal */
|
|
1396
|
+
messenger;
|
|
1397
|
+
/** @internal */
|
|
1398
|
+
bridge;
|
|
1399
|
+
/** @internal */
|
|
1400
|
+
cleanup;
|
|
1401
|
+
/** @internal */
|
|
1402
|
+
childWindow = null;
|
|
1403
|
+
/** @internal */
|
|
1404
|
+
iframe = null;
|
|
1405
|
+
/** @internal */
|
|
1406
|
+
container = null;
|
|
1407
|
+
/** @internal */
|
|
1408
|
+
prerenderElement = null;
|
|
1409
|
+
/** @internal */
|
|
1410
|
+
initPromise = null;
|
|
1411
|
+
/** @internal */
|
|
1412
|
+
rendered = !1;
|
|
1413
|
+
/** @internal */
|
|
1414
|
+
destroyed = !1;
|
|
1415
|
+
/**
|
|
1416
|
+
* Creates a new ParentComponent instance.
|
|
1417
|
+
*
|
|
1418
|
+
* @param options - Component configuration options
|
|
1419
|
+
* @param props - Initial props to pass to the component
|
|
1420
|
+
*/
|
|
1421
|
+
constructor(e, r = {}) {
|
|
1422
|
+
this._uid = we(), this.options = this.normalizeOptions(e), this.context = this.options.defaultContext, this.event = new ne(), this.cleanup = new Ee();
|
|
1423
|
+
const n = this.buildTrustedDomains();
|
|
1424
|
+
this.messenger = new se(this.uid, window, W(), n), this.bridge = new $(this.messenger);
|
|
1425
|
+
const i = this.createPropContext();
|
|
1426
|
+
this.props = Z(r, this.options.props, i), this.setupMessageHandlers(), this.setupCleanup();
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Builds the list of trusted domains for messenger communication.
|
|
1430
|
+
* @internal
|
|
1431
|
+
*/
|
|
1432
|
+
buildTrustedDomains() {
|
|
1433
|
+
const e = [], r = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url;
|
|
1434
|
+
try {
|
|
1435
|
+
const n = new URL(r);
|
|
1436
|
+
e.push(n.origin);
|
|
1437
|
+
} catch {
|
|
1438
|
+
}
|
|
1439
|
+
if (this.options.domain) {
|
|
1440
|
+
if (typeof this.options.domain == "string")
|
|
1441
|
+
e.push(this.options.domain);
|
|
1442
|
+
else if (Array.isArray(this.options.domain))
|
|
1443
|
+
e.push(...this.options.domain);
|
|
1444
|
+
else if (this.options.domain instanceof RegExp)
|
|
1445
|
+
return this.options.domain;
|
|
1446
|
+
}
|
|
1447
|
+
return e.length > 0 ? e : void 0;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Renders the component into a DOM container.
|
|
1451
|
+
*
|
|
1452
|
+
* @remarks
|
|
1453
|
+
* This is the primary method for displaying the component. It creates
|
|
1454
|
+
* an iframe or popup, establishes communication with the child, and
|
|
1455
|
+
* handles the prerender/render lifecycle.
|
|
1456
|
+
*
|
|
1457
|
+
* @param container - CSS selector or HTMLElement to render into
|
|
1458
|
+
* @param context - Override the default rendering context (iframe or popup)
|
|
1459
|
+
* @throws Error if component was already destroyed or rendered
|
|
1460
|
+
*
|
|
1461
|
+
* @example
|
|
1462
|
+
* ```typescript
|
|
1463
|
+
* await instance.render('#container');
|
|
1464
|
+
* await instance.render(document.getElementById('target'), 'popup');
|
|
1465
|
+
* ```
|
|
1466
|
+
*/
|
|
1467
|
+
async render(e, r) {
|
|
1468
|
+
if (this.destroyed)
|
|
1469
|
+
throw new Error("Component has been destroyed");
|
|
1470
|
+
if (this.rendered)
|
|
1471
|
+
throw new Error("Component has already been rendered");
|
|
1472
|
+
this.context = r ?? this.options.defaultContext, this.checkEligibility(), ke(this.props, this.options.props), this.container = this.resolveContainer(e), this.event.emit(p.PRERENDER), this.callPropCallback("onPrerender"), await this.prerender(), this.event.emit(p.PRERENDERED), this.callPropCallback("onPrerendered"), this.event.emit(p.RENDER), this.callPropCallback("onRender"), await this.open(), await this.waitForChild(), this.context === f.IFRAME && this.iframe && this.prerenderElement && (await it(
|
|
1473
|
+
this.container,
|
|
1474
|
+
this.prerenderElement,
|
|
1475
|
+
this.iframe
|
|
1476
|
+
), this.prerenderElement = null), this.rendered = !0, this.event.emit(p.RENDERED), this.callPropCallback("onRendered"), this.event.emit(p.DISPLAY), this.callPropCallback("onDisplay");
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Renders the component into a container in a different window.
|
|
1480
|
+
*
|
|
1481
|
+
* @remarks
|
|
1482
|
+
* Currently delegates to regular render. Full cross-window rendering
|
|
1483
|
+
* would require additional complexity.
|
|
1484
|
+
*
|
|
1485
|
+
* @param _win - Target window (currently unused)
|
|
1486
|
+
* @param container - CSS selector or HTMLElement to render into
|
|
1487
|
+
* @param context - Override the default rendering context
|
|
1488
|
+
*/
|
|
1489
|
+
async renderTo(e, r, n) {
|
|
1490
|
+
return this.render(r, n);
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Closes and destroys the component.
|
|
1494
|
+
*
|
|
1495
|
+
* @remarks
|
|
1496
|
+
* Emits the 'close' event before destruction. Safe to call multiple times.
|
|
1497
|
+
*/
|
|
1498
|
+
async close() {
|
|
1499
|
+
this.destroyed || (this.event.emit(p.CLOSE), await this.destroy());
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Focuses the component window.
|
|
1503
|
+
*
|
|
1504
|
+
* @remarks
|
|
1505
|
+
* For iframes, focuses the iframe element. For popups, brings the window to front.
|
|
1506
|
+
*/
|
|
1507
|
+
async focus() {
|
|
1508
|
+
this.context === f.IFRAME && this.iframe ? Xe(this.iframe) : this.context === f.POPUP && this.childWindow && Ve(this.childWindow), this.event.emit(p.FOCUS), this.callPropCallback("onFocus");
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Resizes the component to the specified dimensions.
|
|
1512
|
+
*
|
|
1513
|
+
* @param dimensions - New width and height for the component
|
|
1514
|
+
*/
|
|
1515
|
+
async resize(e) {
|
|
1516
|
+
this.context === f.IFRAME && this.iframe ? je(this.iframe, e) : this.context === f.POPUP && this.childWindow && Qe(this.childWindow, e), this.event.emit(p.RESIZE, e), this.callPropCallback("onResize", e);
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Shows the component if hidden.
|
|
1520
|
+
*
|
|
1521
|
+
* @remarks
|
|
1522
|
+
* Only applicable to iframe context.
|
|
1523
|
+
*/
|
|
1524
|
+
async show() {
|
|
1525
|
+
this.context === f.IFRAME && this.iframe && He(this.iframe);
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Hides the component.
|
|
1529
|
+
*
|
|
1530
|
+
* @remarks
|
|
1531
|
+
* Only applicable to iframe context.
|
|
1532
|
+
*/
|
|
1533
|
+
async hide() {
|
|
1534
|
+
this.context === f.IFRAME && this.iframe && te(this.iframe);
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Updates the component props and sends them to the child.
|
|
1538
|
+
*
|
|
1539
|
+
* @remarks
|
|
1540
|
+
* Props are normalized and serialized before being sent to the child window.
|
|
1541
|
+
*
|
|
1542
|
+
* @param newProps - Partial props object to merge with existing props
|
|
1543
|
+
*/
|
|
1544
|
+
async updateProps(e) {
|
|
1545
|
+
const r = this.createPropContext();
|
|
1546
|
+
if (this.props = Z(
|
|
1547
|
+
{ ...this.props, ...e },
|
|
1548
|
+
this.options.props,
|
|
1549
|
+
r
|
|
1550
|
+
), this.childWindow && !ce(this.childWindow)) {
|
|
1551
|
+
const n = this.getChildDomain(), i = K(
|
|
1552
|
+
this.props,
|
|
1553
|
+
this.options.props,
|
|
1554
|
+
n,
|
|
1555
|
+
oe(this.childWindow)
|
|
1556
|
+
), s = Q(
|
|
1557
|
+
i,
|
|
1558
|
+
this.options.props,
|
|
1559
|
+
this.bridge
|
|
1560
|
+
);
|
|
1561
|
+
await this.messenger.send(
|
|
1562
|
+
this.childWindow,
|
|
1563
|
+
n,
|
|
1564
|
+
l.PROPS,
|
|
1565
|
+
s
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
this.event.emit(p.PROPS, this.props), this.callPropCallback("onProps", this.props);
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Creates a clone of this instance with the same props.
|
|
1572
|
+
*
|
|
1573
|
+
* @returns A new unrendered component instance with identical configuration
|
|
1574
|
+
*/
|
|
1575
|
+
clone() {
|
|
1576
|
+
return new M(this.options, this.props);
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Checks if the component is eligible to render based on the eligible option.
|
|
1580
|
+
*
|
|
1581
|
+
* @returns True if eligible or no eligibility check defined
|
|
1582
|
+
*/
|
|
1583
|
+
isEligible() {
|
|
1584
|
+
return this.options.eligible ? this.options.eligible({ props: this.props }).eligible : !0;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Normalizes component options with default values.
|
|
1588
|
+
* @internal
|
|
1589
|
+
*/
|
|
1590
|
+
normalizeOptions(e) {
|
|
1591
|
+
return {
|
|
1592
|
+
...e,
|
|
1593
|
+
props: e.props ?? {},
|
|
1594
|
+
defaultContext: e.defaultContext ?? f.IFRAME,
|
|
1595
|
+
dimensions: typeof e.dimensions == "function" ? e.dimensions(this.props) : e.dimensions ?? { width: "100%", height: "100%" },
|
|
1596
|
+
timeout: e.timeout ?? 1e4,
|
|
1597
|
+
children: e.children
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
/**
|
|
1601
|
+
* Creates the prop context passed to prop callbacks and validators.
|
|
1602
|
+
* @internal
|
|
1603
|
+
*/
|
|
1604
|
+
createPropContext() {
|
|
1605
|
+
return {
|
|
1606
|
+
props: this.props,
|
|
1607
|
+
state: this.state,
|
|
1608
|
+
close: () => this.close(),
|
|
1609
|
+
focus: () => this.focus(),
|
|
1610
|
+
onError: (e) => this.handleError(e),
|
|
1611
|
+
container: this.container,
|
|
1612
|
+
uid: this.uid,
|
|
1613
|
+
tag: this.options.tag
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* Resolves a container selector or element to an HTMLElement.
|
|
1618
|
+
* @internal
|
|
1619
|
+
*/
|
|
1620
|
+
resolveContainer(e) {
|
|
1621
|
+
if (!e)
|
|
1622
|
+
throw new Error("Container is required for rendering");
|
|
1623
|
+
if (typeof e == "string") {
|
|
1624
|
+
const r = document.querySelector(e);
|
|
1625
|
+
if (!r)
|
|
1626
|
+
throw new Error(`Container "${e}" not found`);
|
|
1627
|
+
return r;
|
|
1628
|
+
}
|
|
1629
|
+
return e;
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Checks eligibility and throws if component cannot render.
|
|
1633
|
+
* @internal
|
|
1634
|
+
*/
|
|
1635
|
+
checkEligibility() {
|
|
1636
|
+
if (!this.options.eligible) return;
|
|
1637
|
+
const e = this.options.eligible({ props: this.props });
|
|
1638
|
+
if (!e.eligible)
|
|
1639
|
+
throw new Error(`Component not eligible: ${e.reason ?? "Unknown reason"}`);
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Creates and displays the prerender (loading) content.
|
|
1643
|
+
* @internal
|
|
1644
|
+
*/
|
|
1645
|
+
async prerender() {
|
|
1646
|
+
if (!this.container) return;
|
|
1647
|
+
const e = this.options.prerenderTemplate ?? tt, r = this.options.containerTemplate ?? et, n = this.options.dimensions, i = this.props.cspNonce;
|
|
1648
|
+
if (this.context === f.IFRAME) {
|
|
1649
|
+
const c = this.buildWindowName();
|
|
1650
|
+
this.iframe = this.createIframeElement(c), te(this.iframe);
|
|
1651
|
+
}
|
|
1652
|
+
const s = {
|
|
1653
|
+
uid: this.uid,
|
|
1654
|
+
tag: this.options.tag,
|
|
1655
|
+
context: this.context,
|
|
1656
|
+
dimensions: n,
|
|
1657
|
+
props: this.props,
|
|
1658
|
+
doc: document,
|
|
1659
|
+
container: this.container,
|
|
1660
|
+
frame: this.iframe,
|
|
1661
|
+
prerenderFrame: null,
|
|
1662
|
+
close: () => this.close(),
|
|
1663
|
+
focus: () => this.focus(),
|
|
1664
|
+
cspNonce: i
|
|
1665
|
+
};
|
|
1666
|
+
this.prerenderElement = e(s);
|
|
1667
|
+
const o = {
|
|
1668
|
+
uid: this.uid,
|
|
1669
|
+
tag: this.options.tag,
|
|
1670
|
+
context: this.context,
|
|
1671
|
+
dimensions: n,
|
|
1672
|
+
props: this.props,
|
|
1673
|
+
doc: document,
|
|
1674
|
+
container: this.container,
|
|
1675
|
+
frame: this.iframe,
|
|
1676
|
+
prerenderFrame: this.prerenderElement,
|
|
1677
|
+
close: () => this.close(),
|
|
1678
|
+
focus: () => this.focus(),
|
|
1679
|
+
cspNonce: i
|
|
1680
|
+
}, a = r(o);
|
|
1681
|
+
a && (this.container.appendChild(a), this.container = a), this.prerenderElement && !this.prerenderElement.parentNode && this.container.appendChild(this.prerenderElement), this.iframe && !this.iframe.parentNode && this.container.appendChild(this.iframe);
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Creates an iframe element without setting src (for prerender phase).
|
|
1685
|
+
* The window name is set immediately as it carries the payload for the child.
|
|
1686
|
+
* @internal
|
|
1687
|
+
*/
|
|
1688
|
+
createIframeElement(e) {
|
|
1689
|
+
const r = document.createElement("iframe"), n = this.options.dimensions, i = typeof this.options.attributes == "function" ? this.options.attributes(this.props) : this.options.attributes ?? {}, s = typeof this.options.style == "function" ? this.options.style(this.props) : this.options.style ?? {};
|
|
1690
|
+
r.name = e, r.setAttribute("frameborder", "0"), r.setAttribute("allowtransparency", "true"), r.setAttribute("scrolling", "auto"), n.width !== void 0 && (r.style.width = typeof n.width == "number" ? `${n.width}px` : n.width), n.height !== void 0 && (r.style.height = typeof n.height == "number" ? `${n.height}px` : n.height);
|
|
1691
|
+
for (const [o, a] of Object.entries(i))
|
|
1692
|
+
a !== void 0 && (typeof a == "boolean" ? a && r.setAttribute(o, "") : r.setAttribute(o, a));
|
|
1693
|
+
for (const [o, a] of Object.entries(s)) {
|
|
1694
|
+
if (a === void 0) continue;
|
|
1695
|
+
const c = typeof a == "number" ? `${a}px` : a;
|
|
1696
|
+
r.style.setProperty(
|
|
1697
|
+
o.replace(/([A-Z])/g, "-$1").toLowerCase(),
|
|
1698
|
+
String(c)
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
return i.sandbox || r.setAttribute(
|
|
1702
|
+
"sandbox",
|
|
1703
|
+
"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
|
|
1704
|
+
), r;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Opens the child window (iframe or popup).
|
|
1708
|
+
* @internal
|
|
1709
|
+
*/
|
|
1710
|
+
async open() {
|
|
1711
|
+
const e = this.buildUrl();
|
|
1712
|
+
if (this.context === f.IFRAME) {
|
|
1713
|
+
if (!this.iframe)
|
|
1714
|
+
throw new Error("Iframe not created during prerender");
|
|
1715
|
+
this.iframe.src = e, this.childWindow = this.iframe.contentWindow;
|
|
1716
|
+
} else {
|
|
1717
|
+
const r = this.buildWindowName();
|
|
1718
|
+
this.childWindow = Ge({
|
|
1719
|
+
url: e,
|
|
1720
|
+
name: r,
|
|
1721
|
+
dimensions: this.options.dimensions
|
|
1722
|
+
});
|
|
1723
|
+
const n = Ke(this.childWindow, () => {
|
|
1724
|
+
this.destroy();
|
|
1725
|
+
});
|
|
1726
|
+
this.cleanup.register(n);
|
|
1727
|
+
}
|
|
1728
|
+
this.childWindow && ve(this.uid, this.childWindow);
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Builds the URL for the child window including query parameters.
|
|
1732
|
+
* @internal
|
|
1733
|
+
*/
|
|
1734
|
+
buildUrl() {
|
|
1735
|
+
const e = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url, n = We(this.props, this.options.props).toString();
|
|
1736
|
+
if (!n) return e;
|
|
1737
|
+
const i = e.includes("?") ? "&" : "?";
|
|
1738
|
+
return `${e}${i}${n}`;
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Builds the window.name payload for the child window.
|
|
1742
|
+
* @internal
|
|
1743
|
+
*/
|
|
1744
|
+
buildWindowName() {
|
|
1745
|
+
const e = this.getChildDomain(), r = K(
|
|
1746
|
+
this.props,
|
|
1747
|
+
this.options.props,
|
|
1748
|
+
e,
|
|
1749
|
+
!1
|
|
1750
|
+
// Assume cross-domain for initial payload
|
|
1751
|
+
), n = Q(
|
|
1752
|
+
r,
|
|
1753
|
+
this.options.props,
|
|
1754
|
+
this.bridge
|
|
1755
|
+
), i = this.buildChildrenRefs(), s = xe({
|
|
1756
|
+
uid: this.uid,
|
|
1757
|
+
tag: this.options.tag,
|
|
1758
|
+
context: this.context,
|
|
1759
|
+
parentDomain: W(),
|
|
1760
|
+
props: n,
|
|
1761
|
+
exports: this.createParentExports(),
|
|
1762
|
+
children: i
|
|
1763
|
+
});
|
|
1764
|
+
return Te(s);
|
|
1765
|
+
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Builds component references for nested child components.
|
|
1768
|
+
* @internal
|
|
1769
|
+
*/
|
|
1770
|
+
buildChildrenRefs() {
|
|
1771
|
+
if (!this.options.children) return;
|
|
1772
|
+
const e = this.options.children({ props: this.props }), r = {};
|
|
1773
|
+
for (const [n, i] of Object.entries(e)) {
|
|
1774
|
+
const s = i;
|
|
1775
|
+
r[n] = {
|
|
1776
|
+
tag: s.tag ?? n,
|
|
1777
|
+
url: typeof s.url == "function" ? s.url.toString() : s.url ?? ""
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
return Object.keys(r).length > 0 ? r : void 0;
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Creates the exports object sent to the child.
|
|
1784
|
+
* @internal
|
|
1785
|
+
*/
|
|
1786
|
+
createParentExports() {
|
|
1787
|
+
return {
|
|
1788
|
+
init: l.INIT,
|
|
1789
|
+
close: l.CLOSE,
|
|
1790
|
+
resize: l.RESIZE,
|
|
1791
|
+
show: l.SHOW,
|
|
1792
|
+
hide: l.HIDE,
|
|
1793
|
+
onError: l.ERROR,
|
|
1794
|
+
updateProps: l.PROPS,
|
|
1795
|
+
export: l.EXPORT
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Extracts the origin domain from the component URL.
|
|
1800
|
+
* @internal
|
|
1801
|
+
*/
|
|
1802
|
+
getChildDomain() {
|
|
1803
|
+
const e = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url;
|
|
1804
|
+
try {
|
|
1805
|
+
return new URL(e, window.location.origin).origin;
|
|
1806
|
+
} catch {
|
|
1807
|
+
return "*";
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Waits for the child to send the init message.
|
|
1812
|
+
* @internal
|
|
1813
|
+
*/
|
|
1814
|
+
async waitForChild() {
|
|
1815
|
+
this.initPromise = ie();
|
|
1816
|
+
try {
|
|
1817
|
+
await Ce(
|
|
1818
|
+
this.initPromise.promise,
|
|
1819
|
+
this.options.timeout,
|
|
1820
|
+
`Child component "${this.options.tag}" (uid: ${this._uid}) did not initialize within ${this.options.timeout}ms. Check that the child page loads correctly and calls the initialization code.`
|
|
1821
|
+
);
|
|
1822
|
+
} catch (e) {
|
|
1823
|
+
throw this.handleError(e), e;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Sets up message handlers for child communication.
|
|
1828
|
+
* @internal
|
|
1829
|
+
*/
|
|
1830
|
+
setupMessageHandlers() {
|
|
1831
|
+
this.messenger.on(l.INIT, () => (this.initPromise && this.initPromise.resolve(), { success: !0 })), this.messenger.on(l.CLOSE, async () => (await this.close(), { success: !0 })), this.messenger.on(l.RESIZE, async (e) => (await this.resize(e), { success: !0 })), this.messenger.on(l.FOCUS, async () => (await this.focus(), { success: !0 })), this.messenger.on(l.SHOW, async () => (await this.show(), { success: !0 })), this.messenger.on(l.HIDE, async () => (await this.hide(), { success: !0 })), this.messenger.on(
|
|
1832
|
+
l.ERROR,
|
|
1833
|
+
async (e) => {
|
|
1834
|
+
const r = new Error(e.message);
|
|
1835
|
+
return r.stack = e.stack, this.handleError(r), { success: !0 };
|
|
1836
|
+
}
|
|
1837
|
+
), this.messenger.on(l.EXPORT, async (e) => (this.exports = e, { success: !0 })), this.messenger.on(l.PARENT_EXPORT, async (e) => (this.parentExports = e, { success: !0 })), this.messenger.on(
|
|
1838
|
+
l.GET_SIBLINGS,
|
|
1839
|
+
async (e) => {
|
|
1840
|
+
const r = [], n = lt(e.tag);
|
|
1841
|
+
if (n)
|
|
1842
|
+
for (const i of n.instances)
|
|
1843
|
+
i.uid !== e.uid && r.push({
|
|
1844
|
+
uid: i.uid,
|
|
1845
|
+
tag: e.tag,
|
|
1846
|
+
exports: i.exports
|
|
1847
|
+
});
|
|
1848
|
+
return r;
|
|
1849
|
+
}
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Registers cleanup handlers for the instance.
|
|
1854
|
+
* @internal
|
|
1855
|
+
*/
|
|
1856
|
+
setupCleanup() {
|
|
1857
|
+
this.cleanup.register(() => {
|
|
1858
|
+
this.messenger.destroy(), this.bridge.destroy(), this.event.removeAllListeners(), Ae(this.uid);
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Handles errors by emitting events and calling callbacks.
|
|
1863
|
+
* @internal
|
|
1864
|
+
*/
|
|
1865
|
+
handleError(e) {
|
|
1866
|
+
this.event.emit(p.ERROR, e), this.callPropCallback("onError", e);
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Calls a prop callback if it exists.
|
|
1870
|
+
* @internal
|
|
1871
|
+
*/
|
|
1872
|
+
callPropCallback(e, ...r) {
|
|
1873
|
+
const n = this.props[e];
|
|
1874
|
+
if (typeof n == "function")
|
|
1875
|
+
try {
|
|
1876
|
+
const i = n(...r);
|
|
1877
|
+
i && typeof i == "object" && "catch" in i && typeof i.catch == "function" && i.catch((s) => {
|
|
1878
|
+
console.error(`Error in async ${e} callback:`, s);
|
|
1879
|
+
});
|
|
1880
|
+
} catch (i) {
|
|
1881
|
+
console.error(`Error in ${e} callback:`, i);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
/**
|
|
1885
|
+
* Destroys the component and cleans up all resources.
|
|
1886
|
+
* @internal
|
|
1887
|
+
*/
|
|
1888
|
+
async destroy() {
|
|
1889
|
+
this.destroyed || (this.destroyed = !0, this.initPromise && (this.initPromise.reject(
|
|
1890
|
+
new Error(`Component "${this.options.tag}" was destroyed before initialization completed`)
|
|
1891
|
+
), this.initPromise = null), this.iframe && (Be(this.iframe), this.iframe = null), this.context === f.POPUP && this.childWindow && Ye(this.childWindow), this.childWindow = null, this.prerenderElement && (this.prerenderElement.remove(), this.prerenderElement = null), await this.cleanup.cleanup(), this.event.emit(p.DESTROY), this.callPropCallback("onDestroy"));
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
class st {
|
|
1895
|
+
/**
|
|
1896
|
+
* Creates a new ChildComponent instance.
|
|
1897
|
+
*
|
|
1898
|
+
* @param payload - The payload parsed from window.name
|
|
1899
|
+
* @param propDefinitions - Optional prop definitions for deserialization
|
|
1900
|
+
*/
|
|
1901
|
+
constructor(e, r = {}) {
|
|
1902
|
+
this.propDefinitions = r, this.uid = e.uid, this.tag = e.tag, this.parentDomain = e.parentDomain, this.event = new ne(), this.messenger = new se(this.uid, window, W(), this.parentDomain), this.setupMessageHandlers(), this.parentWindow = this.resolveParentWindow(), this.bridge = new $(this.messenger), this.xprops = this.buildXProps(e), window.xprops = this.xprops, this.sendInit();
|
|
1903
|
+
}
|
|
1904
|
+
/** The xprops object containing props and control methods. */
|
|
1905
|
+
xprops;
|
|
1906
|
+
/** Event emitter for lifecycle events. */
|
|
1907
|
+
event;
|
|
1908
|
+
/** @internal */
|
|
1909
|
+
uid;
|
|
1910
|
+
/** @internal */
|
|
1911
|
+
tag;
|
|
1912
|
+
/** @internal */
|
|
1913
|
+
parentWindow;
|
|
1914
|
+
/** @internal */
|
|
1915
|
+
parentDomain;
|
|
1916
|
+
/** @internal */
|
|
1917
|
+
messenger;
|
|
1918
|
+
/** @internal */
|
|
1919
|
+
bridge;
|
|
1920
|
+
/** @internal */
|
|
1921
|
+
propsHandlers = /* @__PURE__ */ new Set();
|
|
1922
|
+
/** @internal */
|
|
1923
|
+
parentProps;
|
|
1924
|
+
/** @internal */
|
|
1925
|
+
initError = null;
|
|
1926
|
+
/**
|
|
1927
|
+
* Returns the xprops object.
|
|
1928
|
+
*
|
|
1929
|
+
* @returns The xprops object with props and control methods
|
|
1930
|
+
*/
|
|
1931
|
+
getProps() {
|
|
1932
|
+
return this.xprops;
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Resolves the parent window reference (iframe parent or popup opener).
|
|
1936
|
+
* @internal
|
|
1937
|
+
*/
|
|
1938
|
+
resolveParentWindow() {
|
|
1939
|
+
if (_e()) {
|
|
1940
|
+
const e = be();
|
|
1941
|
+
if (e) return e;
|
|
1942
|
+
}
|
|
1943
|
+
if (Ie()) {
|
|
1944
|
+
const e = Oe();
|
|
1945
|
+
if (e) return e;
|
|
1946
|
+
}
|
|
1947
|
+
throw new Error("Could not resolve parent window");
|
|
1948
|
+
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Builds the xprops object with deserialized props and control methods.
|
|
1951
|
+
* @internal
|
|
1952
|
+
*/
|
|
1953
|
+
buildXProps(e) {
|
|
1954
|
+
const r = ee(
|
|
1955
|
+
e.props,
|
|
1956
|
+
this.propDefinitions,
|
|
1957
|
+
this.messenger,
|
|
1958
|
+
this.bridge,
|
|
1959
|
+
this.parentWindow,
|
|
1960
|
+
this.parentDomain
|
|
1961
|
+
);
|
|
1962
|
+
return this.parentProps = r, {
|
|
1963
|
+
...r,
|
|
1964
|
+
uid: this.uid,
|
|
1965
|
+
tag: this.tag,
|
|
1966
|
+
close: () => this.close(),
|
|
1967
|
+
focus: () => this.focus(),
|
|
1968
|
+
resize: (n) => this.resize(n),
|
|
1969
|
+
show: () => this.show(),
|
|
1970
|
+
hide: () => this.hide(),
|
|
1971
|
+
onProps: (n) => this.onProps(n),
|
|
1972
|
+
onError: (n) => this.onError(n),
|
|
1973
|
+
getParent: () => this.parentWindow,
|
|
1974
|
+
getParentDomain: () => this.parentDomain,
|
|
1975
|
+
export: (n) => this.exportData(n),
|
|
1976
|
+
parent: {
|
|
1977
|
+
props: this.parentProps,
|
|
1978
|
+
export: (n) => this.parentExport(n)
|
|
1979
|
+
},
|
|
1980
|
+
getSiblings: (n) => this.getSiblings(n),
|
|
1981
|
+
children: this.buildChildComponents(e.children)
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
/**
|
|
1985
|
+
* Sends initialization message to the parent.
|
|
1986
|
+
* @internal
|
|
1987
|
+
*/
|
|
1988
|
+
async sendInit() {
|
|
1989
|
+
try {
|
|
1990
|
+
await this.messenger.send(
|
|
1991
|
+
this.parentWindow,
|
|
1992
|
+
this.parentDomain,
|
|
1993
|
+
l.INIT,
|
|
1994
|
+
{ uid: this.uid, tag: this.tag }
|
|
1995
|
+
);
|
|
1996
|
+
} catch (e) {
|
|
1997
|
+
const r = e instanceof Error ? e : new Error(String(e));
|
|
1998
|
+
this.initError = r, this.event.emit(p.ERROR, {
|
|
1999
|
+
type: "init_failed",
|
|
2000
|
+
message: `Failed to initialize child component: ${r.message}`,
|
|
2001
|
+
error: r
|
|
2002
|
+
}), console.error("Failed to send init message:", e);
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Returns the initialization error if one occurred.
|
|
2007
|
+
*
|
|
2008
|
+
* @returns The initialization error or null if successful
|
|
2009
|
+
*/
|
|
2010
|
+
getInitError() {
|
|
2011
|
+
return this.initError;
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Requests the parent to close this component.
|
|
2015
|
+
* @internal
|
|
2016
|
+
*/
|
|
2017
|
+
async close() {
|
|
2018
|
+
await this.messenger.send(
|
|
2019
|
+
this.parentWindow,
|
|
2020
|
+
this.parentDomain,
|
|
2021
|
+
l.CLOSE,
|
|
2022
|
+
{}
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
2026
|
+
* Focuses this window and notifies the parent.
|
|
2027
|
+
* @internal
|
|
2028
|
+
*/
|
|
2029
|
+
async focus() {
|
|
2030
|
+
window.focus(), await this.messenger.send(
|
|
2031
|
+
this.parentWindow,
|
|
2032
|
+
this.parentDomain,
|
|
2033
|
+
l.FOCUS,
|
|
2034
|
+
{}
|
|
2035
|
+
);
|
|
2036
|
+
}
|
|
2037
|
+
/**
|
|
2038
|
+
* Requests the parent to resize this component.
|
|
2039
|
+
* @internal
|
|
2040
|
+
*/
|
|
2041
|
+
async resize(e) {
|
|
2042
|
+
await this.messenger.send(
|
|
2043
|
+
this.parentWindow,
|
|
2044
|
+
this.parentDomain,
|
|
2045
|
+
l.RESIZE,
|
|
2046
|
+
e
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
/**
|
|
2050
|
+
* Requests the parent to show this component.
|
|
2051
|
+
* @internal
|
|
2052
|
+
*/
|
|
2053
|
+
async show() {
|
|
2054
|
+
await this.messenger.send(
|
|
2055
|
+
this.parentWindow,
|
|
2056
|
+
this.parentDomain,
|
|
2057
|
+
l.SHOW,
|
|
2058
|
+
{}
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Requests the parent to hide this component.
|
|
2063
|
+
* @internal
|
|
2064
|
+
*/
|
|
2065
|
+
async hide() {
|
|
2066
|
+
await this.messenger.send(
|
|
2067
|
+
this.parentWindow,
|
|
2068
|
+
this.parentDomain,
|
|
2069
|
+
l.HIDE,
|
|
2070
|
+
{}
|
|
2071
|
+
);
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Subscribes to prop updates from the parent.
|
|
2075
|
+
* @internal
|
|
2076
|
+
*/
|
|
2077
|
+
onProps(e) {
|
|
2078
|
+
return this.propsHandlers.add(e), {
|
|
2079
|
+
cancel: () => this.propsHandlers.delete(e)
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Reports an error to the parent.
|
|
2084
|
+
* @internal
|
|
2085
|
+
*/
|
|
2086
|
+
async onError(e) {
|
|
2087
|
+
await this.messenger.send(
|
|
2088
|
+
this.parentWindow,
|
|
2089
|
+
this.parentDomain,
|
|
2090
|
+
l.ERROR,
|
|
2091
|
+
{
|
|
2092
|
+
message: e.message,
|
|
2093
|
+
stack: e.stack
|
|
2094
|
+
}
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
/**
|
|
2098
|
+
* Exports data or methods to the parent.
|
|
2099
|
+
* @internal
|
|
2100
|
+
*/
|
|
2101
|
+
async exportData(e) {
|
|
2102
|
+
await this.messenger.send(
|
|
2103
|
+
this.parentWindow,
|
|
2104
|
+
this.parentDomain,
|
|
2105
|
+
l.EXPORT,
|
|
2106
|
+
e
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Exports data to the parent for bidirectional communication.
|
|
2111
|
+
* @internal
|
|
2112
|
+
*/
|
|
2113
|
+
async parentExport(e) {
|
|
2114
|
+
await this.messenger.send(
|
|
2115
|
+
this.parentWindow,
|
|
2116
|
+
this.parentDomain,
|
|
2117
|
+
l.PARENT_EXPORT,
|
|
2118
|
+
e
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Gets information about sibling component instances.
|
|
2123
|
+
* @internal
|
|
2124
|
+
*/
|
|
2125
|
+
async getSiblings(e) {
|
|
2126
|
+
return await this.messenger.send(
|
|
2127
|
+
this.parentWindow,
|
|
2128
|
+
this.parentDomain,
|
|
2129
|
+
l.GET_SIBLINGS,
|
|
2130
|
+
{ uid: this.uid, tag: this.tag, options: e }
|
|
2131
|
+
) ?? [];
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Builds child component factories from refs passed by the parent.
|
|
2135
|
+
* @internal
|
|
2136
|
+
*/
|
|
2137
|
+
buildChildComponents(e) {
|
|
2138
|
+
if (!e) return;
|
|
2139
|
+
const r = {};
|
|
2140
|
+
for (const [n, i] of Object.entries(e))
|
|
2141
|
+
try {
|
|
2142
|
+
r[n] = fe({
|
|
2143
|
+
tag: i.tag,
|
|
2144
|
+
url: i.url,
|
|
2145
|
+
props: i.props,
|
|
2146
|
+
dimensions: i.dimensions,
|
|
2147
|
+
defaultContext: i.defaultContext
|
|
2148
|
+
});
|
|
2149
|
+
} catch (s) {
|
|
2150
|
+
console.warn(`Failed to create child component "${n}":`, s);
|
|
2151
|
+
}
|
|
2152
|
+
return Object.keys(r).length > 0 ? r : void 0;
|
|
2153
|
+
}
|
|
2154
|
+
/**
|
|
2155
|
+
* Sets up message handlers for parent communication.
|
|
2156
|
+
* @internal
|
|
2157
|
+
*/
|
|
2158
|
+
setupMessageHandlers() {
|
|
2159
|
+
this.messenger.on(l.PROPS, (e) => {
|
|
2160
|
+
try {
|
|
2161
|
+
const r = ee(
|
|
2162
|
+
e,
|
|
2163
|
+
this.propDefinitions,
|
|
2164
|
+
this.messenger,
|
|
2165
|
+
this.bridge,
|
|
2166
|
+
this.parentWindow,
|
|
2167
|
+
this.parentDomain
|
|
2168
|
+
);
|
|
2169
|
+
Object.assign(this.xprops, r);
|
|
2170
|
+
for (const n of this.propsHandlers)
|
|
2171
|
+
try {
|
|
2172
|
+
n(r);
|
|
2173
|
+
} catch (i) {
|
|
2174
|
+
console.error("Error in props handler:", i);
|
|
2175
|
+
}
|
|
2176
|
+
return this.event.emit(p.PROPS, r), { success: !0 };
|
|
2177
|
+
} catch (r) {
|
|
2178
|
+
const n = r instanceof Error ? r : new Error(String(r));
|
|
2179
|
+
throw console.error("Error deserializing props:", n), this.event.emit(p.ERROR, n), n;
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
/**
|
|
2184
|
+
* Destroys the child component and cleans up resources.
|
|
2185
|
+
*/
|
|
2186
|
+
destroy() {
|
|
2187
|
+
this.messenger.destroy(), this.bridge.destroy(), this.event.removeAllListeners(), this.propsHandlers.clear();
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
let _ = null;
|
|
2191
|
+
function pe(t) {
|
|
2192
|
+
if (_)
|
|
2193
|
+
return _;
|
|
2194
|
+
if (!de())
|
|
2195
|
+
return null;
|
|
2196
|
+
const e = De();
|
|
2197
|
+
return e ? (_ = new st(
|
|
2198
|
+
e,
|
|
2199
|
+
t
|
|
2200
|
+
), _) : (console.error("Failed to parse ForgeFrame payload from window.name"), null);
|
|
2201
|
+
}
|
|
2202
|
+
function ot() {
|
|
2203
|
+
return de();
|
|
2204
|
+
}
|
|
2205
|
+
function at() {
|
|
2206
|
+
return window.xprops;
|
|
2207
|
+
}
|
|
2208
|
+
const P = /* @__PURE__ */ new Map();
|
|
2209
|
+
function ct(t) {
|
|
2210
|
+
if (!t.tag)
|
|
2211
|
+
throw new Error("Component tag is required");
|
|
2212
|
+
if (!/^[a-z][a-z0-9-]*$/.test(t.tag))
|
|
2213
|
+
throw new Error(
|
|
2214
|
+
`Invalid component tag "${t.tag}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`
|
|
2215
|
+
);
|
|
2216
|
+
if (!t.url)
|
|
2217
|
+
throw new Error("Component url is required");
|
|
2218
|
+
if (typeof t.url == "string")
|
|
2219
|
+
try {
|
|
2220
|
+
new URL(t.url, window.location.origin);
|
|
2221
|
+
} catch {
|
|
2222
|
+
throw new Error(
|
|
2223
|
+
`Invalid component URL "${t.url}". Must be a valid absolute or relative URL.`
|
|
2224
|
+
);
|
|
2225
|
+
}
|
|
2226
|
+
if (P.has(t.tag))
|
|
2227
|
+
throw new Error(`Component "${t.tag}" is already registered`);
|
|
2228
|
+
}
|
|
2229
|
+
function fe(t) {
|
|
2230
|
+
ct(t);
|
|
2231
|
+
const e = [];
|
|
2232
|
+
let r;
|
|
2233
|
+
if (Y(t.tag)) {
|
|
2234
|
+
const i = pe(t.props);
|
|
2235
|
+
i && (r = i.xprops);
|
|
2236
|
+
}
|
|
2237
|
+
const n = function(i = {}) {
|
|
2238
|
+
const s = new M(t, i);
|
|
2239
|
+
return e.push(s), s.event.once("destroy", () => {
|
|
2240
|
+
const o = e.indexOf(s);
|
|
2241
|
+
o !== -1 && e.splice(o, 1);
|
|
2242
|
+
}), s;
|
|
2243
|
+
};
|
|
2244
|
+
return n.instances = e, n.isChild = () => Y(t.tag), n.xprops = r, n.canRenderTo = async (i) => {
|
|
2245
|
+
try {
|
|
2246
|
+
return !!(oe(i) || t.domain);
|
|
2247
|
+
} catch {
|
|
2248
|
+
return !1;
|
|
2249
|
+
}
|
|
2250
|
+
}, P.set(t.tag, n), n;
|
|
2251
|
+
}
|
|
2252
|
+
function lt(t) {
|
|
2253
|
+
return P.get(t);
|
|
2254
|
+
}
|
|
2255
|
+
async function dt(t) {
|
|
2256
|
+
await t.close();
|
|
2257
|
+
}
|
|
2258
|
+
async function me(t) {
|
|
2259
|
+
const e = P.get(t);
|
|
2260
|
+
if (!e) return;
|
|
2261
|
+
const r = [...e.instances];
|
|
2262
|
+
await Promise.all(r.map((n) => n.close()));
|
|
2263
|
+
}
|
|
2264
|
+
async function ht() {
|
|
2265
|
+
const t = Array.from(P.keys());
|
|
2266
|
+
await Promise.all(t.map((e) => me(e)));
|
|
2267
|
+
}
|
|
2268
|
+
function ut(t, e) {
|
|
2269
|
+
const { React: r } = e, { createElement: n, useRef: i, useEffect: s, useState: o, forwardRef: a } = r, c = a(
|
|
2270
|
+
function(g, R) {
|
|
2271
|
+
const {
|
|
2272
|
+
onRendered: U,
|
|
2273
|
+
onError: O,
|
|
2274
|
+
onClose: L,
|
|
2275
|
+
context: ye,
|
|
2276
|
+
className: q,
|
|
2277
|
+
style: B,
|
|
2278
|
+
...x
|
|
2279
|
+
} = g, b = i(null), D = i(null), [j, ge] = o(null);
|
|
2280
|
+
return s(() => {
|
|
2281
|
+
const C = b.current;
|
|
2282
|
+
if (!C) return;
|
|
2283
|
+
const m = t(x);
|
|
2284
|
+
return D.current = m, U && m.event.once("rendered", U), L && m.event.once("close", L), O && m.event.on("error", O), m.render(C, ye).catch((H) => {
|
|
2285
|
+
ge(H), O?.(H);
|
|
2286
|
+
}), () => {
|
|
2287
|
+
m.close().catch(() => {
|
|
2288
|
+
}), D.current = null;
|
|
2289
|
+
};
|
|
2290
|
+
}, []), s(() => {
|
|
2291
|
+
const C = D.current;
|
|
2292
|
+
C && C.updateProps(x).catch((m) => {
|
|
2293
|
+
O?.(m);
|
|
2294
|
+
});
|
|
2295
|
+
}, [JSON.stringify(x)]), s(() => {
|
|
2296
|
+
R && typeof R == "object" && b.current && (R.current = b.current);
|
|
2297
|
+
}, [R]), j ? n(
|
|
2298
|
+
"div",
|
|
2299
|
+
{
|
|
2300
|
+
className: q,
|
|
2301
|
+
style: { color: "red", padding: "16px", ...B }
|
|
2302
|
+
},
|
|
2303
|
+
`Error: ${j.message}`
|
|
2304
|
+
) : n("div", {
|
|
2305
|
+
ref: b,
|
|
2306
|
+
className: q,
|
|
2307
|
+
style: {
|
|
2308
|
+
display: "inline-block",
|
|
2309
|
+
...B
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
), d = `ForgeFrame(${t.name || "Component"})`;
|
|
2314
|
+
return c.displayName = d, c;
|
|
2315
|
+
}
|
|
2316
|
+
function pt(t) {
|
|
2317
|
+
return function(r) {
|
|
2318
|
+
return ut(r, { React: t });
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
pe();
|
|
2322
|
+
const ft = {
|
|
2323
|
+
/**
|
|
2324
|
+
* Create a new component definition.
|
|
2325
|
+
*
|
|
2326
|
+
* @remarks
|
|
2327
|
+
* This is the main entry point for defining components. Returns a
|
|
2328
|
+
* component factory function that can be called to create instances.
|
|
2329
|
+
*
|
|
2330
|
+
* @example
|
|
2331
|
+
* ```typescript
|
|
2332
|
+
* const MyComponent = ForgeFrame.create({
|
|
2333
|
+
* tag: 'my-component',
|
|
2334
|
+
* url: 'https://example.com/component',
|
|
2335
|
+
* props: {
|
|
2336
|
+
* onLogin: { type: ForgeFrame.PROP_TYPE.FUNCTION },
|
|
2337
|
+
* },
|
|
2338
|
+
* });
|
|
2339
|
+
*
|
|
2340
|
+
* const instance = MyComponent({ onLogin: (user) => {} });
|
|
2341
|
+
* await instance.render('#container');
|
|
2342
|
+
* ```
|
|
2343
|
+
*/
|
|
2344
|
+
create: fe,
|
|
2345
|
+
/**
|
|
2346
|
+
* Destroy a single component instance.
|
|
2347
|
+
*
|
|
2348
|
+
* @param instance - The component instance to destroy
|
|
2349
|
+
*/
|
|
2350
|
+
destroy: dt,
|
|
2351
|
+
/**
|
|
2352
|
+
* Destroy all instances of a specific component by tag.
|
|
2353
|
+
*
|
|
2354
|
+
* @param tag - The component tag name
|
|
2355
|
+
*/
|
|
2356
|
+
destroyComponents: me,
|
|
2357
|
+
/**
|
|
2358
|
+
* Destroy all ForgeFrame component instances.
|
|
2359
|
+
*/
|
|
2360
|
+
destroyAll: ht,
|
|
2361
|
+
/**
|
|
2362
|
+
* Check if the current window is a child component context.
|
|
2363
|
+
*
|
|
2364
|
+
* @returns True if running inside a ForgeFrame iframe/popup
|
|
2365
|
+
*/
|
|
2366
|
+
isChild: ot,
|
|
2367
|
+
/**
|
|
2368
|
+
* Get xprops from the current child window.
|
|
2369
|
+
*
|
|
2370
|
+
* @returns The xprops object if in child context, undefined otherwise
|
|
2371
|
+
*/
|
|
2372
|
+
getXProps: at,
|
|
2373
|
+
/**
|
|
2374
|
+
* Prop type constants for defining component props.
|
|
2375
|
+
* @see {@link PROP_TYPE}
|
|
2376
|
+
*/
|
|
2377
|
+
PROP_TYPE: h,
|
|
2378
|
+
/**
|
|
2379
|
+
* Serialization strategy constants.
|
|
2380
|
+
* @see {@link PROP_SERIALIZATION}
|
|
2381
|
+
*/
|
|
2382
|
+
PROP_SERIALIZATION: I,
|
|
2383
|
+
/**
|
|
2384
|
+
* Rendering context constants (IFRAME, POPUP).
|
|
2385
|
+
* @see {@link CONTEXT}
|
|
2386
|
+
*/
|
|
2387
|
+
CONTEXT: f,
|
|
2388
|
+
/**
|
|
2389
|
+
* Lifecycle event name constants.
|
|
2390
|
+
* @see {@link EVENT}
|
|
2391
|
+
*/
|
|
2392
|
+
EVENT: p,
|
|
2393
|
+
/**
|
|
2394
|
+
* Error thrown when popup window fails to open.
|
|
2395
|
+
*/
|
|
2396
|
+
PopupOpenError: ue,
|
|
2397
|
+
/**
|
|
2398
|
+
* Current library version.
|
|
2399
|
+
*/
|
|
2400
|
+
VERSION: re
|
|
2401
|
+
};
|
|
2402
|
+
export {
|
|
2403
|
+
f as CONTEXT,
|
|
2404
|
+
p as EVENT,
|
|
2405
|
+
ft as ForgeFrame,
|
|
2406
|
+
I as PROP_SERIALIZATION,
|
|
2407
|
+
h as PROP_TYPE,
|
|
2408
|
+
ue as PopupOpenError,
|
|
2409
|
+
re as VERSION,
|
|
2410
|
+
fe as create,
|
|
2411
|
+
ut as createReactDriver,
|
|
2412
|
+
ft as default,
|
|
2413
|
+
dt as destroy,
|
|
2414
|
+
ht as destroyAll,
|
|
2415
|
+
me as destroyComponents,
|
|
2416
|
+
at as getXProps,
|
|
2417
|
+
ot as isChild,
|
|
2418
|
+
pt as withReactDriver
|
|
2419
|
+
};
|