forgeframe 0.0.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.
@@ -0,0 +1,3179 @@
1
+ const p = {
2
+ /** Render component in an iframe */
3
+ IFRAME: "iframe",
4
+ /** Render component in a popup window */
5
+ POPUP: "popup"
6
+ }, f = {
7
+ /** Emitted when rendering starts */
8
+ RENDER: "render",
9
+ /** Emitted when component is fully rendered and initialized */
10
+ RENDERED: "rendered",
11
+ /** Emitted when prerender (loading) phase starts */
12
+ PRERENDER: "prerender",
13
+ /** Emitted when prerender phase completes */
14
+ PRERENDERED: "prerendered",
15
+ /** Emitted when component becomes visible */
16
+ DISPLAY: "display",
17
+ /** Emitted when an error occurs */
18
+ ERROR: "error",
19
+ /** Emitted when component is closing */
20
+ CLOSE: "close",
21
+ /** Emitted when component is destroyed */
22
+ DESTROY: "destroy",
23
+ /** Emitted when props are updated */
24
+ PROPS: "props",
25
+ /** Emitted when component is resized */
26
+ RESIZE: "resize",
27
+ /** Emitted when component receives focus */
28
+ FOCUS: "focus"
29
+ }, I = {
30
+ /** Default JSON serialization */
31
+ JSON: "json",
32
+ /** Base64 encoding for binary or large data */
33
+ BASE64: "base64",
34
+ /** Dot notation for nested objects (e.g., "a.b.c=value") */
35
+ DOTIFY: "dotify"
36
+ }, D = {
37
+ /** Request message expecting a response */
38
+ REQUEST: "request",
39
+ /** Response to a previous request */
40
+ RESPONSE: "response"
41
+ }, u = {
42
+ /** Host initialization complete */
43
+ INIT: "forgeframe_init",
44
+ /** Props update from consumer to host */
45
+ PROPS: "forgeframe_props",
46
+ /** Close request from host */
47
+ CLOSE: "forgeframe_close",
48
+ /** Resize request from host */
49
+ RESIZE: "forgeframe_resize",
50
+ /** Focus request from host */
51
+ FOCUS: "forgeframe_focus",
52
+ /** Show request from host */
53
+ SHOW: "forgeframe_show",
54
+ /** Hide request from host */
55
+ HIDE: "forgeframe_hide",
56
+ /** Error report from host */
57
+ ERROR: "forgeframe_error",
58
+ /** Data export from host to consumer */
59
+ EXPORT: "forgeframe_export",
60
+ /** Cross-domain function call */
61
+ CALL: "forgeframe_call",
62
+ /** Consumer export from host context */
63
+ CONSUMER_EXPORT: "forgeframe_consumer_export",
64
+ /** Get sibling components request */
65
+ GET_SIBLINGS: "forgeframe_get_siblings"
66
+ }, N = "__forgeframe__", pe = "0.0.1";
67
+ class me {
68
+ /**
69
+ * Internal storage for event listeners mapped by event name.
70
+ * @internal
71
+ */
72
+ listeners = /* @__PURE__ */ new Map();
73
+ /**
74
+ * Subscribes a handler to a specific event.
75
+ *
76
+ * @typeParam T - The type of data expected by the event handler
77
+ * @param event - The name of the event to subscribe to
78
+ * @param handler - The callback function to invoke when the event is emitted
79
+ * @returns A function that, when called, unsubscribes the handler from the event
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const unsubscribe = emitter.on<{ userId: string }>('login', (data) => {
84
+ * console.log('User logged in:', data.userId);
85
+ * });
86
+ * ```
87
+ *
88
+ * @public
89
+ */
90
+ on(e, s) {
91
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(s), () => this.off(e, s);
92
+ }
93
+ /**
94
+ * Subscribes a handler to an event that will automatically unsubscribe after the first invocation.
95
+ *
96
+ * @typeParam T - The type of data expected by the event handler
97
+ * @param event - The name of the event to subscribe to
98
+ * @param handler - The callback function to invoke once when the event is emitted
99
+ * @returns A function that, when called, unsubscribes the handler before it fires
100
+ *
101
+ * @remarks
102
+ * This is useful for one-time event handling, such as waiting for an initialization
103
+ * event or a single response.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * emitter.once('ready', () => {
108
+ * console.log('Component is ready!');
109
+ * });
110
+ * ```
111
+ *
112
+ * @public
113
+ */
114
+ once(e, s) {
115
+ const n = (i) => (this.off(e, n), s(i));
116
+ return this.on(e, n);
117
+ }
118
+ /**
119
+ * Emits an event, invoking all registered handlers with the provided data.
120
+ *
121
+ * @typeParam T - The type of data to pass to event handlers
122
+ * @param event - The name of the event to emit
123
+ * @param data - Optional data to pass to all registered handlers
124
+ *
125
+ * @remarks
126
+ * Handlers are invoked synchronously in the order they were registered.
127
+ * If a handler throws an error, it is caught and logged to the console,
128
+ * allowing subsequent handlers to still execute.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * emitter.emit('userAction', { action: 'click', target: 'button' });
133
+ * ```
134
+ *
135
+ * @public
136
+ */
137
+ emit(e, s) {
138
+ const n = this.listeners.get(e);
139
+ if (n)
140
+ for (const i of n)
141
+ try {
142
+ const r = i(s);
143
+ r && typeof r == "object" && "catch" in r && typeof r.catch == "function" && r.catch((o) => {
144
+ console.error(`Error in async event handler for "${e}":`, o);
145
+ });
146
+ } catch (r) {
147
+ console.error(`Error in event handler for "${e}":`, r);
148
+ }
149
+ }
150
+ /**
151
+ * Unsubscribes a handler from an event, or removes all handlers for the event.
152
+ *
153
+ * @param event - The name of the event to unsubscribe from
154
+ * @param handler - The specific handler to remove. If not provided, all handlers for the event are removed.
155
+ *
156
+ * @remarks
157
+ * When a specific handler is removed and it was the last handler for that event,
158
+ * the event entry is cleaned up from the internal map.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * // Remove a specific handler
163
+ * emitter.off('message', myHandler);
164
+ *
165
+ * // Remove all handlers for an event
166
+ * emitter.off('message');
167
+ * ```
168
+ *
169
+ * @public
170
+ */
171
+ off(e, s) {
172
+ if (!s) {
173
+ this.listeners.delete(e);
174
+ return;
175
+ }
176
+ const n = this.listeners.get(e);
177
+ n && (n.delete(s), n.size === 0 && this.listeners.delete(e));
178
+ }
179
+ /**
180
+ * Removes all event listeners from the emitter.
181
+ *
182
+ * @remarks
183
+ * This method is typically called during component cleanup or disposal
184
+ * to ensure no memory leaks from lingering event subscriptions.
185
+ *
186
+ * @example
187
+ * ```typescript
188
+ * // Clean up all listeners when component is destroyed
189
+ * emitter.removeAllListeners();
190
+ * ```
191
+ *
192
+ * @public
193
+ */
194
+ removeAllListeners() {
195
+ this.listeners.clear();
196
+ }
197
+ /**
198
+ * Returns the number of listeners registered for a specific event.
199
+ *
200
+ * @param event - The name of the event to check
201
+ * @returns The number of handlers currently subscribed to the event
202
+ *
203
+ * @remarks
204
+ * This method is primarily useful for debugging and testing purposes
205
+ * to verify that subscriptions are being properly managed.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * console.log(`Active listeners: ${emitter.listenerCount('message')}`);
210
+ * ```
211
+ *
212
+ * @public
213
+ */
214
+ listenerCount(e) {
215
+ return this.listeners.get(e)?.size ?? 0;
216
+ }
217
+ }
218
+ function Ie() {
219
+ const t = Date.now().toString(36), e = Math.random().toString(36).slice(2, 11);
220
+ return `${t}_${e}`;
221
+ }
222
+ function W() {
223
+ return Math.random().toString(36).slice(2, 11);
224
+ }
225
+ class De {
226
+ /**
227
+ * Array of registered cleanup tasks awaiting execution.
228
+ * @internal
229
+ */
230
+ tasks = [];
231
+ /**
232
+ * Flag indicating whether cleanup has already been performed.
233
+ * @internal
234
+ */
235
+ cleaned = !1;
236
+ /**
237
+ * Registers a cleanup task to be executed when {@link cleanup} is called.
238
+ *
239
+ * @param task - The cleanup function to register
240
+ *
241
+ * @remarks
242
+ * If cleanup has already been performed, the task is executed immediately
243
+ * rather than being registered. This ensures late-registered tasks are
244
+ * still handled appropriately.
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * cleanup.register(() => {
249
+ * eventEmitter.removeAllListeners();
250
+ * });
251
+ *
252
+ * cleanup.register(async () => {
253
+ * await database.close();
254
+ * });
255
+ * ```
256
+ *
257
+ * @public
258
+ */
259
+ register(e) {
260
+ if (this.cleaned) {
261
+ try {
262
+ e();
263
+ } catch (s) {
264
+ console.error("Error in cleanup task:", s);
265
+ }
266
+ return;
267
+ }
268
+ this.tasks.push(e);
269
+ }
270
+ /**
271
+ * Executes all registered cleanup tasks in LIFO order.
272
+ *
273
+ * @returns A Promise that resolves when all cleanup tasks have completed
274
+ *
275
+ * @remarks
276
+ * Tasks are executed in reverse order of registration (LIFO pattern).
277
+ * Each task is awaited individually, and errors are caught and logged
278
+ * to prevent one failing task from blocking subsequent cleanup operations.
279
+ * Calling this method multiple times has no effect after the first call.
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // In a component's destroy lifecycle
284
+ * async destroy() {
285
+ * await this.cleanupManager.cleanup();
286
+ * }
287
+ * ```
288
+ *
289
+ * @public
290
+ */
291
+ async cleanup() {
292
+ if (this.cleaned) return;
293
+ this.cleaned = !0;
294
+ const e = this.tasks.reverse();
295
+ this.tasks = [];
296
+ for (const s of e)
297
+ try {
298
+ await s();
299
+ } catch (n) {
300
+ console.error("Error in cleanup task:", n);
301
+ }
302
+ }
303
+ /**
304
+ * Checks whether cleanup has already been performed.
305
+ *
306
+ * @returns `true` if {@link cleanup} has been called, `false` otherwise
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * if (!cleanupManager.isCleaned()) {
311
+ * // Safe to register more tasks
312
+ * cleanupManager.register(myTask);
313
+ * }
314
+ * ```
315
+ *
316
+ * @public
317
+ */
318
+ isCleaned() {
319
+ return this.cleaned;
320
+ }
321
+ /**
322
+ * Resets the manager to its initial state, allowing it to be reused.
323
+ *
324
+ * @remarks
325
+ * This method clears all registered tasks and resets the cleaned flag.
326
+ * It is primarily intended for testing scenarios or cases where the
327
+ * manager needs to be reused after cleanup.
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * // In a test teardown
332
+ * afterEach(() => {
333
+ * cleanupManager.reset();
334
+ * });
335
+ * ```
336
+ *
337
+ * @public
338
+ */
339
+ reset() {
340
+ this.tasks = [], this.cleaned = !1;
341
+ }
342
+ }
343
+ function ge() {
344
+ let t, e;
345
+ return { promise: new Promise((n, i) => {
346
+ t = n, e = i;
347
+ }), resolve: t, reject: e };
348
+ }
349
+ function Ne(t, e, s = "Operation timed out") {
350
+ return new Promise((n, i) => {
351
+ const r = setTimeout(() => {
352
+ i(new Error(`${s} (${e}ms)`));
353
+ }, e);
354
+ t.then((o) => {
355
+ clearTimeout(r), n(o);
356
+ }).catch((o) => {
357
+ clearTimeout(r), i(o);
358
+ });
359
+ });
360
+ }
361
+ const z = "forgeframe:";
362
+ function A(t) {
363
+ return z + JSON.stringify(t);
364
+ }
365
+ function Te(t) {
366
+ if (typeof t != "string" || !t.startsWith(z)) return null;
367
+ try {
368
+ const e = t.slice(z.length), s = JSON.parse(e);
369
+ return !s.id || !s.type || !s.name || !s.source ? null : s;
370
+ } catch {
371
+ return null;
372
+ }
373
+ }
374
+ function re(t, e, s, n) {
375
+ return {
376
+ id: t,
377
+ type: D.REQUEST,
378
+ name: e,
379
+ data: s,
380
+ source: n
381
+ };
382
+ }
383
+ function ke(t, e, s, n) {
384
+ return {
385
+ id: t,
386
+ type: D.RESPONSE,
387
+ name: "response",
388
+ data: e,
389
+ source: s,
390
+ error: n ? {
391
+ message: n.message,
392
+ stack: n.stack
393
+ } : void 0
394
+ };
395
+ }
396
+ class ye {
397
+ /**
398
+ * Creates a new Messenger instance.
399
+ *
400
+ * @param uid - Unique identifier for this messenger
401
+ * @param win - The window to listen for messages on
402
+ * @param domain - The origin domain of this messenger
403
+ * @param trustedDomains - Optional domains to trust for incoming messages
404
+ */
405
+ constructor(e, s = window, n = window.location.origin, i) {
406
+ this.uid = e, this.win = s, this.domain = n, this.allowedOrigins.add(n), i && this.addTrustedDomain(i), this.setupListener();
407
+ }
408
+ /** @internal */
409
+ pending = /* @__PURE__ */ new Map();
410
+ /** @internal */
411
+ handlers = /* @__PURE__ */ new Map();
412
+ /** @internal */
413
+ listener = null;
414
+ /** @internal */
415
+ destroyed = !1;
416
+ /** @internal */
417
+ allowedOrigins = /* @__PURE__ */ new Set();
418
+ /** @internal */
419
+ allowedOriginPatterns = [];
420
+ /**
421
+ * Adds a trusted domain that can send messages to this messenger.
422
+ *
423
+ * @param domain - Domain pattern to trust (string, RegExp, or array)
424
+ */
425
+ addTrustedDomain(e) {
426
+ if (Array.isArray(e))
427
+ for (const s of e)
428
+ this.allowedOrigins.add(s);
429
+ else e instanceof RegExp ? this.allowedOriginPatterns.push(e) : this.allowedOrigins.add(e);
430
+ }
431
+ /**
432
+ * Checks if an origin is trusted.
433
+ *
434
+ * @param origin - The origin to check
435
+ * @returns True if the origin is trusted
436
+ * @internal
437
+ */
438
+ isOriginTrusted(e) {
439
+ if (this.allowedOrigins.has(e))
440
+ return !0;
441
+ for (const s of this.allowedOriginPatterns)
442
+ if (s.test(e))
443
+ return !0;
444
+ return !1;
445
+ }
446
+ /**
447
+ * Sends a message and waits for a response.
448
+ *
449
+ * @typeParam T - The data type being sent
450
+ * @typeParam R - The expected response type
451
+ * @param targetWin - The target window to send to
452
+ * @param targetDomain - The target origin domain
453
+ * @param name - The message name/type
454
+ * @param data - Optional data payload
455
+ * @param timeout - Timeout in milliseconds (default: 10000)
456
+ * @returns Promise resolving to the response data
457
+ * @throws Error if messenger is destroyed or timeout occurs
458
+ */
459
+ async send(e, s, n, i, r = 1e4) {
460
+ if (this.destroyed)
461
+ throw new Error("Messenger has been destroyed");
462
+ const o = W(), a = re(o, n, i, {
463
+ uid: this.uid,
464
+ domain: this.domain
465
+ }), c = ge(), l = setTimeout(() => {
466
+ this.pending.delete(o), c.reject(new Error(`Message "${n}" timed out after ${r}ms`));
467
+ }, r);
468
+ this.pending.set(o, {
469
+ deferred: c,
470
+ timeout: l
471
+ });
472
+ try {
473
+ e.postMessage(A(a), s);
474
+ } catch (h) {
475
+ throw this.pending.delete(o), clearTimeout(l), h;
476
+ }
477
+ return c.promise;
478
+ }
479
+ /**
480
+ * Sends a one-way message without waiting for a response.
481
+ *
482
+ * @typeParam T - The data type being sent
483
+ * @param targetWin - The target window to send to
484
+ * @param targetDomain - The target origin domain
485
+ * @param name - The message name/type
486
+ * @param data - Optional data payload
487
+ * @throws Error if messenger is destroyed
488
+ */
489
+ post(e, s, n, i) {
490
+ if (this.destroyed)
491
+ throw new Error("Messenger has been destroyed");
492
+ const r = W(), o = re(r, n, i, {
493
+ uid: this.uid,
494
+ domain: this.domain
495
+ });
496
+ e.postMessage(A(o), s);
497
+ }
498
+ /**
499
+ * Registers a handler for incoming messages of a specific type.
500
+ *
501
+ * @typeParam T - The expected data type of incoming messages
502
+ * @typeParam R - The return type of the handler
503
+ * @param name - The message name/type to handle
504
+ * @param handler - The handler function
505
+ * @returns Function to unregister the handler
506
+ */
507
+ on(e, s) {
508
+ return this.handlers.set(e, s), () => this.handlers.delete(e);
509
+ }
510
+ /**
511
+ * Sets up the postMessage event listener.
512
+ * @internal
513
+ */
514
+ setupListener() {
515
+ this.listener = (e) => {
516
+ if (e.source === this.win || !this.isOriginTrusted(e.origin))
517
+ return;
518
+ const s = Te(e.data);
519
+ s && this.handleMessage(s, e.source, e.origin);
520
+ }, this.win.addEventListener("message", this.listener);
521
+ }
522
+ /**
523
+ * Processes a received message.
524
+ * @internal
525
+ */
526
+ async handleMessage(e, s, n) {
527
+ if (e.type === D.RESPONSE) {
528
+ const i = this.pending.get(e.id);
529
+ if (i)
530
+ if (this.pending.delete(e.id), clearTimeout(i.timeout), e.error) {
531
+ const r = new Error(e.error.message);
532
+ r.stack = e.error.stack, i.deferred.reject(r);
533
+ } else
534
+ i.deferred.resolve(e.data);
535
+ return;
536
+ }
537
+ if (e.type === D.REQUEST) {
538
+ const i = this.handlers.get(e.name);
539
+ if (!i)
540
+ return;
541
+ let r, o;
542
+ try {
543
+ r = await i(e.data, e.source);
544
+ } catch (c) {
545
+ o = c instanceof Error ? c : new Error(String(c));
546
+ }
547
+ const a = ke(
548
+ e.id,
549
+ r,
550
+ { uid: this.uid, domain: this.domain },
551
+ o
552
+ );
553
+ try {
554
+ s.postMessage(A(a), n);
555
+ } catch {
556
+ }
557
+ }
558
+ }
559
+ /**
560
+ * Cleans up the messenger and releases resources.
561
+ *
562
+ * @remarks
563
+ * Removes the message listener, rejects all pending requests,
564
+ * and clears all handlers.
565
+ */
566
+ destroy() {
567
+ if (!this.destroyed) {
568
+ this.destroyed = !0, this.listener && (this.win.removeEventListener("message", this.listener), this.listener = null);
569
+ for (const e of this.pending.values())
570
+ clearTimeout(e.timeout), e.deferred.reject(new Error("Messenger destroyed"));
571
+ this.pending.clear(), this.handlers.clear();
572
+ }
573
+ }
574
+ /**
575
+ * Checks if the messenger has been destroyed.
576
+ *
577
+ * @returns True if destroy() has been called
578
+ */
579
+ isDestroyed() {
580
+ return this.destroyed;
581
+ }
582
+ }
583
+ const oe = 500;
584
+ class B {
585
+ /**
586
+ * Creates a new FunctionBridge instance.
587
+ *
588
+ * @param messenger - The messenger to use for cross-domain calls
589
+ */
590
+ constructor(e) {
591
+ this.messenger = e, this.setupCallHandler();
592
+ }
593
+ /** @internal */
594
+ localFunctions = /* @__PURE__ */ new Map();
595
+ /** @internal */
596
+ remoteFunctions = /* @__PURE__ */ new Map();
597
+ /**
598
+ * Tracks function IDs from the current serialization batch.
599
+ * Used for cleanup of stale references when props are updated.
600
+ * @internal
601
+ */
602
+ currentBatchIds = /* @__PURE__ */ new Set();
603
+ /**
604
+ * Serializes a local function to a transferable reference.
605
+ *
606
+ * @param fn - The function to serialize
607
+ * @param name - Optional name for debugging
608
+ * @returns A function reference that can be sent across domains
609
+ */
610
+ serialize(e, s) {
611
+ if (this.localFunctions.size >= oe) {
612
+ const i = this.localFunctions.keys().next().value;
613
+ i && this.localFunctions.delete(i);
614
+ }
615
+ const n = W();
616
+ return this.localFunctions.set(n, e), this.currentBatchIds.add(n), {
617
+ __type__: "function",
618
+ __id__: n,
619
+ __name__: s || e.name || "anonymous"
620
+ };
621
+ }
622
+ /**
623
+ * Deserializes a function reference to a callable wrapper.
624
+ *
625
+ * @remarks
626
+ * The returned function, when called, will invoke the original function
627
+ * in the remote window via postMessage and return the result.
628
+ *
629
+ * @param ref - The function reference to deserialize
630
+ * @param targetWin - The window containing the original function
631
+ * @param targetDomain - The origin of the target window
632
+ * @returns A callable wrapper function
633
+ */
634
+ deserialize(e, s, n) {
635
+ const i = `${e.__id__}`, r = this.remoteFunctions.get(i);
636
+ if (r) return r;
637
+ if (this.remoteFunctions.size >= oe) {
638
+ const a = this.remoteFunctions.keys().next().value;
639
+ a && this.remoteFunctions.delete(a);
640
+ }
641
+ const o = async (...a) => this.messenger.send(s, n, u.CALL, {
642
+ id: e.__id__,
643
+ args: a
644
+ });
645
+ return Object.defineProperty(o, "name", {
646
+ value: e.__name__,
647
+ configurable: !0
648
+ }), this.remoteFunctions.set(i, o), o;
649
+ }
650
+ /**
651
+ * Type guard to check if a value is a function reference.
652
+ *
653
+ * @param value - The value to check
654
+ * @returns True if the value is a FunctionRef
655
+ */
656
+ static isFunctionRef(e) {
657
+ return typeof e == "object" && e !== null && e.__type__ === "function" && typeof e.__id__ == "string";
658
+ }
659
+ /**
660
+ * Sets up the handler for incoming function call messages.
661
+ * @internal
662
+ */
663
+ setupCallHandler() {
664
+ this.messenger.on(
665
+ u.CALL,
666
+ async ({ id: e, args: s }) => {
667
+ const n = this.localFunctions.get(e);
668
+ if (!n)
669
+ throw new Error(`Function with id "${e}" not found`);
670
+ return n(...s);
671
+ }
672
+ );
673
+ }
674
+ /**
675
+ * Removes a local function reference.
676
+ *
677
+ * @param id - The function reference ID to remove
678
+ */
679
+ removeLocal(e) {
680
+ this.localFunctions.delete(e);
681
+ }
682
+ /**
683
+ * Starts a new serialization batch.
684
+ *
685
+ * @remarks
686
+ * Call this before serializing a new set of props. After serialization,
687
+ * call {@link finishBatch} to clean up functions from previous batches.
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * bridge.startBatch();
692
+ * const serialized = serializeFunctions(props, bridge);
693
+ * bridge.finishBatch();
694
+ * ```
695
+ */
696
+ startBatch() {
697
+ this.currentBatchIds.clear();
698
+ }
699
+ /**
700
+ * Finishes the current batch and removes functions not in this batch.
701
+ *
702
+ * @remarks
703
+ * This cleans up function references from previous prop updates that
704
+ * are no longer needed, preventing memory leaks.
705
+ *
706
+ * @param keepPrevious - If true, keeps previous batch functions (default: false)
707
+ */
708
+ finishBatch(e = !1) {
709
+ if (e) {
710
+ this.currentBatchIds.clear();
711
+ return;
712
+ }
713
+ for (const s of this.localFunctions.keys())
714
+ this.currentBatchIds.has(s) || this.localFunctions.delete(s);
715
+ this.currentBatchIds.clear();
716
+ }
717
+ /**
718
+ * Clears all remote function references.
719
+ *
720
+ * @remarks
721
+ * Call this when the remote window is no longer accessible
722
+ * (e.g., closed or navigated away).
723
+ */
724
+ clearRemote() {
725
+ this.remoteFunctions.clear();
726
+ }
727
+ /**
728
+ * Returns the current number of registered local functions.
729
+ * Useful for debugging and monitoring.
730
+ */
731
+ get localFunctionCount() {
732
+ return this.localFunctions.size;
733
+ }
734
+ /**
735
+ * Returns the current number of cached remote functions.
736
+ * Useful for debugging and monitoring.
737
+ */
738
+ get remoteFunctionCount() {
739
+ return this.remoteFunctions.size;
740
+ }
741
+ /**
742
+ * Cleans up all function references.
743
+ */
744
+ destroy() {
745
+ this.localFunctions.clear(), this.remoteFunctions.clear(), this.currentBatchIds.clear();
746
+ }
747
+ }
748
+ function M(t, e, s = /* @__PURE__ */ new WeakSet()) {
749
+ if (typeof t == "function")
750
+ return e.serialize(t);
751
+ if (Array.isArray(t)) {
752
+ if (s.has(t))
753
+ throw new Error("Circular reference detected in props - arrays cannot contain circular references");
754
+ return s.add(t), t.map((n) => M(n, e, s));
755
+ }
756
+ if (typeof t == "object" && t !== null) {
757
+ if (s.has(t))
758
+ throw new Error("Circular reference detected in props - objects cannot contain circular references");
759
+ s.add(t);
760
+ const n = {};
761
+ for (const [i, r] of Object.entries(t))
762
+ n[i] = M(r, e, s);
763
+ return n;
764
+ }
765
+ return t;
766
+ }
767
+ function U(t, e, s, n, i = /* @__PURE__ */ new WeakSet()) {
768
+ if (B.isFunctionRef(t))
769
+ return e.deserialize(t, s, n);
770
+ if (Array.isArray(t)) {
771
+ if (i.has(t))
772
+ throw new Error("Circular reference detected in serialized props");
773
+ return i.add(t), t.map(
774
+ (r) => U(r, e, s, n, i)
775
+ );
776
+ }
777
+ if (typeof t == "object" && t !== null) {
778
+ if (i.has(t))
779
+ throw new Error("Circular reference detected in serialized props");
780
+ i.add(t);
781
+ const r = {};
782
+ for (const [o, a] of Object.entries(t))
783
+ r[o] = U(a, e, s, n, i);
784
+ return r;
785
+ }
786
+ return t;
787
+ }
788
+ function j(t = window) {
789
+ try {
790
+ return t.location.origin;
791
+ } catch {
792
+ return "";
793
+ }
794
+ }
795
+ function _e(t, e = window) {
796
+ try {
797
+ return t.location.origin === e.location.origin;
798
+ } catch {
799
+ return !1;
800
+ }
801
+ }
802
+ function we(t, e) {
803
+ return typeof t == "string" ? t === "*" ? !0 : t === e : t instanceof RegExp ? t.test(e) : Array.isArray(t) ? t.some((s) => we(s, e)) : !1;
804
+ }
805
+ function Ee(t) {
806
+ if (!t) return !0;
807
+ try {
808
+ return t.closed;
809
+ } catch {
810
+ return !0;
811
+ }
812
+ }
813
+ function $e(t = window) {
814
+ try {
815
+ return t.opener;
816
+ } catch {
817
+ return null;
818
+ }
819
+ }
820
+ function Fe(t = window) {
821
+ try {
822
+ const e = t.parent;
823
+ return e && e !== t ? e : null;
824
+ } catch {
825
+ return null;
826
+ }
827
+ }
828
+ function Le(t = window) {
829
+ try {
830
+ return t.parent !== t;
831
+ } catch {
832
+ return !0;
833
+ }
834
+ }
835
+ function Ae(t = window) {
836
+ try {
837
+ return t.opener !== null && t.opener !== void 0;
838
+ } catch {
839
+ return !1;
840
+ }
841
+ }
842
+ const ae = 32 * 1024;
843
+ function He(t) {
844
+ const e = We(t);
845
+ return `${N}${e}`;
846
+ }
847
+ function be(t) {
848
+ if (!t || !t.startsWith(N))
849
+ return null;
850
+ const e = t.slice(N.length);
851
+ return ze(e);
852
+ }
853
+ function J(t = window) {
854
+ try {
855
+ return t.name.startsWith(N);
856
+ } catch {
857
+ return !1;
858
+ }
859
+ }
860
+ function H(t, e = window) {
861
+ return be(e.name)?.tag === t;
862
+ }
863
+ function We(t) {
864
+ try {
865
+ const e = JSON.stringify(t), s = btoa(encodeURIComponent(e)), n = new Blob([s]).size;
866
+ if (n > ae)
867
+ throw new Error(
868
+ `Payload size (${Math.round(n / 1024)}KB) exceeds maximum allowed size (${ae / 1024}KB). Consider reducing the amount of data passed via props.`
869
+ );
870
+ return s;
871
+ } catch (e) {
872
+ throw e instanceof Error && e.message.includes("Payload size") ? e : new Error(`Failed to encode payload: ${e}`);
873
+ }
874
+ }
875
+ function ze(t) {
876
+ try {
877
+ const e = decodeURIComponent(atob(t));
878
+ return JSON.parse(e);
879
+ } catch {
880
+ return null;
881
+ }
882
+ }
883
+ function Me(t) {
884
+ return {
885
+ uid: t.uid,
886
+ tag: t.tag,
887
+ version: pe,
888
+ context: t.context,
889
+ consumerDomain: t.consumerDomain,
890
+ props: t.props,
891
+ exports: t.exports,
892
+ children: t.children
893
+ };
894
+ }
895
+ function Ue(t = window) {
896
+ return be(t.name);
897
+ }
898
+ const ce = 100, w = /* @__PURE__ */ new Map();
899
+ function je() {
900
+ const t = [];
901
+ for (const [e, s] of w.entries())
902
+ Ee(s) && t.push(e);
903
+ for (const e of t)
904
+ w.delete(e);
905
+ }
906
+ function Be(t, e) {
907
+ if (w.size >= ce && je(), w.size >= ce) {
908
+ const s = w.keys().next().value;
909
+ s && w.delete(s);
910
+ }
911
+ w.set(t, e);
912
+ }
913
+ function Je(t) {
914
+ w.delete(t);
915
+ }
916
+ class m {
917
+ /** @internal */
918
+ _optional = !1;
919
+ /** @internal */
920
+ _nullable = !1;
921
+ /** @internal */
922
+ _default;
923
+ /**
924
+ * StandardSchemaV1 implementation.
925
+ * @internal
926
+ */
927
+ "~standard" = {
928
+ version: 1,
929
+ vendor: "forgeframe",
930
+ validate: (e) => e === null ? this._nullable ? { value: null } : { issues: [{ message: "Expected a value, got null" }] } : e === void 0 ? this._default !== void 0 ? { value: typeof this._default == "function" ? this._default() : this._default } : this._optional ? { value: void 0 } : { issues: [{ message: "Required" }] } : this._validate(e)
931
+ };
932
+ /**
933
+ * Marks this prop as optional.
934
+ *
935
+ * @returns Schema that accepts undefined
936
+ *
937
+ * @example
938
+ * ```typescript
939
+ * props: {
940
+ * nickname: prop.string().optional(),
941
+ * }
942
+ * ```
943
+ */
944
+ optional() {
945
+ const e = this._clone();
946
+ return e._optional = !0, e;
947
+ }
948
+ /**
949
+ * Marks this prop as nullable (accepts null).
950
+ *
951
+ * @returns Schema that accepts null
952
+ *
953
+ * @example
954
+ * ```typescript
955
+ * props: {
956
+ * middleName: prop.string().nullable(),
957
+ * }
958
+ * ```
959
+ */
960
+ nullable() {
961
+ const e = this._clone();
962
+ return e._nullable = !0, e;
963
+ }
964
+ /**
965
+ * Sets a default value for this prop.
966
+ *
967
+ * @param value - Default value or function returning default
968
+ * @returns Schema with default value
969
+ *
970
+ * @example
971
+ * ```typescript
972
+ * props: {
973
+ * count: prop.number().default(0),
974
+ * id: prop.string().default(() => crypto.randomUUID()),
975
+ * }
976
+ * ```
977
+ */
978
+ default(e) {
979
+ const s = this._clone();
980
+ return s._default = e, s;
981
+ }
982
+ }
983
+ class V extends m {
984
+ /** @internal */
985
+ _minLength;
986
+ /** @internal */
987
+ _maxLength;
988
+ /** @internal */
989
+ _pattern;
990
+ /** @internal */
991
+ _patternMessage;
992
+ /** @internal */
993
+ _trim = !1;
994
+ /** @internal */
995
+ _validate(e) {
996
+ if (typeof e != "string")
997
+ return {
998
+ issues: [{ message: `Expected string, got ${typeof e}` }]
999
+ };
1000
+ const s = this._trim ? e.trim() : e;
1001
+ return this._minLength !== void 0 && s.length < this._minLength ? {
1002
+ issues: [
1003
+ { message: `String must be at least ${this._minLength} characters` }
1004
+ ]
1005
+ } : this._maxLength !== void 0 && s.length > this._maxLength ? {
1006
+ issues: [
1007
+ { message: `String must be at most ${this._maxLength} characters` }
1008
+ ]
1009
+ } : this._pattern && !this._pattern.test(s) ? {
1010
+ issues: [
1011
+ {
1012
+ message: this._patternMessage || `String must match pattern ${this._pattern}`
1013
+ }
1014
+ ]
1015
+ } : { value: s };
1016
+ }
1017
+ /** @internal */
1018
+ _clone() {
1019
+ const e = new V();
1020
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e._minLength = this._minLength, e._maxLength = this._maxLength, e._pattern = this._pattern, e._patternMessage = this._patternMessage, e._trim = this._trim, e;
1021
+ }
1022
+ /**
1023
+ * Requires minimum string length.
1024
+ *
1025
+ * @param length - Minimum number of characters
1026
+ *
1027
+ * @example
1028
+ * ```typescript
1029
+ * name: prop.string().min(2)
1030
+ * ```
1031
+ */
1032
+ min(e) {
1033
+ const s = this._clone();
1034
+ return s._minLength = e, s;
1035
+ }
1036
+ /**
1037
+ * Requires maximum string length.
1038
+ *
1039
+ * @param length - Maximum number of characters
1040
+ *
1041
+ * @example
1042
+ * ```typescript
1043
+ * bio: prop.string().max(500)
1044
+ * ```
1045
+ */
1046
+ max(e) {
1047
+ const s = this._clone();
1048
+ return s._maxLength = e, s;
1049
+ }
1050
+ /**
1051
+ * Requires exact string length.
1052
+ *
1053
+ * @param length - Exact number of characters required
1054
+ *
1055
+ * @example
1056
+ * ```typescript
1057
+ * code: prop.string().length(6)
1058
+ * ```
1059
+ */
1060
+ length(e) {
1061
+ const s = this._clone();
1062
+ return s._minLength = e, s._maxLength = e, s;
1063
+ }
1064
+ /**
1065
+ * Requires string to match a regex pattern.
1066
+ *
1067
+ * @param regex - Pattern to match
1068
+ * @param message - Optional custom error message
1069
+ *
1070
+ * @example
1071
+ * ```typescript
1072
+ * slug: prop.string().pattern(/^[a-z0-9-]+$/, 'Invalid slug format')
1073
+ * ```
1074
+ */
1075
+ pattern(e, s) {
1076
+ const n = this._clone();
1077
+ return n._pattern = e, n._patternMessage = s, n;
1078
+ }
1079
+ /**
1080
+ * Validates as email address.
1081
+ *
1082
+ * @example
1083
+ * ```typescript
1084
+ * email: prop.string().email()
1085
+ * ```
1086
+ */
1087
+ email() {
1088
+ return this.pattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, "Invalid email address");
1089
+ }
1090
+ /**
1091
+ * Validates as URL.
1092
+ *
1093
+ * @example
1094
+ * ```typescript
1095
+ * website: prop.string().url()
1096
+ * ```
1097
+ */
1098
+ url() {
1099
+ return this.pattern(/^https?:\/\/.+/, "Invalid URL");
1100
+ }
1101
+ /**
1102
+ * Validates as UUID.
1103
+ *
1104
+ * @example
1105
+ * ```typescript
1106
+ * id: prop.string().uuid()
1107
+ * ```
1108
+ */
1109
+ uuid() {
1110
+ return this.pattern(
1111
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
1112
+ "Invalid UUID"
1113
+ );
1114
+ }
1115
+ /**
1116
+ * Trims whitespace from both ends of the string.
1117
+ *
1118
+ * @remarks
1119
+ * The trimmed value is used for validation and returned as the result.
1120
+ *
1121
+ * @example
1122
+ * ```typescript
1123
+ * name: prop.string().trim()
1124
+ * username: prop.string().trim().min(3)
1125
+ * ```
1126
+ */
1127
+ trim() {
1128
+ const e = this._clone();
1129
+ return e._trim = !0, e;
1130
+ }
1131
+ /**
1132
+ * Requires non-empty string (at least 1 character).
1133
+ *
1134
+ * @example
1135
+ * ```typescript
1136
+ * title: prop.string().nonempty()
1137
+ * ```
1138
+ */
1139
+ nonempty() {
1140
+ const e = this._clone();
1141
+ return e._minLength = 1, e;
1142
+ }
1143
+ }
1144
+ class q extends m {
1145
+ /** @internal */
1146
+ _min;
1147
+ /** @internal */
1148
+ _max;
1149
+ /** @internal */
1150
+ _int = !1;
1151
+ /** @internal */
1152
+ _validate(e) {
1153
+ return typeof e != "number" || Number.isNaN(e) ? {
1154
+ issues: [{ message: `Expected number, got ${typeof e}` }]
1155
+ } : this._int && !Number.isInteger(e) ? { issues: [{ message: "Expected integer" }] } : this._min !== void 0 && e < this._min ? { issues: [{ message: `Number must be >= ${this._min}` }] } : this._max !== void 0 && e > this._max ? { issues: [{ message: `Number must be <= ${this._max}` }] } : { value: e };
1156
+ }
1157
+ /** @internal */
1158
+ _clone() {
1159
+ const e = new q();
1160
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e._min = this._min, e._max = this._max, e._int = this._int, e;
1161
+ }
1162
+ /**
1163
+ * Requires minimum value.
1164
+ *
1165
+ * @param n - Minimum value (inclusive)
1166
+ *
1167
+ * @example
1168
+ * ```typescript
1169
+ * age: prop.number().min(0)
1170
+ * ```
1171
+ */
1172
+ min(e) {
1173
+ const s = this._clone();
1174
+ return s._min = e, s;
1175
+ }
1176
+ /**
1177
+ * Requires maximum value.
1178
+ *
1179
+ * @param n - Maximum value (inclusive)
1180
+ *
1181
+ * @example
1182
+ * ```typescript
1183
+ * rating: prop.number().max(5)
1184
+ * ```
1185
+ */
1186
+ max(e) {
1187
+ const s = this._clone();
1188
+ return s._max = e, s;
1189
+ }
1190
+ /**
1191
+ * Requires integer value.
1192
+ *
1193
+ * @example
1194
+ * ```typescript
1195
+ * count: prop.number().int()
1196
+ * ```
1197
+ */
1198
+ int() {
1199
+ const e = this._clone();
1200
+ return e._int = !0, e;
1201
+ }
1202
+ /**
1203
+ * Requires positive number (> 0).
1204
+ *
1205
+ * @example
1206
+ * ```typescript
1207
+ * price: prop.number().positive()
1208
+ * ```
1209
+ */
1210
+ positive() {
1211
+ const e = this._clone();
1212
+ return e._min = Number.MIN_VALUE, e;
1213
+ }
1214
+ /**
1215
+ * Requires non-negative number (>= 0).
1216
+ *
1217
+ * @example
1218
+ * ```typescript
1219
+ * quantity: prop.number().nonnegative()
1220
+ * ```
1221
+ */
1222
+ nonnegative() {
1223
+ const e = this._clone();
1224
+ return e._min = 0, e;
1225
+ }
1226
+ /**
1227
+ * Requires negative number (< 0).
1228
+ *
1229
+ * @example
1230
+ * ```typescript
1231
+ * debt: prop.number().negative()
1232
+ * ```
1233
+ */
1234
+ negative() {
1235
+ const e = this._clone();
1236
+ return e._max = -Number.MIN_VALUE, e;
1237
+ }
1238
+ }
1239
+ class X extends m {
1240
+ /** @internal */
1241
+ _validate(e) {
1242
+ return typeof e != "boolean" ? {
1243
+ issues: [{ message: `Expected boolean, got ${typeof e}` }]
1244
+ } : { value: e };
1245
+ }
1246
+ /** @internal */
1247
+ _clone() {
1248
+ const e = new X();
1249
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e;
1250
+ }
1251
+ }
1252
+ class Y extends m {
1253
+ /** @internal */
1254
+ _validate(e) {
1255
+ return typeof e != "function" ? {
1256
+ issues: [{ message: `Expected function, got ${typeof e}` }]
1257
+ } : { value: e };
1258
+ }
1259
+ /** @internal */
1260
+ _clone() {
1261
+ const e = new Y();
1262
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e;
1263
+ }
1264
+ }
1265
+ class T extends m {
1266
+ /** @internal */
1267
+ _itemSchema;
1268
+ /** @internal */
1269
+ _minLength;
1270
+ /** @internal */
1271
+ _maxLength;
1272
+ /** @internal */
1273
+ _validate(e) {
1274
+ if (!Array.isArray(e))
1275
+ return {
1276
+ issues: [{ message: `Expected array, got ${typeof e}` }]
1277
+ };
1278
+ if (this._minLength !== void 0 && e.length < this._minLength)
1279
+ return {
1280
+ issues: [
1281
+ { message: `Array must have at least ${this._minLength} items` }
1282
+ ]
1283
+ };
1284
+ if (this._maxLength !== void 0 && e.length > this._maxLength)
1285
+ return {
1286
+ issues: [
1287
+ { message: `Array must have at most ${this._maxLength} items` }
1288
+ ]
1289
+ };
1290
+ if (this._itemSchema) {
1291
+ const s = [];
1292
+ for (let n = 0; n < e.length; n++) {
1293
+ const i = this._itemSchema["~standard"].validate(e[n]);
1294
+ if (i instanceof Promise)
1295
+ throw new Error(
1296
+ "Async schema validation is not supported. Use synchronous schemas."
1297
+ );
1298
+ if (i.issues)
1299
+ return {
1300
+ issues: i.issues.map((r) => ({
1301
+ ...r,
1302
+ path: [n, ...r.path || []]
1303
+ }))
1304
+ };
1305
+ s.push(i.value);
1306
+ }
1307
+ return { value: s };
1308
+ }
1309
+ return { value: e };
1310
+ }
1311
+ /** @internal */
1312
+ _clone() {
1313
+ const e = new T();
1314
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e._itemSchema = this._itemSchema, e._minLength = this._minLength, e._maxLength = this._maxLength, e;
1315
+ }
1316
+ /**
1317
+ * Specifies the schema for array items.
1318
+ *
1319
+ * @typeParam U - Item type
1320
+ * @param schema - Schema for validating each item
1321
+ *
1322
+ * @example
1323
+ * ```typescript
1324
+ * tags: prop.array().of(prop.string())
1325
+ * scores: prop.array().of(prop.number().min(0).max(100))
1326
+ * ```
1327
+ */
1328
+ of(e) {
1329
+ const s = new T();
1330
+ return s._optional = this._optional, s._nullable = this._nullable, s._itemSchema = e, s._minLength = this._minLength, s._maxLength = this._maxLength, s;
1331
+ }
1332
+ /**
1333
+ * Requires minimum array length.
1334
+ *
1335
+ * @param length - Minimum number of items
1336
+ *
1337
+ * @example
1338
+ * ```typescript
1339
+ * items: prop.array().min(1)
1340
+ * ```
1341
+ */
1342
+ min(e) {
1343
+ const s = this._clone();
1344
+ return s._minLength = e, s;
1345
+ }
1346
+ /**
1347
+ * Requires maximum array length.
1348
+ *
1349
+ * @param length - Maximum number of items
1350
+ *
1351
+ * @example
1352
+ * ```typescript
1353
+ * selections: prop.array().max(5)
1354
+ * ```
1355
+ */
1356
+ max(e) {
1357
+ const s = this._clone();
1358
+ return s._maxLength = e, s;
1359
+ }
1360
+ /**
1361
+ * Requires non-empty array.
1362
+ *
1363
+ * @example
1364
+ * ```typescript
1365
+ * options: prop.array().nonempty()
1366
+ * ```
1367
+ */
1368
+ nonempty() {
1369
+ return this.min(1);
1370
+ }
1371
+ }
1372
+ class k extends m {
1373
+ /** @internal */
1374
+ _shape;
1375
+ /** @internal */
1376
+ _strict = !1;
1377
+ /** @internal */
1378
+ _validate(e) {
1379
+ if (typeof e != "object" || e === null || Array.isArray(e))
1380
+ return {
1381
+ issues: [
1382
+ {
1383
+ message: `Expected object, got ${Array.isArray(e) ? "array" : typeof e}`
1384
+ }
1385
+ ]
1386
+ };
1387
+ const s = e, n = {};
1388
+ if (this._shape) {
1389
+ if (this._strict) {
1390
+ const i = new Set(Object.keys(this._shape));
1391
+ for (const r of Object.keys(s))
1392
+ if (!i.has(r))
1393
+ return {
1394
+ issues: [{ message: `Unknown key: ${r}`, path: [r] }]
1395
+ };
1396
+ }
1397
+ for (const [i, r] of Object.entries(this._shape)) {
1398
+ const o = r["~standard"].validate(s[i]);
1399
+ if (o instanceof Promise)
1400
+ throw new Error(
1401
+ "Async schema validation is not supported. Use synchronous schemas."
1402
+ );
1403
+ if (o.issues)
1404
+ return {
1405
+ issues: o.issues.map((a) => ({
1406
+ ...a,
1407
+ path: [i, ...a.path || []]
1408
+ }))
1409
+ };
1410
+ n[i] = o.value;
1411
+ }
1412
+ if (!this._strict)
1413
+ for (const i of Object.keys(s))
1414
+ i in this._shape || (n[i] = s[i]);
1415
+ return { value: n };
1416
+ }
1417
+ return { value: e };
1418
+ }
1419
+ /** @internal */
1420
+ _clone() {
1421
+ const e = new k();
1422
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e._shape = this._shape, e._strict = this._strict, e;
1423
+ }
1424
+ /**
1425
+ * Defines the shape of the object with field schemas.
1426
+ *
1427
+ * @typeParam S - Shape definition type
1428
+ * @param shape - Object mapping field names to schemas
1429
+ *
1430
+ * @example
1431
+ * ```typescript
1432
+ * user: prop.object().shape({
1433
+ * name: prop.string(),
1434
+ * age: prop.number().optional(),
1435
+ * })
1436
+ * ```
1437
+ */
1438
+ shape(e) {
1439
+ const s = new k();
1440
+ return s._optional = this._optional, s._nullable = this._nullable, s._shape = e, s._strict = this._strict, s;
1441
+ }
1442
+ /**
1443
+ * Rejects objects with unknown keys.
1444
+ *
1445
+ * @example
1446
+ * ```typescript
1447
+ * config: prop.object().shape({ debug: prop.boolean() }).strict()
1448
+ * ```
1449
+ */
1450
+ strict() {
1451
+ const e = this._clone();
1452
+ return e._strict = !0, e;
1453
+ }
1454
+ }
1455
+ class Z extends m {
1456
+ /** @internal */
1457
+ _value;
1458
+ constructor(e) {
1459
+ super(), this._value = e;
1460
+ }
1461
+ /** @internal */
1462
+ _validate(e) {
1463
+ return e !== this._value ? {
1464
+ issues: [{ message: `Expected ${JSON.stringify(this._value)}, got ${JSON.stringify(e)}` }]
1465
+ } : { value: e };
1466
+ }
1467
+ /** @internal */
1468
+ _clone() {
1469
+ const e = new Z(this._value);
1470
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e;
1471
+ }
1472
+ }
1473
+ class G extends m {
1474
+ /** @internal */
1475
+ _values;
1476
+ constructor(e) {
1477
+ super(), this._values = e;
1478
+ }
1479
+ /** @internal */
1480
+ _validate(e) {
1481
+ return this._values.includes(e) ? { value: e } : {
1482
+ issues: [
1483
+ {
1484
+ message: `Expected one of [${this._values.map((s) => JSON.stringify(s)).join(", ")}], got ${JSON.stringify(e)}`
1485
+ }
1486
+ ]
1487
+ };
1488
+ }
1489
+ /** @internal */
1490
+ _clone() {
1491
+ const e = new G(this._values);
1492
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e;
1493
+ }
1494
+ }
1495
+ class K extends m {
1496
+ constructor() {
1497
+ super(), this._nullable = !0;
1498
+ }
1499
+ /** @internal */
1500
+ _validate(e) {
1501
+ return { value: e };
1502
+ }
1503
+ /** @internal */
1504
+ _clone() {
1505
+ const e = new K();
1506
+ return e._optional = this._optional, e._nullable = this._nullable, e._default = this._default, e;
1507
+ }
1508
+ }
1509
+ const d = {
1510
+ /**
1511
+ * Creates a string schema.
1512
+ *
1513
+ * @example
1514
+ * ```typescript
1515
+ * prop.string()
1516
+ * prop.string().min(1).max(100)
1517
+ * prop.string().email()
1518
+ * prop.string().url()
1519
+ * prop.string().pattern(/^[a-z]+$/)
1520
+ * ```
1521
+ */
1522
+ string: () => new V(),
1523
+ /**
1524
+ * Creates a number schema.
1525
+ *
1526
+ * @example
1527
+ * ```typescript
1528
+ * prop.number()
1529
+ * prop.number().min(0).max(100)
1530
+ * prop.number().int()
1531
+ * prop.number().positive()
1532
+ * ```
1533
+ */
1534
+ number: () => new q(),
1535
+ /**
1536
+ * Creates a boolean schema.
1537
+ *
1538
+ * @example
1539
+ * ```typescript
1540
+ * prop.boolean()
1541
+ * prop.boolean().default(false)
1542
+ * ```
1543
+ */
1544
+ boolean: () => new X(),
1545
+ /**
1546
+ * Creates a function schema.
1547
+ *
1548
+ * @typeParam T - Function type signature
1549
+ *
1550
+ * @example
1551
+ * ```typescript
1552
+ * prop.function()
1553
+ * prop.function<() => void>()
1554
+ * prop.function<(data: { id: string }) => Promise<void>>()
1555
+ * ```
1556
+ */
1557
+ function: () => new Y(),
1558
+ /**
1559
+ * Creates an array schema.
1560
+ *
1561
+ * @typeParam T - Array item type
1562
+ *
1563
+ * @example
1564
+ * ```typescript
1565
+ * prop.array()
1566
+ * prop.array().of(prop.string())
1567
+ * prop.array().of(prop.number()).min(1).max(10)
1568
+ * ```
1569
+ */
1570
+ array: () => new T(),
1571
+ /**
1572
+ * Creates an object schema.
1573
+ *
1574
+ * @typeParam T - Object type
1575
+ *
1576
+ * @example
1577
+ * ```typescript
1578
+ * prop.object()
1579
+ * prop.object().shape({
1580
+ * name: prop.string(),
1581
+ * age: prop.number().optional(),
1582
+ * })
1583
+ * prop.object().shape({ key: prop.string() }).strict()
1584
+ * ```
1585
+ */
1586
+ object: () => new k(),
1587
+ /**
1588
+ * Creates a literal schema for exact value matching.
1589
+ *
1590
+ * @param value - The exact value to match
1591
+ *
1592
+ * @example
1593
+ * ```typescript
1594
+ * prop.literal('active')
1595
+ * prop.literal(42)
1596
+ * prop.literal(true)
1597
+ * ```
1598
+ */
1599
+ literal: (t) => new Z(t),
1600
+ /**
1601
+ * Creates an enum schema for a set of allowed values.
1602
+ *
1603
+ * @param values - Array of allowed values
1604
+ *
1605
+ * @example
1606
+ * ```typescript
1607
+ * prop.enum(['pending', 'active', 'completed'])
1608
+ * prop.enum([1, 2, 3])
1609
+ * ```
1610
+ */
1611
+ enum: (t) => new G(t),
1612
+ /**
1613
+ * Creates a schema that accepts any value.
1614
+ *
1615
+ * @remarks
1616
+ * Use sparingly - prefer typed schemas when possible.
1617
+ *
1618
+ * @example
1619
+ * ```typescript
1620
+ * prop.any()
1621
+ * ```
1622
+ */
1623
+ any: () => new K()
1624
+ }, R = {
1625
+ uid: {
1626
+ schema: d.string().optional(),
1627
+ sendToHost: !0
1628
+ },
1629
+ tag: {
1630
+ schema: d.string().optional(),
1631
+ sendToHost: !0
1632
+ },
1633
+ dimensions: {
1634
+ schema: d.object().default(() => ({ width: "100%", height: "100%" })),
1635
+ sendToHost: !1
1636
+ },
1637
+ timeout: {
1638
+ schema: d.number().default(1e4),
1639
+ sendToHost: !1
1640
+ },
1641
+ cspNonce: {
1642
+ schema: d.string().optional(),
1643
+ sendToHost: !0
1644
+ },
1645
+ // Lifecycle callbacks - not sent to host (consumer-only)
1646
+ onDisplay: {
1647
+ schema: d.function().optional(),
1648
+ sendToHost: !1
1649
+ },
1650
+ onRendered: {
1651
+ schema: d.function().optional(),
1652
+ sendToHost: !1
1653
+ },
1654
+ onRender: {
1655
+ schema: d.function().optional(),
1656
+ sendToHost: !1
1657
+ },
1658
+ onPrerendered: {
1659
+ schema: d.function().optional(),
1660
+ sendToHost: !1
1661
+ },
1662
+ onPrerender: {
1663
+ schema: d.function().optional(),
1664
+ sendToHost: !1
1665
+ },
1666
+ onClose: {
1667
+ schema: d.function().optional(),
1668
+ sendToHost: !1
1669
+ },
1670
+ onDestroy: {
1671
+ schema: d.function().optional(),
1672
+ sendToHost: !1
1673
+ },
1674
+ onResize: {
1675
+ schema: d.function().optional(),
1676
+ sendToHost: !1
1677
+ },
1678
+ onFocus: {
1679
+ schema: d.function().optional(),
1680
+ sendToHost: !1
1681
+ },
1682
+ onError: {
1683
+ schema: d.function().optional(),
1684
+ sendToHost: !1
1685
+ },
1686
+ onProps: {
1687
+ schema: d.function().optional(),
1688
+ sendToHost: !1
1689
+ }
1690
+ };
1691
+ function E(t) {
1692
+ return typeof t == "object" && t !== null && "~standard" in t && typeof t["~standard"] == "object" && t["~standard"] !== null && t["~standard"].version === 1 && typeof t["~standard"].validate == "function";
1693
+ }
1694
+ function Ve(t, e, s) {
1695
+ const n = t["~standard"].validate(e);
1696
+ if (n instanceof Promise)
1697
+ throw new Error(
1698
+ `Prop "${s}" uses an async schema. ForgeFrame only supports synchronous schema validation. Please use a synchronous schema or remove async operations (like database lookups) from your schema definition.`
1699
+ );
1700
+ if (n.issues) {
1701
+ const i = n.issues.map((r) => `${qe(r.path, s)}: ${r.message}`);
1702
+ throw new Error(`Validation failed: ${i.join("; ")}`);
1703
+ }
1704
+ return n.value;
1705
+ }
1706
+ function qe(t, e) {
1707
+ if (!t || t.length === 0)
1708
+ return e;
1709
+ const s = t.map((n) => typeof n == "object" && n !== null && "key" in n ? String(n.key) : String(n));
1710
+ return `${e}.${s.join(".")}`;
1711
+ }
1712
+ function le(t, e, s) {
1713
+ const n = {
1714
+ ...R,
1715
+ ...e
1716
+ }, i = {};
1717
+ for (const [r, o] of Object.entries(n)) {
1718
+ const c = E(o) ? { schema: o } : o;
1719
+ let l;
1720
+ const h = c.alias, g = r in t, y = h && h in t;
1721
+ if (g)
1722
+ l = t[r];
1723
+ else if (y)
1724
+ l = t[h];
1725
+ else if (c.value)
1726
+ l = c.value(s);
1727
+ else if (c.default !== void 0)
1728
+ l = typeof c.default == "function" ? c.default(s) : c.default;
1729
+ else if (c.schema && E(c.schema)) {
1730
+ const b = c.schema["~standard"].validate(void 0);
1731
+ !(b instanceof Promise) && !b.issues && (l = b.value);
1732
+ }
1733
+ l !== void 0 && c.decorate && (l = c.decorate({ value: l, props: i })), i[r] = l;
1734
+ }
1735
+ return i;
1736
+ }
1737
+ function Xe(t, e) {
1738
+ const s = {
1739
+ ...R,
1740
+ ...e
1741
+ };
1742
+ for (const [n, i] of Object.entries(s)) {
1743
+ const r = E(i), o = r ? { schema: i } : i;
1744
+ let a = t[n];
1745
+ if (o.required && a === void 0)
1746
+ throw new Error(`Prop "${n}" is required but was not provided`);
1747
+ if (o.schema && E(o.schema))
1748
+ (a !== void 0 || r) && (a = Ve(o.schema, a, n), t[n] = a);
1749
+ else if (a === void 0)
1750
+ continue;
1751
+ o.validate && o.validate({ value: a, props: t });
1752
+ }
1753
+ }
1754
+ function ue(t, e, s, n) {
1755
+ const i = {
1756
+ ...R,
1757
+ ...e
1758
+ }, r = {};
1759
+ for (const [o, a] of Object.entries(i)) {
1760
+ const l = E(a) ? { schema: a } : a, h = t[o];
1761
+ if (l.sendToHost === !1 || l.sameDomain && !n) continue;
1762
+ if (l.trustedDomains) {
1763
+ const y = l.trustedDomains;
1764
+ if (!we(y, s)) continue;
1765
+ }
1766
+ let g = h;
1767
+ l.hostDecorate && h !== void 0 && (g = l.hostDecorate({ value: h, props: t })), r[o] = g;
1768
+ }
1769
+ return r;
1770
+ }
1771
+ function Ye(t, e) {
1772
+ const s = new URLSearchParams(), n = {
1773
+ ...R,
1774
+ ...e
1775
+ };
1776
+ for (const [i, r] of Object.entries(n)) {
1777
+ const a = E(r) ? { schema: r } : r, c = t[i];
1778
+ if (c === void 0 || typeof c == "function" || !a.queryParam) continue;
1779
+ const l = typeof a.queryParam == "string" ? a.queryParam : i;
1780
+ let h;
1781
+ typeof a.queryParam == "function" ? h = a.queryParam({ value: c }) : typeof c == "object" ? h = JSON.stringify(c) : h = String(c), s.set(l, h);
1782
+ }
1783
+ return s;
1784
+ }
1785
+ function Pe(t, e = "") {
1786
+ const s = [];
1787
+ for (const [n, i] of Object.entries(t)) {
1788
+ const r = e ? `${e}.${n}` : n;
1789
+ if (i !== null && typeof i == "object" && !Array.isArray(i))
1790
+ s.push(Pe(i, r));
1791
+ else {
1792
+ const o = encodeURIComponent(JSON.stringify(i));
1793
+ s.push(`${r}=${o}`);
1794
+ }
1795
+ }
1796
+ return s.filter(Boolean).join("&");
1797
+ }
1798
+ function Ze(t) {
1799
+ const e = {};
1800
+ if (!t) return e;
1801
+ const s = t.split("&");
1802
+ for (const n of s) {
1803
+ const [i, r] = n.split("=");
1804
+ if (!i || r === void 0) continue;
1805
+ let o;
1806
+ try {
1807
+ o = JSON.parse(decodeURIComponent(r));
1808
+ } catch {
1809
+ o = decodeURIComponent(r);
1810
+ }
1811
+ const a = i.split(".");
1812
+ let c = e;
1813
+ for (let l = 0; l < a.length - 1; l++) {
1814
+ const h = a[l];
1815
+ (!(h in c) || typeof c[h] != "object") && (c[h] = {}), c = c[h];
1816
+ }
1817
+ c[a[a.length - 1]] = o;
1818
+ }
1819
+ return e;
1820
+ }
1821
+ function Ge(t) {
1822
+ return typeof t == "object" && t !== null && t.__type__ === "dotify" && typeof t.__value__ == "string";
1823
+ }
1824
+ function he(t, e, s) {
1825
+ const n = {
1826
+ ...R,
1827
+ ...e
1828
+ }, i = {};
1829
+ for (const [r, o] of Object.entries(t)) {
1830
+ if (o === void 0) continue;
1831
+ const a = n[r];
1832
+ i[r] = Ke(o, a, s);
1833
+ }
1834
+ return i;
1835
+ }
1836
+ function Ke(t, e, s) {
1837
+ if (typeof t == "function")
1838
+ return s.serialize(t);
1839
+ const n = e?.serialization ?? I.JSON;
1840
+ if (n === I.BASE64 && typeof t == "object") {
1841
+ const i = JSON.stringify(t);
1842
+ return {
1843
+ __type__: "base64",
1844
+ __value__: btoa(encodeURIComponent(i))
1845
+ };
1846
+ }
1847
+ return n === I.DOTIFY && typeof t == "object" && t !== null && !Array.isArray(t) ? {
1848
+ __type__: "dotify",
1849
+ __value__: Pe(t)
1850
+ } : M(t, s);
1851
+ }
1852
+ function de(t, e, s, n, i, r) {
1853
+ const o = {
1854
+ ...R,
1855
+ ...e
1856
+ }, a = {};
1857
+ for (const [c, l] of Object.entries(t)) {
1858
+ const h = o[c];
1859
+ a[c] = Qe(
1860
+ l,
1861
+ h,
1862
+ s,
1863
+ n,
1864
+ i,
1865
+ r
1866
+ );
1867
+ }
1868
+ return a;
1869
+ }
1870
+ function Qe(t, e, s, n, i, r) {
1871
+ if (et(t))
1872
+ try {
1873
+ const o = decodeURIComponent(atob(t.__value__));
1874
+ return JSON.parse(o);
1875
+ } catch {
1876
+ return t;
1877
+ }
1878
+ if (Ge(t))
1879
+ try {
1880
+ return Ze(t.__value__);
1881
+ } catch {
1882
+ return t;
1883
+ }
1884
+ return U(t, n, i, r);
1885
+ }
1886
+ function et(t) {
1887
+ return typeof t == "object" && t !== null && t.__type__ === "base64" && typeof t.__value__ == "string";
1888
+ }
1889
+ function P(t, e = "100%") {
1890
+ return t === void 0 ? e : typeof t == "number" ? `${t}px` : t;
1891
+ }
1892
+ function $(t, e) {
1893
+ if (t === void 0) return e;
1894
+ if (typeof t == "number") return t;
1895
+ const s = parseInt(t, 10);
1896
+ return isNaN(s) ? e : s;
1897
+ }
1898
+ function tt(t) {
1899
+ try {
1900
+ t.src = "about:blank", t.parentNode?.removeChild(t);
1901
+ } catch {
1902
+ }
1903
+ }
1904
+ function st(t, e) {
1905
+ rt(t, e);
1906
+ }
1907
+ function nt(t) {
1908
+ t.style.display = "", t.style.visibility = "visible";
1909
+ }
1910
+ function fe(t) {
1911
+ t.style.display = "none", t.style.visibility = "hidden";
1912
+ }
1913
+ function it(t) {
1914
+ try {
1915
+ t.focus(), t.contentWindow?.focus();
1916
+ } catch {
1917
+ }
1918
+ }
1919
+ function rt(t, e) {
1920
+ e.width !== void 0 && (t.style.width = P(e.width)), e.height !== void 0 && (t.style.height = P(e.height));
1921
+ }
1922
+ class Re extends Error {
1923
+ constructor(e = "Popup blocked by browser") {
1924
+ super(e), this.name = "PopupOpenError";
1925
+ }
1926
+ }
1927
+ function ot(t) {
1928
+ const { url: e, name: s, dimensions: n } = t, i = $(n.width, 500), r = $(n.height, 500), o = Math.floor(window.screenX + (window.outerWidth - i) / 2), a = Math.floor(window.screenY + (window.outerHeight - r) / 2), c = [
1929
+ `width=${i}`,
1930
+ `height=${r}`,
1931
+ `left=${o}`,
1932
+ `top=${a}`,
1933
+ "menubar=no",
1934
+ "toolbar=no",
1935
+ "location=yes",
1936
+ // Required for security
1937
+ "status=no",
1938
+ "resizable=yes",
1939
+ "scrollbars=yes"
1940
+ ].join(","), l = window.open(e, s, c);
1941
+ if (!l || lt(l))
1942
+ throw new Re();
1943
+ return l;
1944
+ }
1945
+ function at(t) {
1946
+ try {
1947
+ t.closed || t.close();
1948
+ } catch {
1949
+ }
1950
+ }
1951
+ function ct(t) {
1952
+ try {
1953
+ t.closed || t.focus();
1954
+ } catch {
1955
+ }
1956
+ }
1957
+ function lt(t) {
1958
+ if (!t) return !0;
1959
+ try {
1960
+ return !!(t.closed || t.innerHeight === 0 || t.innerWidth === 0);
1961
+ } catch {
1962
+ return !0;
1963
+ }
1964
+ }
1965
+ function ut(t, e, s = {}) {
1966
+ const {
1967
+ initialInterval: n = 100,
1968
+ // Start fast to catch quick closes
1969
+ maxInterval: i = 2e3,
1970
+ // Cap at 2 seconds
1971
+ multiplier: r = 1.5
1972
+ // Exponential backoff multiplier
1973
+ } = s;
1974
+ let o = n, a, c = !1;
1975
+ const l = () => {
1976
+ try {
1977
+ e();
1978
+ } catch (g) {
1979
+ console.error("Error in popup close callback:", g);
1980
+ }
1981
+ }, h = () => {
1982
+ if (!c) {
1983
+ try {
1984
+ if (t.closed) {
1985
+ l();
1986
+ return;
1987
+ }
1988
+ } catch {
1989
+ l();
1990
+ return;
1991
+ }
1992
+ o = Math.min(o * r, i), a = setTimeout(h, o);
1993
+ }
1994
+ };
1995
+ return a = setTimeout(h, o), () => {
1996
+ c = !0, clearTimeout(a);
1997
+ };
1998
+ }
1999
+ function ht(t, e) {
2000
+ try {
2001
+ const s = $(e.width, t.outerWidth), n = $(
2002
+ e.height,
2003
+ t.outerHeight
2004
+ );
2005
+ t.resizeTo(s, n);
2006
+ } catch {
2007
+ }
2008
+ }
2009
+ function dt(t) {
2010
+ const { doc: e, dimensions: s, uid: n, tag: i } = t, r = e.createElement("div");
2011
+ return r.id = `forgeframe-container-${n}`, r.setAttribute("data-forgeframe-tag", i), Object.assign(r.style, {
2012
+ display: "inline-block",
2013
+ position: "relative",
2014
+ width: P(s.width),
2015
+ height: P(s.height),
2016
+ overflow: "hidden"
2017
+ }), r;
2018
+ }
2019
+ function ft(t) {
2020
+ const { doc: e, dimensions: s, cspNonce: n } = t, i = e.createElement("div");
2021
+ Object.assign(i.style, {
2022
+ display: "flex",
2023
+ alignItems: "center",
2024
+ justifyContent: "center",
2025
+ width: P(s.width),
2026
+ height: P(s.height),
2027
+ backgroundColor: "#f5f5f5",
2028
+ position: "absolute",
2029
+ top: "0",
2030
+ left: "0",
2031
+ zIndex: "100"
2032
+ });
2033
+ const r = e.createElement("div");
2034
+ Object.assign(r.style, {
2035
+ width: "40px",
2036
+ height: "40px",
2037
+ border: "3px solid #e0e0e0",
2038
+ borderTopColor: "#3498db",
2039
+ borderRadius: "50%",
2040
+ animation: "forgeframe-spin 1s linear infinite"
2041
+ });
2042
+ const o = e.createElement("style");
2043
+ return n && o.setAttribute("nonce", n), o.textContent = `
2044
+ @keyframes forgeframe-spin {
2045
+ to { transform: rotate(360deg); }
2046
+ }
2047
+ `, i.appendChild(o), i.appendChild(r), i;
2048
+ }
2049
+ function pt(t, e = 200) {
2050
+ return new Promise((s) => {
2051
+ t.style.opacity = "0", t.style.transition = `opacity ${e}ms ease-in`, t.offsetHeight, t.style.opacity = "1", setTimeout(s, e);
2052
+ });
2053
+ }
2054
+ function mt(t, e = 200) {
2055
+ return new Promise((s) => {
2056
+ t.style.transition = `opacity ${e}ms ease-out`, t.style.opacity = "0", setTimeout(s, e);
2057
+ });
2058
+ }
2059
+ async function gt(t, e, s) {
2060
+ e && (await mt(e, 150), e.remove()), s.style.display = "", s.style.visibility = "visible", s.style.opacity = "0", await pt(s, 150);
2061
+ }
2062
+ class Q {
2063
+ /** Event emitter for lifecycle events. */
2064
+ event;
2065
+ /** Arbitrary state storage for the component instance. */
2066
+ state = {};
2067
+ /** Data exported by the host component. */
2068
+ exports;
2069
+ /** Data exported from the consumer by the host. */
2070
+ consumerExports;
2071
+ /** @internal */
2072
+ _uid;
2073
+ /**
2074
+ * Unique instance identifier.
2075
+ * @readonly
2076
+ */
2077
+ get uid() {
2078
+ return this._uid;
2079
+ }
2080
+ /** @internal */
2081
+ options;
2082
+ /** @internal */
2083
+ props;
2084
+ /** @internal */
2085
+ context;
2086
+ /** @internal */
2087
+ messenger;
2088
+ /** @internal */
2089
+ bridge;
2090
+ /** @internal */
2091
+ cleanup;
2092
+ /** @internal */
2093
+ hostWindow = null;
2094
+ /** @internal */
2095
+ iframe = null;
2096
+ /** @internal */
2097
+ container = null;
2098
+ /** @internal */
2099
+ prerenderElement = null;
2100
+ /** @internal */
2101
+ initPromise = null;
2102
+ /** @internal */
2103
+ rendered = !1;
2104
+ /** @internal */
2105
+ destroyed = !1;
2106
+ /**
2107
+ * Creates a new ConsumerComponent instance.
2108
+ *
2109
+ * @param options - Component configuration options
2110
+ * @param props - Initial props to pass to the component
2111
+ */
2112
+ constructor(e, s = {}) {
2113
+ this._uid = Ie(), this.options = this.normalizeOptions(e), this.context = this.options.defaultContext, this.event = new me(), this.cleanup = new De();
2114
+ const n = this.buildTrustedDomains();
2115
+ this.messenger = new ye(this.uid, window, j(), n), this.bridge = new B(this.messenger);
2116
+ const i = this.createPropContext();
2117
+ this.props = le(s, this.options.props, i), this.setupMessageHandlers(), this.setupCleanup();
2118
+ }
2119
+ /**
2120
+ * Builds the list of trusted domains for messenger communication.
2121
+ * @internal
2122
+ */
2123
+ buildTrustedDomains() {
2124
+ const e = [], s = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url;
2125
+ try {
2126
+ const n = new URL(s);
2127
+ e.push(n.origin);
2128
+ } catch {
2129
+ }
2130
+ if (this.options.domain) {
2131
+ if (typeof this.options.domain == "string")
2132
+ e.push(this.options.domain);
2133
+ else if (Array.isArray(this.options.domain))
2134
+ e.push(...this.options.domain);
2135
+ else if (this.options.domain instanceof RegExp)
2136
+ return this.options.domain;
2137
+ }
2138
+ return e.length > 0 ? e : void 0;
2139
+ }
2140
+ /**
2141
+ * Renders the component into a DOM container.
2142
+ *
2143
+ * @remarks
2144
+ * This is the primary method for displaying the component. It creates
2145
+ * an iframe or popup, establishes communication with the host, and
2146
+ * handles the prerender/render lifecycle.
2147
+ *
2148
+ * @param container - CSS selector or HTMLElement to render into
2149
+ * @param context - Override the default rendering context (iframe or popup)
2150
+ * @throws Error if component was already destroyed or rendered
2151
+ *
2152
+ * @example
2153
+ * ```typescript
2154
+ * await instance.render('#container');
2155
+ * await instance.render(document.getElementById('target'), 'popup');
2156
+ * ```
2157
+ */
2158
+ async render(e, s) {
2159
+ if (this.destroyed)
2160
+ throw new Error("Component has been destroyed");
2161
+ if (this.rendered)
2162
+ throw new Error("Component has already been rendered");
2163
+ this.context = s ?? this.options.defaultContext, this.checkEligibility(), Xe(this.props, this.options.props), this.container = this.resolveContainer(e), this.event.emit(f.PRERENDER), this.callPropCallback("onPrerender"), await this.prerender(), this.event.emit(f.PRERENDERED), this.callPropCallback("onPrerendered"), this.event.emit(f.RENDER), this.callPropCallback("onRender"), await this.open(), await this.waitForHost(), this.context === p.IFRAME && this.iframe && this.prerenderElement && (await gt(
2164
+ this.container,
2165
+ this.prerenderElement,
2166
+ this.iframe
2167
+ ), this.prerenderElement = null), this.rendered = !0, this.event.emit(f.RENDERED), this.callPropCallback("onRendered"), this.event.emit(f.DISPLAY), this.callPropCallback("onDisplay");
2168
+ }
2169
+ /**
2170
+ * Renders the component into a container in a different window.
2171
+ *
2172
+ * @remarks
2173
+ * Currently delegates to regular render. Full cross-window rendering
2174
+ * would require additional complexity.
2175
+ *
2176
+ * @param _win - Target window (currently unused)
2177
+ * @param container - CSS selector or HTMLElement to render into
2178
+ * @param context - Override the default rendering context
2179
+ */
2180
+ async renderTo(e, s, n) {
2181
+ return this.render(s, n);
2182
+ }
2183
+ /**
2184
+ * Closes and destroys the component.
2185
+ *
2186
+ * @remarks
2187
+ * Emits the 'close' event before destruction. Safe to call multiple times.
2188
+ */
2189
+ async close() {
2190
+ this.destroyed || (this.event.emit(f.CLOSE), await this.destroy());
2191
+ }
2192
+ /**
2193
+ * Focuses the component window.
2194
+ *
2195
+ * @remarks
2196
+ * For iframes, focuses the iframe element. For popups, brings the window to front.
2197
+ */
2198
+ async focus() {
2199
+ this.context === p.IFRAME && this.iframe ? it(this.iframe) : this.context === p.POPUP && this.hostWindow && ct(this.hostWindow), this.event.emit(f.FOCUS), this.callPropCallback("onFocus");
2200
+ }
2201
+ /**
2202
+ * Resizes the component to the specified dimensions.
2203
+ *
2204
+ * @param dimensions - New width and height for the component
2205
+ */
2206
+ async resize(e) {
2207
+ this.context === p.IFRAME && this.iframe ? st(this.iframe, e) : this.context === p.POPUP && this.hostWindow && ht(this.hostWindow, e), this.event.emit(f.RESIZE, e), this.callPropCallback("onResize", e);
2208
+ }
2209
+ /**
2210
+ * Shows the component if hidden.
2211
+ *
2212
+ * @remarks
2213
+ * Only applicable to iframe context.
2214
+ */
2215
+ async show() {
2216
+ this.context === p.IFRAME && this.iframe && nt(this.iframe);
2217
+ }
2218
+ /**
2219
+ * Hides the component.
2220
+ *
2221
+ * @remarks
2222
+ * Only applicable to iframe context.
2223
+ */
2224
+ async hide() {
2225
+ this.context === p.IFRAME && this.iframe && fe(this.iframe);
2226
+ }
2227
+ /**
2228
+ * Updates the component props and sends them to the host.
2229
+ *
2230
+ * @remarks
2231
+ * Props are normalized and serialized before being sent to the host window.
2232
+ *
2233
+ * @param newProps - Partial props object to merge with existing props
2234
+ */
2235
+ async updateProps(e) {
2236
+ const s = this.createPropContext();
2237
+ if (this.props = le(
2238
+ { ...this.props, ...e },
2239
+ this.options.props,
2240
+ s
2241
+ ), this.hostWindow && !Ee(this.hostWindow)) {
2242
+ const n = this.getHostDomain(), i = ue(
2243
+ this.props,
2244
+ this.options.props,
2245
+ n,
2246
+ _e(this.hostWindow)
2247
+ ), r = he(
2248
+ i,
2249
+ this.options.props,
2250
+ this.bridge
2251
+ );
2252
+ await this.messenger.send(
2253
+ this.hostWindow,
2254
+ n,
2255
+ u.PROPS,
2256
+ r
2257
+ );
2258
+ }
2259
+ this.event.emit(f.PROPS, this.props), this.callPropCallback("onProps", this.props);
2260
+ }
2261
+ /**
2262
+ * Creates a clone of this instance with the same props.
2263
+ *
2264
+ * @returns A new unrendered component instance with identical configuration
2265
+ */
2266
+ clone() {
2267
+ return new Q(this.options, this.props);
2268
+ }
2269
+ /**
2270
+ * Checks if the component is eligible to render based on the eligible option.
2271
+ *
2272
+ * @returns True if eligible or no eligibility check defined
2273
+ */
2274
+ isEligible() {
2275
+ return this.options.eligible ? this.options.eligible({ props: this.props }).eligible : !0;
2276
+ }
2277
+ /**
2278
+ * Normalizes component options with default values.
2279
+ * @internal
2280
+ */
2281
+ normalizeOptions(e) {
2282
+ return {
2283
+ ...e,
2284
+ props: e.props ?? {},
2285
+ defaultContext: e.defaultContext ?? p.IFRAME,
2286
+ dimensions: typeof e.dimensions == "function" ? e.dimensions(this.props) : e.dimensions ?? { width: "100%", height: "100%" },
2287
+ timeout: e.timeout ?? 1e4,
2288
+ children: e.children
2289
+ };
2290
+ }
2291
+ /**
2292
+ * Creates the prop context passed to prop callbacks and validators.
2293
+ * @internal
2294
+ */
2295
+ createPropContext() {
2296
+ return {
2297
+ props: this.props,
2298
+ state: this.state,
2299
+ close: () => this.close(),
2300
+ focus: () => this.focus(),
2301
+ onError: (e) => this.handleError(e),
2302
+ container: this.container,
2303
+ uid: this.uid,
2304
+ tag: this.options.tag
2305
+ };
2306
+ }
2307
+ /**
2308
+ * Resolves a container selector or element to an HTMLElement.
2309
+ * @internal
2310
+ */
2311
+ resolveContainer(e) {
2312
+ if (!e)
2313
+ throw new Error("Container is required for rendering");
2314
+ if (typeof e == "string") {
2315
+ const s = document.querySelector(e);
2316
+ if (!s)
2317
+ throw new Error(`Container "${e}" not found`);
2318
+ return s;
2319
+ }
2320
+ return e;
2321
+ }
2322
+ /**
2323
+ * Checks eligibility and throws if component cannot render.
2324
+ * @internal
2325
+ */
2326
+ checkEligibility() {
2327
+ if (!this.options.eligible) return;
2328
+ const e = this.options.eligible({ props: this.props });
2329
+ if (!e.eligible)
2330
+ throw new Error(`Component not eligible: ${e.reason ?? "Unknown reason"}`);
2331
+ }
2332
+ /**
2333
+ * Creates and displays the prerender (loading) content.
2334
+ * @internal
2335
+ */
2336
+ async prerender() {
2337
+ if (!this.container) return;
2338
+ const e = this.options.prerenderTemplate ?? ft, s = this.options.containerTemplate ?? dt, n = this.options.dimensions, i = this.props.cspNonce;
2339
+ if (this.context === p.IFRAME) {
2340
+ const c = this.buildWindowName();
2341
+ this.iframe = this.createIframeElement(c), fe(this.iframe);
2342
+ }
2343
+ const r = {
2344
+ uid: this.uid,
2345
+ tag: this.options.tag,
2346
+ context: this.context,
2347
+ dimensions: n,
2348
+ props: this.props,
2349
+ doc: document,
2350
+ container: this.container,
2351
+ frame: this.iframe,
2352
+ prerenderFrame: null,
2353
+ close: () => this.close(),
2354
+ focus: () => this.focus(),
2355
+ cspNonce: i
2356
+ };
2357
+ this.prerenderElement = e(r);
2358
+ const o = {
2359
+ uid: this.uid,
2360
+ tag: this.options.tag,
2361
+ context: this.context,
2362
+ dimensions: n,
2363
+ props: this.props,
2364
+ doc: document,
2365
+ container: this.container,
2366
+ frame: this.iframe,
2367
+ prerenderFrame: this.prerenderElement,
2368
+ close: () => this.close(),
2369
+ focus: () => this.focus(),
2370
+ cspNonce: i
2371
+ }, a = s(o);
2372
+ 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);
2373
+ }
2374
+ /**
2375
+ * Creates an iframe element without setting src (for prerender phase).
2376
+ * The window name is set immediately as it carries the payload for the host.
2377
+ * @internal
2378
+ */
2379
+ createIframeElement(e) {
2380
+ const s = document.createElement("iframe"), n = this.options.dimensions, i = typeof this.options.attributes == "function" ? this.options.attributes(this.props) : this.options.attributes ?? {}, r = typeof this.options.style == "function" ? this.options.style(this.props) : this.options.style ?? {};
2381
+ s.name = e, s.setAttribute("frameborder", "0"), s.setAttribute("allowtransparency", "true"), s.setAttribute("scrolling", "auto"), n.width !== void 0 && (s.style.width = typeof n.width == "number" ? `${n.width}px` : n.width), n.height !== void 0 && (s.style.height = typeof n.height == "number" ? `${n.height}px` : n.height);
2382
+ for (const [o, a] of Object.entries(i))
2383
+ a !== void 0 && (typeof a == "boolean" ? a && s.setAttribute(o, "") : s.setAttribute(o, a));
2384
+ for (const [o, a] of Object.entries(r)) {
2385
+ if (a === void 0) continue;
2386
+ const c = typeof a == "number" ? `${a}px` : a;
2387
+ s.style.setProperty(
2388
+ o.replace(/([A-Z])/g, "-$1").toLowerCase(),
2389
+ String(c)
2390
+ );
2391
+ }
2392
+ return i.sandbox || s.setAttribute(
2393
+ "sandbox",
2394
+ "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
2395
+ ), s;
2396
+ }
2397
+ /**
2398
+ * Opens the host window (iframe or popup).
2399
+ * @internal
2400
+ */
2401
+ async open() {
2402
+ const e = this.buildUrl();
2403
+ if (this.context === p.IFRAME) {
2404
+ if (!this.iframe)
2405
+ throw new Error("Iframe not created during prerender");
2406
+ this.iframe.src = e, this.hostWindow = this.iframe.contentWindow;
2407
+ } else {
2408
+ const s = this.buildWindowName();
2409
+ this.hostWindow = ot({
2410
+ url: e,
2411
+ name: s,
2412
+ dimensions: this.options.dimensions
2413
+ });
2414
+ const n = ut(this.hostWindow, () => {
2415
+ this.destroy();
2416
+ });
2417
+ this.cleanup.register(n);
2418
+ }
2419
+ this.hostWindow && Be(this.uid, this.hostWindow);
2420
+ }
2421
+ /**
2422
+ * Builds the URL for the host window including query parameters.
2423
+ * @internal
2424
+ */
2425
+ buildUrl() {
2426
+ const e = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url, n = Ye(this.props, this.options.props).toString();
2427
+ if (!n) return e;
2428
+ const i = e.includes("?") ? "&" : "?";
2429
+ return `${e}${i}${n}`;
2430
+ }
2431
+ /**
2432
+ * Builds the window.name payload for the host window.
2433
+ * @internal
2434
+ */
2435
+ buildWindowName() {
2436
+ const e = this.getHostDomain(), s = ue(
2437
+ this.props,
2438
+ this.options.props,
2439
+ e,
2440
+ !1
2441
+ // Assume cross-domain for initial payload
2442
+ ), n = he(
2443
+ s,
2444
+ this.options.props,
2445
+ this.bridge
2446
+ ), i = this.buildNestedHostRefs(), r = Me({
2447
+ uid: this.uid,
2448
+ tag: this.options.tag,
2449
+ context: this.context,
2450
+ consumerDomain: j(),
2451
+ props: n,
2452
+ exports: this.createConsumerExports(),
2453
+ children: i
2454
+ });
2455
+ return He(r);
2456
+ }
2457
+ /**
2458
+ * Builds component references for nested host components.
2459
+ * @internal
2460
+ */
2461
+ buildNestedHostRefs() {
2462
+ if (!this.options.children) return;
2463
+ const e = this.options.children({ props: this.props }), s = {};
2464
+ for (const [n, i] of Object.entries(e)) {
2465
+ const r = i;
2466
+ s[n] = {
2467
+ tag: r.tag ?? n,
2468
+ url: typeof r.url == "function" ? r.url.toString() : r.url ?? ""
2469
+ };
2470
+ }
2471
+ return Object.keys(s).length > 0 ? s : void 0;
2472
+ }
2473
+ /**
2474
+ * Creates the exports object sent to the host.
2475
+ * @internal
2476
+ */
2477
+ createConsumerExports() {
2478
+ return {
2479
+ init: u.INIT,
2480
+ close: u.CLOSE,
2481
+ resize: u.RESIZE,
2482
+ show: u.SHOW,
2483
+ hide: u.HIDE,
2484
+ onError: u.ERROR,
2485
+ updateProps: u.PROPS,
2486
+ export: u.EXPORT
2487
+ };
2488
+ }
2489
+ /**
2490
+ * Extracts the origin domain from the component URL.
2491
+ * @internal
2492
+ */
2493
+ getHostDomain() {
2494
+ const e = typeof this.options.url == "function" ? this.options.url(this.props) : this.options.url;
2495
+ try {
2496
+ return new URL(e, window.location.origin).origin;
2497
+ } catch {
2498
+ return "*";
2499
+ }
2500
+ }
2501
+ /**
2502
+ * Waits for the host to send the init message.
2503
+ * @internal
2504
+ */
2505
+ async waitForHost() {
2506
+ this.initPromise = ge();
2507
+ try {
2508
+ await Ne(
2509
+ this.initPromise.promise,
2510
+ this.options.timeout,
2511
+ `Host component "${this.options.tag}" (uid: ${this._uid}) did not initialize within ${this.options.timeout}ms. Check that the host page loads correctly and calls the initialization code.`
2512
+ );
2513
+ } catch (e) {
2514
+ throw this.handleError(e), e;
2515
+ }
2516
+ }
2517
+ /**
2518
+ * Sets up message handlers for host communication.
2519
+ * @internal
2520
+ */
2521
+ setupMessageHandlers() {
2522
+ this.messenger.on(u.INIT, () => (this.initPromise && this.initPromise.resolve(), { success: !0 })), this.messenger.on(u.CLOSE, async () => (await this.close(), { success: !0 })), this.messenger.on(u.RESIZE, async (e) => (await this.resize(e), { success: !0 })), this.messenger.on(u.FOCUS, async () => (await this.focus(), { success: !0 })), this.messenger.on(u.SHOW, async () => (await this.show(), { success: !0 })), this.messenger.on(u.HIDE, async () => (await this.hide(), { success: !0 })), this.messenger.on(
2523
+ u.ERROR,
2524
+ async (e) => {
2525
+ const s = new Error(e.message);
2526
+ return s.stack = e.stack, this.handleError(s), { success: !0 };
2527
+ }
2528
+ ), this.messenger.on(u.EXPORT, async (e) => (this.exports = e, { success: !0 })), this.messenger.on(u.CONSUMER_EXPORT, async (e) => (this.consumerExports = e, { success: !0 })), this.messenger.on(
2529
+ u.GET_SIBLINGS,
2530
+ async (e) => {
2531
+ const s = [], n = Pt(e.tag);
2532
+ if (n)
2533
+ for (const i of n.instances)
2534
+ i.uid !== e.uid && s.push({
2535
+ uid: i.uid,
2536
+ tag: e.tag,
2537
+ exports: i.exports
2538
+ });
2539
+ return s;
2540
+ }
2541
+ );
2542
+ }
2543
+ /**
2544
+ * Registers cleanup handlers for the instance.
2545
+ * @internal
2546
+ */
2547
+ setupCleanup() {
2548
+ this.cleanup.register(() => {
2549
+ this.messenger.destroy(), this.bridge.destroy(), this.event.removeAllListeners(), Je(this.uid);
2550
+ });
2551
+ }
2552
+ /**
2553
+ * Handles errors by emitting events and calling callbacks.
2554
+ * @internal
2555
+ */
2556
+ handleError(e) {
2557
+ this.event.emit(f.ERROR, e), this.callPropCallback("onError", e);
2558
+ }
2559
+ /**
2560
+ * Calls a prop callback if it exists.
2561
+ * @internal
2562
+ */
2563
+ callPropCallback(e, ...s) {
2564
+ const n = this.props[e];
2565
+ if (typeof n == "function")
2566
+ try {
2567
+ const i = n(...s);
2568
+ i && typeof i == "object" && "catch" in i && typeof i.catch == "function" && i.catch((r) => {
2569
+ console.error(`Error in async ${e} callback:`, r);
2570
+ });
2571
+ } catch (i) {
2572
+ console.error(`Error in ${e} callback:`, i);
2573
+ }
2574
+ }
2575
+ /**
2576
+ * Destroys the component and cleans up all resources.
2577
+ * @internal
2578
+ */
2579
+ async destroy() {
2580
+ this.destroyed || (this.destroyed = !0, this.initPromise && (this.initPromise.reject(
2581
+ new Error(`Component "${this.options.tag}" was destroyed before initialization completed`)
2582
+ ), this.initPromise = null), this.iframe && (tt(this.iframe), this.iframe = null), this.context === p.POPUP && this.hostWindow && at(this.hostWindow), this.hostWindow = null, this.prerenderElement && (this.prerenderElement.remove(), this.prerenderElement = null), await this.cleanup.cleanup(), this.event.emit(f.DESTROY), this.callPropCallback("onDestroy"));
2583
+ }
2584
+ }
2585
+ class yt {
2586
+ /**
2587
+ * Creates a new HostComponent instance.
2588
+ *
2589
+ * @param payload - The payload parsed from window.name
2590
+ * @param propDefinitions - Optional prop definitions for deserialization
2591
+ */
2592
+ constructor(e, s = {}) {
2593
+ this.propDefinitions = s, this.uid = e.uid, this.tag = e.tag, this.consumerDomain = e.consumerDomain, this.event = new me(), this.messenger = new ye(this.uid, window, j(), this.consumerDomain), this.setupMessageHandlers(), this.consumerWindow = this.resolveConsumerWindow(), this.bridge = new B(this.messenger), this.hostProps = this.buildHostProps(e), window.hostProps = this.hostProps, this.sendInit();
2594
+ }
2595
+ /** The hostProps object containing props and control methods passed from the consumer. */
2596
+ hostProps;
2597
+ /** Event emitter for lifecycle events. */
2598
+ event;
2599
+ /** @internal */
2600
+ uid;
2601
+ /** @internal */
2602
+ tag;
2603
+ /** @internal */
2604
+ consumerWindow;
2605
+ /** @internal */
2606
+ consumerDomain;
2607
+ /** @internal */
2608
+ messenger;
2609
+ /** @internal */
2610
+ bridge;
2611
+ /** @internal */
2612
+ propsHandlers = /* @__PURE__ */ new Set();
2613
+ /** @internal */
2614
+ consumerProps;
2615
+ /** @internal */
2616
+ initError = null;
2617
+ /**
2618
+ * Returns the hostProps object.
2619
+ *
2620
+ * @returns The hostProps object with props and control methods
2621
+ */
2622
+ getProps() {
2623
+ return this.hostProps;
2624
+ }
2625
+ /**
2626
+ * Resolves the consumer window reference (iframe parent or popup opener).
2627
+ * @internal
2628
+ */
2629
+ resolveConsumerWindow() {
2630
+ if (Le()) {
2631
+ const e = Fe();
2632
+ if (e) return e;
2633
+ }
2634
+ if (Ae()) {
2635
+ const e = $e();
2636
+ if (e) return e;
2637
+ }
2638
+ throw new Error("Could not resolve consumer window");
2639
+ }
2640
+ /**
2641
+ * Builds the hostProps object with deserialized props and control methods.
2642
+ * @internal
2643
+ */
2644
+ buildHostProps(e) {
2645
+ const s = de(
2646
+ e.props,
2647
+ this.propDefinitions,
2648
+ this.messenger,
2649
+ this.bridge,
2650
+ this.consumerWindow,
2651
+ this.consumerDomain
2652
+ );
2653
+ return this.consumerProps = s, {
2654
+ ...s,
2655
+ uid: this.uid,
2656
+ tag: this.tag,
2657
+ close: () => this.close(),
2658
+ focus: () => this.focus(),
2659
+ resize: (n) => this.resize(n),
2660
+ show: () => this.show(),
2661
+ hide: () => this.hide(),
2662
+ onProps: (n) => this.onProps(n),
2663
+ onError: (n) => this.onError(n),
2664
+ getConsumer: () => this.consumerWindow,
2665
+ getConsumerDomain: () => this.consumerDomain,
2666
+ export: (n) => this.exportData(n),
2667
+ consumer: {
2668
+ props: this.consumerProps,
2669
+ export: (n) => this.consumerExport(n)
2670
+ },
2671
+ getPeerInstances: (n) => this.getPeerInstances(n),
2672
+ children: this.buildNestedComponents(e.children)
2673
+ };
2674
+ }
2675
+ /**
2676
+ * Sends initialization message to the consumer.
2677
+ * @internal
2678
+ */
2679
+ async sendInit() {
2680
+ try {
2681
+ await this.messenger.send(
2682
+ this.consumerWindow,
2683
+ this.consumerDomain,
2684
+ u.INIT,
2685
+ { uid: this.uid, tag: this.tag }
2686
+ );
2687
+ } catch (e) {
2688
+ const s = e instanceof Error ? e : new Error(String(e));
2689
+ this.initError = s, this.event.emit(f.ERROR, {
2690
+ type: "init_failed",
2691
+ message: `Failed to initialize host component: ${s.message}`,
2692
+ error: s
2693
+ }), console.error("Failed to send init message:", e);
2694
+ }
2695
+ }
2696
+ /**
2697
+ * Returns the initialization error if one occurred.
2698
+ *
2699
+ * @returns The initialization error or null if successful
2700
+ */
2701
+ getInitError() {
2702
+ return this.initError;
2703
+ }
2704
+ /**
2705
+ * Requests the consumer to close this component.
2706
+ * @internal
2707
+ */
2708
+ async close() {
2709
+ await this.messenger.send(
2710
+ this.consumerWindow,
2711
+ this.consumerDomain,
2712
+ u.CLOSE,
2713
+ {}
2714
+ );
2715
+ }
2716
+ /**
2717
+ * Focuses this window and notifies the consumer.
2718
+ * @internal
2719
+ */
2720
+ async focus() {
2721
+ window.focus(), await this.messenger.send(
2722
+ this.consumerWindow,
2723
+ this.consumerDomain,
2724
+ u.FOCUS,
2725
+ {}
2726
+ );
2727
+ }
2728
+ /**
2729
+ * Requests the consumer to resize this component.
2730
+ * @internal
2731
+ */
2732
+ async resize(e) {
2733
+ await this.messenger.send(
2734
+ this.consumerWindow,
2735
+ this.consumerDomain,
2736
+ u.RESIZE,
2737
+ e
2738
+ );
2739
+ }
2740
+ /**
2741
+ * Requests the consumer to show this component.
2742
+ * @internal
2743
+ */
2744
+ async show() {
2745
+ await this.messenger.send(
2746
+ this.consumerWindow,
2747
+ this.consumerDomain,
2748
+ u.SHOW,
2749
+ {}
2750
+ );
2751
+ }
2752
+ /**
2753
+ * Requests the consumer to hide this component.
2754
+ * @internal
2755
+ */
2756
+ async hide() {
2757
+ await this.messenger.send(
2758
+ this.consumerWindow,
2759
+ this.consumerDomain,
2760
+ u.HIDE,
2761
+ {}
2762
+ );
2763
+ }
2764
+ /**
2765
+ * Subscribes to prop updates from the consumer.
2766
+ * @internal
2767
+ */
2768
+ onProps(e) {
2769
+ return this.propsHandlers.add(e), {
2770
+ cancel: () => this.propsHandlers.delete(e)
2771
+ };
2772
+ }
2773
+ /**
2774
+ * Reports an error to the consumer.
2775
+ * @internal
2776
+ */
2777
+ async onError(e) {
2778
+ await this.messenger.send(
2779
+ this.consumerWindow,
2780
+ this.consumerDomain,
2781
+ u.ERROR,
2782
+ {
2783
+ message: e.message,
2784
+ stack: e.stack
2785
+ }
2786
+ );
2787
+ }
2788
+ /**
2789
+ * Exports data or methods to the consumer.
2790
+ * @internal
2791
+ */
2792
+ async exportData(e) {
2793
+ await this.messenger.send(
2794
+ this.consumerWindow,
2795
+ this.consumerDomain,
2796
+ u.EXPORT,
2797
+ e
2798
+ );
2799
+ }
2800
+ /**
2801
+ * Exports data to the consumer for bidirectional communication.
2802
+ * @internal
2803
+ */
2804
+ async consumerExport(e) {
2805
+ await this.messenger.send(
2806
+ this.consumerWindow,
2807
+ this.consumerDomain,
2808
+ u.CONSUMER_EXPORT,
2809
+ e
2810
+ );
2811
+ }
2812
+ /**
2813
+ * Gets information about peer component instances.
2814
+ * @internal
2815
+ */
2816
+ async getPeerInstances(e) {
2817
+ return await this.messenger.send(
2818
+ this.consumerWindow,
2819
+ this.consumerDomain,
2820
+ u.GET_SIBLINGS,
2821
+ { uid: this.uid, tag: this.tag, options: e }
2822
+ ) ?? [];
2823
+ }
2824
+ /**
2825
+ * Builds nested component factories from refs passed by the consumer.
2826
+ * @internal
2827
+ */
2828
+ buildNestedComponents(e) {
2829
+ if (!e) return;
2830
+ const s = {};
2831
+ for (const [n, i] of Object.entries(e))
2832
+ try {
2833
+ s[n] = Se({
2834
+ tag: i.tag,
2835
+ url: i.url,
2836
+ props: i.props,
2837
+ dimensions: i.dimensions,
2838
+ defaultContext: i.defaultContext
2839
+ });
2840
+ } catch (r) {
2841
+ console.warn(`Failed to create nested component "${n}":`, r);
2842
+ }
2843
+ return Object.keys(s).length > 0 ? s : void 0;
2844
+ }
2845
+ /**
2846
+ * Sets up message handlers for consumer communication.
2847
+ * @internal
2848
+ */
2849
+ setupMessageHandlers() {
2850
+ this.messenger.on(u.PROPS, (e) => {
2851
+ try {
2852
+ const s = de(
2853
+ e,
2854
+ this.propDefinitions,
2855
+ this.messenger,
2856
+ this.bridge,
2857
+ this.consumerWindow,
2858
+ this.consumerDomain
2859
+ );
2860
+ Object.assign(this.hostProps, s);
2861
+ for (const n of this.propsHandlers)
2862
+ try {
2863
+ n(s);
2864
+ } catch (i) {
2865
+ console.error("Error in props handler:", i);
2866
+ }
2867
+ return this.event.emit(f.PROPS, s), { success: !0 };
2868
+ } catch (s) {
2869
+ const n = s instanceof Error ? s : new Error(String(s));
2870
+ throw console.error("Error deserializing props:", n), this.event.emit(f.ERROR, n), n;
2871
+ }
2872
+ });
2873
+ }
2874
+ /**
2875
+ * Destroys the host component and cleans up resources.
2876
+ */
2877
+ destroy() {
2878
+ this.messenger.destroy(), this.bridge.destroy(), this.event.removeAllListeners(), this.propsHandlers.clear();
2879
+ }
2880
+ }
2881
+ let v = null;
2882
+ function xe(t) {
2883
+ if (v)
2884
+ return v;
2885
+ if (!J())
2886
+ return null;
2887
+ const e = Ue();
2888
+ return e ? (v = new yt(
2889
+ e,
2890
+ t
2891
+ ), v) : (console.error("Failed to parse ForgeFrame payload from window.name"), null);
2892
+ }
2893
+ function _t() {
2894
+ return J();
2895
+ }
2896
+ function wt() {
2897
+ return J();
2898
+ }
2899
+ function Et() {
2900
+ return window.hostProps;
2901
+ }
2902
+ const S = /* @__PURE__ */ new Map();
2903
+ function bt(t) {
2904
+ if (!t.tag)
2905
+ throw new Error("Component tag is required");
2906
+ if (!/^[a-z][a-z0-9-]*$/.test(t.tag))
2907
+ throw new Error(
2908
+ `Invalid component tag "${t.tag}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`
2909
+ );
2910
+ if (!t.url)
2911
+ throw new Error("Component url is required");
2912
+ if (typeof t.url == "string")
2913
+ try {
2914
+ new URL(t.url, window.location.origin);
2915
+ } catch {
2916
+ throw new Error(
2917
+ `Invalid component URL "${t.url}". Must be a valid absolute or relative URL.`
2918
+ );
2919
+ }
2920
+ if (S.has(t.tag))
2921
+ throw new Error(`Component "${t.tag}" is already registered`);
2922
+ }
2923
+ function Se(t) {
2924
+ bt(t);
2925
+ const e = [];
2926
+ let s;
2927
+ if (H(t.tag)) {
2928
+ const i = xe(t.props);
2929
+ i && (s = i.hostProps);
2930
+ }
2931
+ const n = function(i = {}) {
2932
+ const r = new Q(t, i);
2933
+ return e.push(r), r.event.once("destroy", () => {
2934
+ const o = e.indexOf(r);
2935
+ o !== -1 && e.splice(o, 1);
2936
+ }), r;
2937
+ };
2938
+ return n.instances = e, n.isHost = () => H(t.tag), n.isEmbedded = () => H(t.tag), n.hostProps = s, n.canRenderTo = async (i) => {
2939
+ try {
2940
+ return !!(_e(i) || t.domain);
2941
+ } catch {
2942
+ return !1;
2943
+ }
2944
+ }, S.set(t.tag, n), n;
2945
+ }
2946
+ function Pt(t) {
2947
+ return S.get(t);
2948
+ }
2949
+ async function Rt(t) {
2950
+ await t.close();
2951
+ }
2952
+ async function Oe(t) {
2953
+ const e = S.get(t);
2954
+ if (!e) return;
2955
+ const s = [...e.instances];
2956
+ await Promise.all(s.map((n) => n.close()));
2957
+ }
2958
+ async function xt() {
2959
+ const t = Array.from(S.keys());
2960
+ await Promise.all(t.map((e) => Oe(e)));
2961
+ }
2962
+ function St(t, e) {
2963
+ const { React: s } = e, { createElement: n, useRef: i, useEffect: r, useState: o, forwardRef: a } = s, c = a(
2964
+ function(g, y) {
2965
+ const {
2966
+ onRendered: b,
2967
+ onError: O,
2968
+ onClose: ee,
2969
+ context: Ce,
2970
+ className: te,
2971
+ style: se,
2972
+ ...F
2973
+ } = g, C = i(null), L = i(null), [ne, ve] = o(null);
2974
+ return r(() => {
2975
+ const x = C.current;
2976
+ if (!x) return;
2977
+ const _ = t(F);
2978
+ return L.current = _, b && _.event.once("rendered", b), ee && _.event.once("close", ee), O && _.event.on("error", O), _.render(x, Ce).catch((ie) => {
2979
+ ve(ie), O?.(ie);
2980
+ }), () => {
2981
+ _.close().catch(() => {
2982
+ }), L.current = null;
2983
+ };
2984
+ }, []), r(() => {
2985
+ const x = L.current;
2986
+ x && x.updateProps(F).catch((_) => {
2987
+ O?.(_);
2988
+ });
2989
+ }, [JSON.stringify(F)]), r(() => {
2990
+ y && typeof y == "object" && C.current && (y.current = C.current);
2991
+ }, [y]), ne ? n(
2992
+ "div",
2993
+ {
2994
+ className: te,
2995
+ style: { color: "red", padding: "16px", ...se }
2996
+ },
2997
+ `Error: ${ne.message}`
2998
+ ) : n("div", {
2999
+ ref: C,
3000
+ className: te,
3001
+ style: {
3002
+ display: "inline-block",
3003
+ ...se
3004
+ }
3005
+ });
3006
+ }
3007
+ ), l = `ForgeFrame(${t.name || "Component"})`;
3008
+ return c.displayName = l, c;
3009
+ }
3010
+ function Ot(t) {
3011
+ return function(s) {
3012
+ return St(s, { React: t });
3013
+ };
3014
+ }
3015
+ xe();
3016
+ const Ct = {
3017
+ /**
3018
+ * Create a new component definition.
3019
+ *
3020
+ * @remarks
3021
+ * This is the main entry point for defining components. Returns a
3022
+ * component factory function that can be called to create instances.
3023
+ *
3024
+ * @example
3025
+ * ```typescript
3026
+ * import ForgeFrame, { prop } from 'forgeframe';
3027
+ *
3028
+ * const MyComponent = ForgeFrame.create({
3029
+ * tag: 'my-component',
3030
+ * url: 'https://example.com/component',
3031
+ * props: {
3032
+ * email: prop.string().email(),
3033
+ * onLogin: prop.function<(user: { id: string }) => void>(),
3034
+ * },
3035
+ * });
3036
+ *
3037
+ * const instance = MyComponent({ email: 'user@example.com', onLogin: (user) => {} });
3038
+ * await instance.render('#container');
3039
+ * ```
3040
+ */
3041
+ create: Se,
3042
+ /**
3043
+ * Destroy a single component instance.
3044
+ *
3045
+ * @param instance - The component instance to destroy
3046
+ */
3047
+ destroy: Rt,
3048
+ /**
3049
+ * Destroy all instances of a specific component by tag.
3050
+ *
3051
+ * @param tag - The component tag name
3052
+ */
3053
+ destroyByTag: Oe,
3054
+ /**
3055
+ * Destroy all ForgeFrame component instances.
3056
+ */
3057
+ destroyAll: xt,
3058
+ /**
3059
+ * Check if the current window is a host component context.
3060
+ *
3061
+ * @remarks
3062
+ * A "host" is the embedded iframe or popup window that receives props
3063
+ * from the consumer (the embedding app).
3064
+ *
3065
+ * @returns True if running inside a ForgeFrame iframe/popup
3066
+ */
3067
+ isHost: _t,
3068
+ /**
3069
+ * Check if the current window is embedded by ForgeFrame.
3070
+ *
3071
+ * @remarks
3072
+ * This is an alias for {@link isHost} that uses more intuitive terminology.
3073
+ *
3074
+ * @returns True if running inside a ForgeFrame iframe/popup
3075
+ */
3076
+ isEmbedded: wt,
3077
+ /**
3078
+ * Get hostProps from the current host window.
3079
+ *
3080
+ * @remarks
3081
+ * Returns the props passed from the consumer plus built-in control methods.
3082
+ *
3083
+ * @returns The hostProps object if in host context, undefined otherwise
3084
+ */
3085
+ getHostProps: Et,
3086
+ /**
3087
+ * Serialization strategy constants.
3088
+ * @see {@link PROP_SERIALIZATION}
3089
+ */
3090
+ PROP_SERIALIZATION: I,
3091
+ /**
3092
+ * Rendering context constants (IFRAME, POPUP).
3093
+ * @see {@link CONTEXT}
3094
+ */
3095
+ CONTEXT: p,
3096
+ /**
3097
+ * Lifecycle event name constants.
3098
+ * @see {@link EVENT}
3099
+ */
3100
+ EVENT: f,
3101
+ /**
3102
+ * Error thrown when popup window fails to open.
3103
+ */
3104
+ PopupOpenError: Re,
3105
+ /**
3106
+ * Current library version.
3107
+ */
3108
+ VERSION: pe,
3109
+ /**
3110
+ * Check if a value is a Standard Schema (Zod, Valibot, ArkType, etc.)
3111
+ *
3112
+ * @param value - The value to check
3113
+ * @returns True if the value implements StandardSchemaV1
3114
+ *
3115
+ * @example
3116
+ * ```typescript
3117
+ * import { z } from 'zod';
3118
+ *
3119
+ * const schema = z.string();
3120
+ * if (ForgeFrame.isStandardSchema(schema)) {
3121
+ * // schema is StandardSchemaV1
3122
+ * }
3123
+ * ```
3124
+ */
3125
+ isStandardSchema: E,
3126
+ /**
3127
+ * Prop schema builders for defining component props.
3128
+ *
3129
+ * @remarks
3130
+ * Provides a fluent, Zod-like API for defining prop schemas with built-in
3131
+ * validation. All schemas implement StandardSchemaV1.
3132
+ *
3133
+ * @example
3134
+ * ```typescript
3135
+ * import ForgeFrame from 'forgeframe';
3136
+ *
3137
+ * const Component = ForgeFrame.create({
3138
+ * tag: 'my-component',
3139
+ * url: '/component',
3140
+ * props: {
3141
+ * name: ForgeFrame.prop.string(),
3142
+ * count: ForgeFrame.prop.number().default(0),
3143
+ * onSubmit: ForgeFrame.prop.function().optional(),
3144
+ * },
3145
+ * });
3146
+ * ```
3147
+ */
3148
+ prop: d
3149
+ };
3150
+ export {
3151
+ K as AnySchema,
3152
+ T as ArraySchema,
3153
+ X as BooleanSchema,
3154
+ p as CONTEXT,
3155
+ f as EVENT,
3156
+ G as EnumSchema,
3157
+ Ct as ForgeFrame,
3158
+ Y as FunctionSchema,
3159
+ Z as LiteralSchema,
3160
+ q as NumberSchema,
3161
+ k as ObjectSchema,
3162
+ I as PROP_SERIALIZATION,
3163
+ Re as PopupOpenError,
3164
+ m as PropSchema,
3165
+ V as StringSchema,
3166
+ pe as VERSION,
3167
+ Se as create,
3168
+ St as createReactComponent,
3169
+ Ct as default,
3170
+ Rt as destroy,
3171
+ xt as destroyAll,
3172
+ Oe as destroyByTag,
3173
+ Et as getHostProps,
3174
+ wt as isEmbedded,
3175
+ _t as isHost,
3176
+ E as isStandardSchema,
3177
+ d as prop,
3178
+ Ot as withReactComponent
3179
+ };