@jay-framework/secure 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1027 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { createJayContext, currentConstructionContext, withContext, childComp, useContext, GetTrapProxy, EVENT_TRAP, BaseReferencesManager, ManagedRefType, ComponentCollectionRefImpl, ComponentRefsImpl, normalizeUpdates, saveContext, restoreContext } from "@jay-framework/runtime";
8
+ import { makeJayComponent, createSignal, useReactive, COMPONENT_CONTEXT } from "@jay-framework/component";
9
+ import { deserialize, serialize } from "@jay-framework/serialization";
10
+ let _mainPort;
11
+ function setMainPort(port) {
12
+ _mainPort = port;
13
+ }
14
+ function useMainPort() {
15
+ return _mainPort;
16
+ }
17
+ let _workerPort;
18
+ function setWorkerPort(port) {
19
+ _workerPort = port;
20
+ }
21
+ function useWorkerPort() {
22
+ return _workerPort;
23
+ }
24
+ class JayPort {
25
+ constructor(channel, logger) {
26
+ __publicField(this, "messages", []);
27
+ __publicField(this, "endpoints", /* @__PURE__ */ new Map());
28
+ __publicField(this, "futureEndpointMessages", /* @__PURE__ */ new Map());
29
+ __publicField(this, "inBatch", false);
30
+ __publicField(this, "comps", /* @__PURE__ */ new Map());
31
+ __publicField(this, "lastCompId", 0);
32
+ __publicField(this, "newCompIdMessages", []);
33
+ __publicField(this, "isAutoFlushScheduled", false);
34
+ __publicField(this, "autoFlushTimeout");
35
+ __publicField(this, "getCompId", (parentCompId, coordinate) => {
36
+ let fullId = `${parentCompId}-${coordinate}`;
37
+ if (!this.comps.has(fullId)) {
38
+ let compId = Math.max(this.lastCompId, parentCompId) + 1;
39
+ this.lastCompId = compId;
40
+ this.comps.set(fullId, compId);
41
+ this.newCompIdMessages.push([fullId, compId]);
42
+ }
43
+ return this.comps.get(fullId);
44
+ });
45
+ this.channel = channel;
46
+ this.logger = logger;
47
+ channel.onMessages(
48
+ (messages, newCompIdMessages) => this.invoke(messages, newCompIdMessages)
49
+ );
50
+ }
51
+ getEndpoint(parentCompId, parentCoordinate) {
52
+ let compId = this.getCompId(parentCompId, parentCoordinate);
53
+ if (this.endpoints.has(compId))
54
+ return this.endpoints.get(compId);
55
+ let ep = new JayEndpoint(compId, this);
56
+ this.endpoints.set(compId, ep);
57
+ ep.setInitMessages(this.futureEndpointMessages.get(compId) || []);
58
+ this.futureEndpointMessages.delete(compId);
59
+ return ep;
60
+ }
61
+ getRootEndpoint() {
62
+ return this.getEndpoint(-1, [""]);
63
+ }
64
+ post(compId, outMessage) {
65
+ if (this.logger)
66
+ this.logger.logPost(compId, outMessage);
67
+ this.messages.push([compId, outMessage]);
68
+ if (!this.inBatch)
69
+ this.scheduleFlush();
70
+ }
71
+ batch(handler) {
72
+ if (this.inBatch)
73
+ return handler();
74
+ this.inBatch = true;
75
+ try {
76
+ return handler();
77
+ } finally {
78
+ if (this.messages.length > 0)
79
+ this.flush();
80
+ this.inBatch = false;
81
+ }
82
+ }
83
+ invoke(messages, newCompIdMessages) {
84
+ newCompIdMessages.forEach(([fullId, compId]) => {
85
+ this.comps.set(fullId, compId);
86
+ this.lastCompId = Math.max(this.lastCompId, compId);
87
+ });
88
+ this.batch(() => {
89
+ messages.forEach(([compId, message]) => {
90
+ let endpoint = this.endpoints.get(compId);
91
+ if (this.logger)
92
+ this.logger.logInvoke(compId, message, !!endpoint);
93
+ if (endpoint)
94
+ endpoint.invoke(message);
95
+ else {
96
+ if (!this.futureEndpointMessages.has(compId))
97
+ this.futureEndpointMessages.set(compId, [message]);
98
+ else
99
+ this.futureEndpointMessages.get(compId).push(message);
100
+ }
101
+ });
102
+ });
103
+ }
104
+ flush() {
105
+ this.channel.postMessages(this.messages, this.newCompIdMessages);
106
+ this.messages = [];
107
+ this.newCompIdMessages = [];
108
+ if (this.isAutoFlushScheduled) {
109
+ this.isAutoFlushScheduled = false;
110
+ clearTimeout(this.autoFlushTimeout);
111
+ }
112
+ }
113
+ scheduleFlush() {
114
+ this.isAutoFlushScheduled = true;
115
+ this.autoFlushTimeout = setTimeout(() => {
116
+ this.autoFlushTimeout = void 0;
117
+ this.isAutoFlushScheduled = false;
118
+ this.flush();
119
+ });
120
+ }
121
+ }
122
+ class JayEndpoint {
123
+ constructor(compId, port) {
124
+ __publicField(this, "handler");
125
+ __publicField(this, "initMessages", []);
126
+ this.compId = compId;
127
+ this.port = port;
128
+ }
129
+ post(outMessage) {
130
+ this.port.post(this.compId, outMessage);
131
+ }
132
+ onUpdate(handler) {
133
+ this.handler = handler;
134
+ this.initMessages.forEach((message) => handler(message));
135
+ this.initMessages = [];
136
+ }
137
+ invoke(inMessage) {
138
+ this?.handler(inMessage);
139
+ }
140
+ setInitMessages(initMessages) {
141
+ this.initMessages = initMessages;
142
+ }
143
+ }
144
+ class JayPortLoggerConsole {
145
+ logPost(compId, message) {
146
+ console.log("[port] post", compId, message);
147
+ }
148
+ logInvoke(compId, message, endpointFound) {
149
+ console.log("[port] invoke", compId, message);
150
+ }
151
+ }
152
+ const SYN = "SYN";
153
+ const ACK = "ACK";
154
+ class HandshakeMessageJayChannel {
155
+ constructor(worker) {
156
+ __publicField(this, "handler");
157
+ __publicField(this, "worker");
158
+ __publicField(this, "handshakeComplete", false);
159
+ __publicField(this, "pendingMessages", []);
160
+ __publicField(this, "workerOnMessage", (ev) => {
161
+ if (ev.data === SYN || ev.data === ACK) {
162
+ if (!this.handshakeComplete) {
163
+ if (ev.data === SYN)
164
+ this.worker.postMessage(ACK);
165
+ this.handshakeComplete = true;
166
+ this.pendingMessages.forEach((message) => this.worker.postMessage(message));
167
+ this.pendingMessages = [];
168
+ }
169
+ } else {
170
+ let { messages, newCompIdMessages } = ev.data;
171
+ if (this.handler)
172
+ this.handler(messages, newCompIdMessages);
173
+ }
174
+ });
175
+ worker.addEventListener("message", this.workerOnMessage);
176
+ this.worker = worker;
177
+ this.worker.postMessage(SYN);
178
+ }
179
+ onMessages(handler) {
180
+ this.handler = handler;
181
+ }
182
+ postMessages(messages, newCompIdMessages) {
183
+ if (!this.handshakeComplete)
184
+ this.pendingMessages.push({ messages, newCompIdMessages });
185
+ else
186
+ this.worker.postMessage({ messages, newCompIdMessages });
187
+ }
188
+ }
189
+ const SECURE_COMPONENT_MARKER = createJayContext();
190
+ const SECURE_COORDINATE_MARKER = createJayContext();
191
+ function secureChildComp(compCreator, getProps, ref) {
192
+ currentConstructionContext();
193
+ let coordinate = ref.coordinate;
194
+ return withContext(SECURE_COORDINATE_MARKER, { coordinate }, () => {
195
+ return childComp(compCreator, getProps, ref);
196
+ });
197
+ }
198
+ var JayPortMessageType = /* @__PURE__ */ ((JayPortMessageType2) => {
199
+ JayPortMessageType2[JayPortMessageType2["render"] = 0] = "render";
200
+ JayPortMessageType2[JayPortMessageType2["addEventListener"] = 1] = "addEventListener";
201
+ JayPortMessageType2[JayPortMessageType2["root"] = 2] = "root";
202
+ JayPortMessageType2[JayPortMessageType2["eventInvocation"] = 3] = "eventInvocation";
203
+ JayPortMessageType2[JayPortMessageType2["removeEventListener"] = 4] = "removeEventListener";
204
+ JayPortMessageType2[JayPortMessageType2["nativeExec"] = 5] = "nativeExec";
205
+ JayPortMessageType2[JayPortMessageType2["nativeExecResult"] = 6] = "nativeExecResult";
206
+ JayPortMessageType2[JayPortMessageType2["rootApiInvoke"] = 7] = "rootApiInvoke";
207
+ JayPortMessageType2[JayPortMessageType2["rootApiReturns"] = 8] = "rootApiReturns";
208
+ return JayPortMessageType2;
209
+ })(JayPortMessageType || {});
210
+ function rootApiReturns(callId, returns, error) {
211
+ return {
212
+ callId,
213
+ returns,
214
+ error,
215
+ type: 8
216
+ /* rootApiReturns */
217
+ };
218
+ }
219
+ function renderMessage(patch) {
220
+ return {
221
+ patch,
222
+ type: 0
223
+ /* render */
224
+ };
225
+ }
226
+ function addEventListenerMessage(refName, eventType, nativeId) {
227
+ return {
228
+ refName,
229
+ eventType,
230
+ nativeId,
231
+ type: 1
232
+ /* addEventListener */
233
+ };
234
+ }
235
+ function removeEventListenerMessage(refName, eventType) {
236
+ return {
237
+ refName,
238
+ eventType,
239
+ type: 4
240
+ /* removeEventListener */
241
+ };
242
+ }
243
+ function eventInvocationMessage(eventType, coordinate, eventData) {
244
+ return {
245
+ coordinate,
246
+ eventType,
247
+ eventData,
248
+ type: 3
249
+ /* eventInvocation */
250
+ };
251
+ }
252
+ function rootComponentViewState(patch) {
253
+ return {
254
+ patch,
255
+ type: 2
256
+ /* root */
257
+ };
258
+ }
259
+ function nativeExec(nativeId, correlationId, refName, coordinate) {
260
+ return {
261
+ refName,
262
+ nativeId,
263
+ correlationId,
264
+ coordinate,
265
+ type: 5
266
+ /* nativeExec */
267
+ };
268
+ }
269
+ function nativeExecResult(correlationId, result, error, refName) {
270
+ return {
271
+ refName,
272
+ result,
273
+ correlationId,
274
+ error,
275
+ type: 6
276
+ /* nativeExecResult */
277
+ };
278
+ }
279
+ function rootApiInvoke(apiName, callId, params) {
280
+ return {
281
+ apiName,
282
+ callId,
283
+ params,
284
+ type: 7
285
+ /* rootApiInvoke */
286
+ };
287
+ }
288
+ function makeComponentBridgeConstructor(props, refs) {
289
+ let [viewState, setViewState] = createSignal({});
290
+ let reactive = useReactive();
291
+ let { endpoint, port, funcRepository } = useContext(SECURE_COMPONENT_MARKER);
292
+ let ongoingAPICalls = {};
293
+ let eventHandlers = {};
294
+ let deserializedViewState, nextDeserialize = deserialize;
295
+ endpoint.onUpdate((message) => {
296
+ switch (message.type) {
297
+ case JayPortMessageType.render:
298
+ reactive.batchReactions(() => {
299
+ [deserializedViewState, nextDeserialize] = nextDeserialize(message.patch);
300
+ setViewState(deserializedViewState);
301
+ });
302
+ break;
303
+ case JayPortMessageType.addEventListener:
304
+ {
305
+ let { eventType, nativeId } = message;
306
+ refs[message.refName].addEventListener(
307
+ eventType,
308
+ (event) => {
309
+ port.batch(() => {
310
+ if (message.nativeId) {
311
+ let eventData = funcRepository[nativeId](event);
312
+ endpoint.post(
313
+ eventInvocationMessage(
314
+ eventType,
315
+ event.coordinate,
316
+ eventData
317
+ )
318
+ );
319
+ } else
320
+ endpoint.post(
321
+ eventInvocationMessage(eventType, event.coordinate)
322
+ );
323
+ });
324
+ }
325
+ );
326
+ }
327
+ break;
328
+ case JayPortMessageType.rootApiReturns:
329
+ let { callId, error, returns } = message;
330
+ if (ongoingAPICalls[callId]) {
331
+ if (error)
332
+ ongoingAPICalls[callId][1](error);
333
+ else
334
+ ongoingAPICalls[callId][0](returns);
335
+ delete ongoingAPICalls[callId];
336
+ }
337
+ break;
338
+ case JayPortMessageType.eventInvocation: {
339
+ let { eventType, eventData } = message;
340
+ eventHandlers[eventType]({ event: eventData, coordinate: [""], viewState: null });
341
+ break;
342
+ }
343
+ case JayPortMessageType.nativeExec: {
344
+ let { nativeId, refName, coordinate, correlationId } = message;
345
+ let ref = refs[refName];
346
+ port.batch(async () => {
347
+ try {
348
+ let result = ref.find ? await ref.find(
349
+ (vs, c) => c.length === coordinate.length && coordinate.reduce(
350
+ (acc, el1, i) => acc && c[i] === el1,
351
+ true
352
+ )
353
+ ).exec$(
354
+ (elem, vs) => funcRepository[nativeId](elem, vs)
355
+ ) : await ref.exec$(
356
+ (elem, vs) => funcRepository[nativeId](
357
+ elem,
358
+ vs
359
+ )
360
+ );
361
+ endpoint.post(nativeExecResult(correlationId, result, void 0, refName));
362
+ } catch (err) {
363
+ endpoint.post(
364
+ nativeExecResult(correlationId, void 0, err.message, refName)
365
+ );
366
+ }
367
+ });
368
+ }
369
+ }
370
+ });
371
+ let nextCallId = 0;
372
+ let invokeAPI = (functionName, args) => {
373
+ let callId = nextCallId++;
374
+ port.batch(() => {
375
+ endpoint.post(rootApiInvoke(functionName, callId, args));
376
+ });
377
+ return new Promise((resolve, reject) => {
378
+ ongoingAPICalls[callId] = [resolve, reject];
379
+ });
380
+ };
381
+ let registerEvent = (eventType, handler) => {
382
+ eventHandlers[eventType] = handler;
383
+ port.batch(() => {
384
+ endpoint.post(addEventListenerMessage("", eventType));
385
+ });
386
+ };
387
+ return {
388
+ render: viewState,
389
+ invokeAPI,
390
+ registerEvent
391
+ };
392
+ }
393
+ function defineCompPublicAPI(comp, endpoint, options) {
394
+ if (options?.events)
395
+ comp["addEventListener"] = (eventType, handler) => comp.registerEvent(eventType, handler);
396
+ options?.functions?.forEach((functionName) => {
397
+ comp[functionName] = (...args) => {
398
+ return comp.invokeAPI(functionName, args);
399
+ };
400
+ });
401
+ }
402
+ function makeJayComponentBridge(render, options) {
403
+ let component = makeJayComponent(render, makeComponentBridgeConstructor);
404
+ return (props) => {
405
+ let { compId, port } = useContext(SECURE_COMPONENT_MARKER);
406
+ let { coordinate } = useContext(SECURE_COORDINATE_MARKER);
407
+ let endpoint = port.getEndpoint(compId, coordinate);
408
+ let newSecureComponentContext = {
409
+ endpoint,
410
+ compId: endpoint.compId,
411
+ port,
412
+ funcRepository: options?.funcRepository
413
+ };
414
+ return withContext(SECURE_COMPONENT_MARKER, newSecureComponentContext, () => {
415
+ let comp = component(props);
416
+ defineCompPublicAPI(comp, endpoint, options);
417
+ return comp;
418
+ });
419
+ };
420
+ }
421
+ function mainRoot(viewState, elementConstructor, funcRepository) {
422
+ let port = useMainPort();
423
+ let endpoint = port.getRootEndpoint();
424
+ let context = { compId: endpoint.compId, endpoint, port, funcRepository };
425
+ endpoint.onUpdate(async (message) => {
426
+ switch (message.type) {
427
+ case JayPortMessageType.nativeExec: {
428
+ let { nativeId, correlationId } = message;
429
+ try {
430
+ let result = await funcRepository[nativeId]();
431
+ port.batch(async () => {
432
+ endpoint.post(nativeExecResult(correlationId, result, void 0));
433
+ });
434
+ } catch (err) {
435
+ port.batch(async () => {
436
+ endpoint.post(nativeExecResult(correlationId, void 0, err.message));
437
+ });
438
+ }
439
+ break;
440
+ }
441
+ }
442
+ });
443
+ return withContext(SECURE_COMPONENT_MARKER, context, () => {
444
+ let patch, nextSerialize;
445
+ let element = port.batch(() => {
446
+ [patch, nextSerialize] = serialize(viewState);
447
+ endpoint.post(rootComponentViewState(patch));
448
+ return elementConstructor();
449
+ });
450
+ return {
451
+ dom: element.dom,
452
+ mount: element.mount,
453
+ unmount: element.unmount,
454
+ update: (newData) => {
455
+ element.update(newData);
456
+ port.batch(() => {
457
+ [patch, nextSerialize] = nextSerialize(newData);
458
+ endpoint.post(rootComponentViewState(patch));
459
+ });
460
+ }
461
+ };
462
+ });
463
+ }
464
+ function nativeExecId(id) {
465
+ let fn = () => null;
466
+ fn.id = id;
467
+ return fn;
468
+ }
469
+ function handler$(id) {
470
+ return nativeExecId(id);
471
+ }
472
+ function func$(id) {
473
+ return nativeExecId(id);
474
+ }
475
+ function funcGlobal$(id) {
476
+ return nativeExecId(id);
477
+ }
478
+ let nextCorrelationId = 0;
479
+ let promises$ = /* @__PURE__ */ new Map();
480
+ function correlatedPromise() {
481
+ let correlationId = nextCorrelationId++;
482
+ let resolve, reject;
483
+ let execPromise$ = new Promise((_resolve, _reject) => {
484
+ resolve = _resolve;
485
+ reject = _reject;
486
+ });
487
+ let corrPromise = { correlationId, execPromise$, resolve, reject };
488
+ promises$.set(correlationId, corrPromise);
489
+ return corrPromise;
490
+ }
491
+ function completeCorrelatedPromise(message) {
492
+ if (message.error)
493
+ promises$.get(message.correlationId)?.reject(message.error);
494
+ else
495
+ promises$.get(message.correlationId)?.resolve(message.result);
496
+ promises$.delete(message.correlationId);
497
+ }
498
+ const SANDBOX_BRIDGE_CONTEXT = createJayContext();
499
+ const SANDBOX_CREATION_CONTEXT = createJayContext();
500
+ class SecureReferencesManager extends BaseReferencesManager {
501
+ constructor(ep, eventWrapper) {
502
+ super(eventWrapper);
503
+ this.ep = ep;
504
+ this.eventWrapper = eventWrapper;
505
+ }
506
+ mkManagedRef(refType, refName) {
507
+ switch (refType) {
508
+ case ManagedRefType.element:
509
+ return new SecureHTMLElementRefsImpl(refName, this.ep);
510
+ case ManagedRefType.elementCollection:
511
+ return new SecureHTMLElementCollectionRefsImpl(refName, this.ep);
512
+ case ManagedRefType.component:
513
+ return new ComponentRefsImpl();
514
+ case ManagedRefType.componentCollection:
515
+ return new ComponentCollectionRefImpl();
516
+ }
517
+ }
518
+ currentContext() {
519
+ let { viewState, dataIds } = useContext(SANDBOX_CREATION_CONTEXT);
520
+ return { currData: viewState, coordinate: (refName) => [...dataIds, refName] };
521
+ }
522
+ static for(endpoint, eventWrapper, elem, elemCollection, comp, compCollection, childRefManagers) {
523
+ const refManager = new SecureReferencesManager(endpoint, eventWrapper);
524
+ return [
525
+ refManager,
526
+ refManager.mkRefs(elem, elemCollection, comp, compCollection, childRefManagers)
527
+ ];
528
+ }
529
+ static forElement(elem, elemCollection, comp, compCollection, childRefManagers) {
530
+ const parentComponentContext = useContext(SANDBOX_BRIDGE_CONTEXT);
531
+ const { reactive, getComponentInstance } = useContext(COMPONENT_CONTEXT);
532
+ const thisComponentEndpoint = parentComponentContext.port.getEndpoint(
533
+ parentComponentContext.compId,
534
+ parentComponentContext.coordinate
535
+ );
536
+ return SecureReferencesManager.for(
537
+ thisComponentEndpoint,
538
+ (orig, event) => {
539
+ return reactive.batchReactions(() => orig(event));
540
+ },
541
+ elem,
542
+ elemCollection,
543
+ comp,
544
+ compCollection,
545
+ childRefManagers
546
+ );
547
+ }
548
+ static forSandboxRoot(elem, elemCollection, comp, compCollection, childRefManagers) {
549
+ const { endpoint } = useContext(SANDBOX_CREATION_CONTEXT);
550
+ return SecureReferencesManager.for(
551
+ endpoint,
552
+ void 0,
553
+ elem,
554
+ elemCollection,
555
+ comp,
556
+ compCollection,
557
+ childRefManagers
558
+ );
559
+ }
560
+ }
561
+ class SecurePrivateRefs {
562
+ constructor(ref, ep) {
563
+ __publicField(this, "listeners", /* @__PURE__ */ new Map());
564
+ __publicField(this, "items", /* @__PURE__ */ new Map());
565
+ __publicField(this, "invoke", (type, coordinate, eventData) => {
566
+ let listener = this.listeners.get(type);
567
+ if (listener) {
568
+ let item = this.items.get(coordinate.toString());
569
+ if (item)
570
+ listener({
571
+ event: eventData,
572
+ viewState: item.viewState,
573
+ coordinate: item.coordinate
574
+ });
575
+ }
576
+ });
577
+ this.ref = ref;
578
+ this.ep = ep;
579
+ }
580
+ addEventListener(type, listener, options, nativeId) {
581
+ this.ep.post(addEventListenerMessage(this.ref, type, nativeId));
582
+ this.listeners.set(type, listener);
583
+ }
584
+ removeEventListener(type, listener, options) {
585
+ this.ep.post(removeEventListenerMessage(this.ref, type));
586
+ this.listeners.delete(type);
587
+ }
588
+ addRef(ref) {
589
+ let key = ref.coordinate.toString();
590
+ if (!this.items.has(key)) {
591
+ this.items.set(key, ref);
592
+ }
593
+ }
594
+ removeRef(ref) {
595
+ this.items.delete(ref.coordinate.toString());
596
+ }
597
+ }
598
+ class SecureHTMLElementRefImpl {
599
+ constructor(ref, ep, viewState, coordinate, parentCollection) {
600
+ __publicField(this, "listeners", /* @__PURE__ */ new Map());
601
+ __publicField(this, "invoke", (type, coordinate, eventData) => {
602
+ let listener = this.listeners.get(type);
603
+ if (listener)
604
+ listener({
605
+ event: eventData,
606
+ viewState: this.viewState,
607
+ coordinate
608
+ });
609
+ });
610
+ __publicField(this, "update", (newViewState) => {
611
+ this.viewState = newViewState;
612
+ });
613
+ this.ref = ref;
614
+ this.ep = ep;
615
+ this.viewState = viewState;
616
+ this.coordinate = coordinate;
617
+ this.parentCollection = parentCollection;
618
+ this.parentCollection?.addRef(this);
619
+ }
620
+ addEventListener(type, listener, options, nativeId) {
621
+ this.ep.post(addEventListenerMessage(this.ref, type, nativeId));
622
+ this.listeners.set(type, listener);
623
+ }
624
+ removeEventListener(type, listener, options) {
625
+ this.ep.post(removeEventListenerMessage(this.ref, type));
626
+ this.listeners.delete(type);
627
+ }
628
+ exec$(handler) {
629
+ let { execPromise$, correlationId } = correlatedPromise();
630
+ this.ep.post(
631
+ nativeExec(
632
+ handler.id,
633
+ correlationId,
634
+ this.ref,
635
+ this.coordinate
636
+ )
637
+ );
638
+ return execPromise$;
639
+ }
640
+ mount() {
641
+ this.parentCollection?.addRef(this);
642
+ }
643
+ unmount() {
644
+ this.parentCollection?.removeRef(this);
645
+ }
646
+ getPublicAPI() {
647
+ return newSecureHTMLElementPublicApiProxy(this);
648
+ }
649
+ }
650
+ class SecureHTMLElementRefsImpl extends SecurePrivateRefs {
651
+ mkManagedRef(currData, coordinate, eventWrapper) {
652
+ return new SecureHTMLElementRefImpl(this.ref, this.ep, currData, coordinate, this);
653
+ }
654
+ getPublicAPI() {
655
+ return newSecureHTMLElementPublicApiProxy(this);
656
+ }
657
+ exec$(handler) {
658
+ return [...this.items][0][1].exec$(handler);
659
+ }
660
+ }
661
+ class SecureHTMLElementCollectionRefsImpl extends SecurePrivateRefs {
662
+ mkManagedRef(currData, coordinate, eventWrapper) {
663
+ return new SecureHTMLElementRefImpl(this.ref, this.ep, currData, coordinate, this);
664
+ }
665
+ getPublicAPI() {
666
+ return newSecureHTMLElementPublicApiProxy(this);
667
+ }
668
+ find(predicate) {
669
+ for (const [, item] of this.items)
670
+ if (predicate(item.viewState, item.coordinate)) {
671
+ return item.getPublicAPI();
672
+ }
673
+ }
674
+ map(handler) {
675
+ let promises = [];
676
+ for (const [, item] of this.items) {
677
+ const handlerResponse = handler(item.getPublicAPI(), item.viewState, item.coordinate);
678
+ if (handlerResponse)
679
+ promises.push(handlerResponse);
680
+ }
681
+ return promises;
682
+ }
683
+ }
684
+ const SECURE_EVENT$_TRAP = (target, prop) => {
685
+ if (typeof prop === "string") {
686
+ if (prop.indexOf("on") === 0 && prop.at(-1) === "$") {
687
+ let eventName = prop.slice(2, -1);
688
+ return (func$2) => {
689
+ let regularHandler;
690
+ const handler = ({ event, viewState, coordinate }) => {
691
+ if (regularHandler)
692
+ regularHandler({ event, viewState, coordinate });
693
+ };
694
+ target.addEventListener(eventName, handler, void 0, func$2.id);
695
+ return {
696
+ then: (handler2) => {
697
+ regularHandler = handler2;
698
+ }
699
+ };
700
+ };
701
+ }
702
+ }
703
+ return false;
704
+ };
705
+ const SecureHTMLElementRefProxy = GetTrapProxy([SECURE_EVENT$_TRAP, EVENT_TRAP]);
706
+ function newSecureHTMLElementPublicApiProxy(ref) {
707
+ return new Proxy(ref, SecureHTMLElementRefProxy);
708
+ }
709
+ function mkBridgeElement(viewState, sandboxElements, endpoint, reactive, refManager, getComponentInstance, arraySerializationContext) {
710
+ let events = {};
711
+ let port = endpoint.port;
712
+ return withContext(
713
+ SANDBOX_CREATION_CONTEXT,
714
+ {
715
+ endpoint,
716
+ viewState,
717
+ dataIds: [],
718
+ isDynamic: false,
719
+ parentComponentReactive: reactive
720
+ },
721
+ () => {
722
+ let elements = sandboxElements();
723
+ let patch, nextSerialize = serialize;
724
+ let postUpdateMessage = (newViewState) => {
725
+ [patch, nextSerialize] = nextSerialize(newViewState, arraySerializationContext);
726
+ if (patch.length)
727
+ endpoint.post(renderMessage(patch));
728
+ };
729
+ let update = normalizeUpdates([postUpdateMessage, ...elements.map((el) => el.update)]);
730
+ update(viewState);
731
+ endpoint.onUpdate(async (inMessage) => {
732
+ switch (inMessage.type) {
733
+ case JayPortMessageType.eventInvocation: {
734
+ reactive.batchReactions(() => {
735
+ refManager.get(
736
+ inMessage.coordinate.slice(-1)[0]
737
+ ).invoke(
738
+ inMessage.eventType,
739
+ inMessage.coordinate,
740
+ inMessage.eventData
741
+ );
742
+ });
743
+ break;
744
+ }
745
+ case JayPortMessageType.nativeExecResult: {
746
+ reactive.batchReactions(() => {
747
+ completeCorrelatedPromise(inMessage);
748
+ });
749
+ break;
750
+ }
751
+ case JayPortMessageType.rootApiInvoke: {
752
+ let message = inMessage;
753
+ let returns, error;
754
+ try {
755
+ returns = await getComponentInstance()[message.apiName](message.params);
756
+ } catch (err) {
757
+ error = err;
758
+ }
759
+ port.batch(() => {
760
+ endpoint.post(rootApiReturns(message.callId, returns, error));
761
+ });
762
+ break;
763
+ }
764
+ case JayPortMessageType.addEventListener: {
765
+ let handler = ({ event, coordinate }) => {
766
+ port.batch(() => {
767
+ endpoint.post(
768
+ eventInvocationMessage(inMessage.eventType, coordinate, event)
769
+ );
770
+ });
771
+ };
772
+ events[inMessage.eventType] = handler;
773
+ getComponentInstance().addEventListener(inMessage.eventType, handler);
774
+ break;
775
+ }
776
+ case JayPortMessageType.removeEventListener: {
777
+ getComponentInstance().removeEventListener(
778
+ inMessage.eventType,
779
+ events[inMessage.eventType]
780
+ );
781
+ delete events[inMessage.eventType];
782
+ }
783
+ }
784
+ });
785
+ const mount = () => elements.forEach((_) => _.mount());
786
+ const unmount = () => elements.forEach((_) => _.unmount());
787
+ mount();
788
+ return refManager.applyToElement({
789
+ dom: void 0,
790
+ update,
791
+ mount,
792
+ unmount
793
+ });
794
+ }
795
+ );
796
+ }
797
+ function elementBridge(viewState, refManager, sandboxElements, arraySerializationContext = []) {
798
+ const parentComponentContext = useContext(SANDBOX_BRIDGE_CONTEXT);
799
+ const { reactive, getComponentInstance } = useContext(COMPONENT_CONTEXT);
800
+ const thisComponentEndpoint = parentComponentContext.port.getEndpoint(
801
+ parentComponentContext.compId,
802
+ parentComponentContext.coordinate
803
+ );
804
+ return mkBridgeElement(
805
+ viewState,
806
+ sandboxElements,
807
+ thisComponentEndpoint,
808
+ reactive,
809
+ refManager,
810
+ getComponentInstance,
811
+ arraySerializationContext
812
+ );
813
+ }
814
+ function sandboxElement(ref) {
815
+ return ref;
816
+ }
817
+ function sandboxChildComp(compCreator, getProps, ref) {
818
+ let { viewState, endpoint } = useContext(SANDBOX_CREATION_CONTEXT);
819
+ let coordinate = ref.coordinate;
820
+ let context = { compId: endpoint.compId, coordinate, port: endpoint.port };
821
+ let childComp2 = withContext(SANDBOX_BRIDGE_CONTEXT, context, () => {
822
+ return compCreator(getProps(viewState));
823
+ });
824
+ ref.set(childComp2);
825
+ ref.mount();
826
+ return {
827
+ update: (newViewState) => {
828
+ ref.update(newViewState);
829
+ childComp2.update(getProps(newViewState));
830
+ },
831
+ mount: () => {
832
+ ref.mount();
833
+ childComp2.mount();
834
+ },
835
+ unmount: () => {
836
+ ref.unmount();
837
+ childComp2.unmount();
838
+ }
839
+ };
840
+ }
841
+ function compareLists(oldList, newList, matchBy) {
842
+ let removedItems = [];
843
+ let addedItems = [];
844
+ let itemsToUpdate = [];
845
+ let newListIds = new Set(newList.map((item) => item[matchBy]));
846
+ let oldListIdsMap = new Map(oldList.map((item) => [item[matchBy], item]));
847
+ oldList.forEach((oldItem) => {
848
+ if (!newListIds.has(oldItem[matchBy]))
849
+ removedItems.push(oldItem);
850
+ });
851
+ newList.forEach((newItem) => {
852
+ if (!oldListIdsMap.has(newItem[matchBy]))
853
+ addedItems.push(newItem);
854
+ else {
855
+ let oldItem = oldListIdsMap.get(newItem[matchBy]);
856
+ let isModified = newItem !== oldItem;
857
+ if (isModified)
858
+ itemsToUpdate.push(newItem);
859
+ }
860
+ });
861
+ return { removedItems, addedItems, itemsToUpdate };
862
+ }
863
+ function sandboxForEach(getItems, matchBy, children) {
864
+ const { viewState, endpoint, dataIds, parentComponentReactive } = useContext(SANDBOX_CREATION_CONTEXT);
865
+ let lastItems = [];
866
+ let childElementsMap = /* @__PURE__ */ new Map();
867
+ let savedContext = saveContext();
868
+ let update = (viewState2) => {
869
+ let newItems = getItems(viewState2) || [];
870
+ let isModified = newItems !== lastItems;
871
+ if (isModified) {
872
+ let { removedItems, addedItems, itemsToUpdate } = compareLists(
873
+ lastItems,
874
+ newItems,
875
+ matchBy
876
+ );
877
+ addedItems.forEach((item) => {
878
+ let childElements = restoreContext(
879
+ savedContext,
880
+ () => withContext(
881
+ SANDBOX_CREATION_CONTEXT,
882
+ {
883
+ endpoint,
884
+ viewState: item,
885
+ dataIds: [...dataIds, item[matchBy]],
886
+ isDynamic: true,
887
+ parentComponentReactive
888
+ },
889
+ children
890
+ )
891
+ );
892
+ childElements.forEach((childElement) => childElement.mount());
893
+ childElementsMap.set(item[matchBy], childElements);
894
+ });
895
+ removedItems.forEach((item) => {
896
+ let childElements = childElementsMap.get(item[matchBy]);
897
+ childElements.forEach((childElement) => childElement.unmount());
898
+ childElementsMap.delete(item[matchBy]);
899
+ });
900
+ itemsToUpdate.forEach((item) => {
901
+ childElementsMap.get(item[matchBy]).forEach((childElement) => {
902
+ childElement.update(item);
903
+ });
904
+ });
905
+ lastItems = newItems;
906
+ }
907
+ };
908
+ let mountUnmount = (op) => () => {
909
+ childElementsMap.forEach(
910
+ (childElements) => childElements.forEach((childElement) => childElement[op]())
911
+ );
912
+ };
913
+ let mount = mountUnmount("mount");
914
+ let unmount = mountUnmount("unmount");
915
+ update(viewState);
916
+ return {
917
+ update,
918
+ mount,
919
+ unmount
920
+ };
921
+ }
922
+ function sandboxCondition(condition, children) {
923
+ let { viewState } = useContext(SANDBOX_CREATION_CONTEXT);
924
+ let state = condition(viewState);
925
+ let mounted = true;
926
+ let childMounted = true;
927
+ const updateChild = () => {
928
+ let newState = condition(viewState);
929
+ if (mounted) {
930
+ if (newState !== state || childMounted !== newState) {
931
+ newState ? children.forEach((_) => _.mount()) : children.forEach((_) => _.unmount());
932
+ childMounted = newState;
933
+ }
934
+ } else {
935
+ if (childMounted)
936
+ children.forEach((_) => _.unmount());
937
+ childMounted = false;
938
+ }
939
+ };
940
+ updateChild();
941
+ const update = (newViewState) => {
942
+ viewState = newViewState;
943
+ children.forEach((_) => _.update(newViewState));
944
+ updateChild();
945
+ };
946
+ const mount = () => {
947
+ mounted = true;
948
+ updateChild();
949
+ };
950
+ const unmount = () => {
951
+ mounted = false;
952
+ updateChild();
953
+ };
954
+ return { update, mount, unmount };
955
+ }
956
+ function sandboxRoot(sandboxElements) {
957
+ let port = useWorkerPort();
958
+ let endpoint = port.getRootEndpoint();
959
+ let elements;
960
+ let viewState, nextDeserialize = deserialize;
961
+ endpoint.onUpdate((inMessage) => {
962
+ switch (inMessage.type) {
963
+ case JayPortMessageType.root: {
964
+ [viewState, nextDeserialize] = nextDeserialize(inMessage.patch);
965
+ if (!elements) {
966
+ let context = {
967
+ viewState,
968
+ endpoint,
969
+ isDynamic: false,
970
+ dataIds: []
971
+ };
972
+ elements = withContext(SANDBOX_CREATION_CONTEXT, context, () => {
973
+ return sandboxElements();
974
+ });
975
+ } else {
976
+ [viewState, nextDeserialize] = nextDeserialize(inMessage.patch);
977
+ elements.forEach((element) => element.update(viewState));
978
+ }
979
+ break;
980
+ }
981
+ case JayPortMessageType.nativeExecResult: {
982
+ completeCorrelatedPromise(inMessage);
983
+ break;
984
+ }
985
+ }
986
+ });
987
+ }
988
+ function exec$(handler) {
989
+ let port = useWorkerPort();
990
+ let { execPromise$, correlationId } = correlatedPromise();
991
+ port.getRootEndpoint().post(
992
+ nativeExec(handler.id, correlationId)
993
+ );
994
+ return execPromise$;
995
+ }
996
+ export {
997
+ HandshakeMessageJayChannel,
998
+ JayEndpoint,
999
+ JayPort,
1000
+ JayPortLoggerConsole,
1001
+ SECURE_COORDINATE_MARKER,
1002
+ SecureHTMLElementCollectionRefsImpl,
1003
+ SecureHTMLElementRefImpl,
1004
+ SecurePrivateRefs,
1005
+ SecureReferencesManager,
1006
+ completeCorrelatedPromise,
1007
+ correlatedPromise,
1008
+ elementBridge,
1009
+ exec$,
1010
+ func$,
1011
+ funcGlobal$,
1012
+ handler$,
1013
+ mainRoot,
1014
+ makeJayComponentBridge,
1015
+ mkBridgeElement,
1016
+ newSecureHTMLElementPublicApiProxy,
1017
+ sandboxChildComp,
1018
+ sandboxCondition,
1019
+ sandboxElement,
1020
+ sandboxForEach,
1021
+ sandboxRoot,
1022
+ secureChildComp,
1023
+ setMainPort,
1024
+ setWorkerPort,
1025
+ useMainPort,
1026
+ useWorkerPort
1027
+ };