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.
- package/LICENSE +21 -0
- package/README.md +868 -0
- package/dist/communication/bridge.d.ts +167 -0
- package/dist/communication/index.d.ts +12 -0
- package/dist/communication/messenger.d.ts +142 -0
- package/dist/communication/protocol.d.ts +75 -0
- package/dist/constants.d.ts +161 -0
- package/dist/core/component.d.ts +137 -0
- package/dist/core/consumer.d.ts +263 -0
- package/dist/core/host.d.ts +249 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/react.d.ts +224 -0
- package/dist/events/emitter.d.ts +150 -0
- package/dist/forgeframe.js +3179 -0
- package/dist/forgeframe.umd.cjs +5 -0
- package/dist/index.d.ts +230 -0
- package/dist/props/definitions.d.ts +63 -0
- package/dist/props/index.d.ts +13 -0
- package/dist/props/normalize.d.ts +59 -0
- package/dist/props/prop.d.ts +636 -0
- package/dist/props/schema.d.ts +196 -0
- package/dist/props/serialize.d.ts +60 -0
- package/dist/render/iframe.d.ts +213 -0
- package/dist/render/index.d.ts +38 -0
- package/dist/render/popup.d.ts +215 -0
- package/dist/render/templates.d.ts +202 -0
- package/dist/types.d.ts +1008 -0
- package/dist/utils/cleanup.d.ts +122 -0
- package/dist/utils/dimension.d.ts +50 -0
- package/dist/utils/index.d.ts +37 -0
- package/dist/utils/promise.d.ts +155 -0
- package/dist/utils/uid.d.ts +60 -0
- package/dist/window/helpers.d.ts +316 -0
- package/dist/window/index.d.ts +13 -0
- package/dist/window/name-payload.d.ts +188 -0
- package/dist/window/proxy.d.ts +168 -0
- package/package.json +47 -0
|
@@ -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
|
+
};
|