@adobe/uix-host 1.1.2 → 1.1.4
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/host.d.ts +9 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/index.js +204 -7
- package/dist/index.js.map +1 -1
- package/dist/port.d.ts +4 -1
- package/dist/port.d.ts.map +1 -1
- package/dist/utils/compareExtensions.d.ts +14 -0
- package/dist/utils/compareExtensions.d.ts.map +1 -0
- package/dist/utils/comparePackagesVersions.d.ts +2 -0
- package/dist/utils/comparePackagesVersions.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/host.ts +53 -0
- package/src/port.ts +78 -7
- package/src/utils/compareExtensions.ts +153 -0
- package/src/utils/comparePackagesVersions.ts +13 -0
package/dist/host.d.ts
CHANGED
|
@@ -38,10 +38,12 @@ export type HostEventError = HostEvent<"error", {
|
|
|
38
38
|
error: Error;
|
|
39
39
|
}>;
|
|
40
40
|
/** @public */
|
|
41
|
-
export type HostEvents = HostGuestEvent<"beforeload"> | HostGuestEvent<"load"> | HostEvent<"beforeunload"> | HostEvent<"unload"> | HostEventLoadAllGuests | HostEventContextChange | HostEventError;
|
|
41
|
+
export type HostEvents = HostGuestEvent<"beforeload"> | HostGuestEvent<"load"> | HostGuestEvent<"beforeunload"> | HostGuestEvent<"unload"> | HostEvent<"beforeunload"> | HostEvent<"unload"> | HostEventLoadAllGuests | HostEventContextChange | HostEventError;
|
|
42
42
|
/** @public */
|
|
43
43
|
export type InstalledExtensions = Record<Extension["id"], Extension["url"] | Extension>;
|
|
44
44
|
/** @public */
|
|
45
|
+
export type ExtensionsArray = Array<[string, Extension | string]>;
|
|
46
|
+
/** @public */
|
|
45
47
|
export type ExtensionsProvider = () => Promise<InstalledExtensions>;
|
|
46
48
|
/**
|
|
47
49
|
* Values for shared context. Must be a plain object, serializable to JSON.
|
|
@@ -151,6 +153,7 @@ export declare class Host extends Emitter<HostEvents> {
|
|
|
151
153
|
*/
|
|
152
154
|
error: HostEventError;
|
|
153
155
|
private static containerStyle;
|
|
156
|
+
private lastExtenstionList;
|
|
154
157
|
/**
|
|
155
158
|
* Unique string identifying the Host object.
|
|
156
159
|
*/
|
|
@@ -238,6 +241,11 @@ export declare class Host extends Emitter<HostEvents> {
|
|
|
238
241
|
* @returns Promise which resolves when all guests have been loaded.
|
|
239
242
|
*/
|
|
240
243
|
load(extensions: InstalledExtensions, options?: PortOptions): Promise<void>;
|
|
244
|
+
addLoadsNewGuests(extensions: InstalledExtensions, options?: PortOptions): Promise<void>;
|
|
245
|
+
/**
|
|
246
|
+
* Unload and remove a specific extension by its ID.
|
|
247
|
+
*/
|
|
248
|
+
removeGuest(id: string, extension: Extension): Promise<void>;
|
|
241
249
|
/**
|
|
242
250
|
* Unload all extensions and remove their frames/workers. Use this to unmount
|
|
243
251
|
* a UI or when switching to a different extensible UI.
|
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EAEV,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAgB,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EAEV,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAgB,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAK9C;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAExC,cAAc;AACd,MAAM,MAAM,SAAS,CACnB,IAAI,SAAS,MAAM,GAAG,MAAM,EAC5B,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AACxE,cAAc;AACd,KAAK,cAAc,CAAC,IAAI,SAAS,MAAM,IAAI,SAAS,CAClD,QAAQ,IAAI,EAAE,EACd;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAC5C,eAAe,EACf;IAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAAC,MAAM,EAAE,IAAI,EAAE,CAAA;CAAE,CACnC,CAAC;AAEF;;;GAGG;AAEH,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAC5C,eAAe,EACf;IAAE,OAAO,EAAE,mBAAmB,CAAA;CAAE,CACjC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,OAAO,EAAE;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAElE,cAAc;AACd,MAAM,MAAM,UAAU,GAClB,cAAc,CAAC,YAAY,CAAC,GAC5B,cAAc,CAAC,MAAM,CAAC,GACtB,cAAc,CAAC,cAAc,CAAC,GAC9B,cAAc,CAAC,QAAQ,CAAC,GACxB,SAAS,CAAC,cAAc,CAAC,GACzB,SAAS,CAAC,QAAQ,CAAC,GACnB,sBAAsB,GACtB,sBAAsB,GACtB,cAAc,CAAC;AAEnB,cAAc;AACd,MAAM,MAAM,mBAAmB,GAAG,MAAM,CACtC,SAAS,CAAC,IAAI,CAAC,EACf,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAC7B,CAAC;AAEF,cAAc;AACd,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC;AAElE,cAAc;AACd,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D,cAAc;AACd,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC;AAInD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,IAAK,SAAQ,OAAO,CAAC,UAAU,CAAC;IAC3C;;;OAGG;IACI,aAAa,EAAE,sBAAsB,CAAC;IAE7C;;;OAGG;IACI,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAEzC;;;OAGG;IACI,eAAe,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;IAErD;;;;OAIG;IACI,iBAAiB,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAEzD;;;;OAIG;IACI,WAAW,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE7C;;;OAGG;IACI,aAAa,EAAE,sBAAsB,CAAC;IAE7C;;;OAGG;IACI,KAAK,EAAE,cAAc,CAAC;IAE7B,OAAO,CAAC,MAAM,CAAC,cAAc,CAQ3B;IAEF,OAAO,CAAC,kBAAkB,CAA2B;IACrD;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,UAAS;IAChB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAa;IAC5B,OAAO,CAAC,qBAAqB,CAA0C;IACvE,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,aAAa,CAAsB;gBAC/B,MAAM,EAAE,UAAU;IAiB9B;;OAEG;IACH,eAAe,CAAC,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE;IACzC;;OAEG;IACH,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE;IAC5D;;OAEG;IACH,eAAe,CAAC,IAAI,SAAS,SAAS,EACpC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,GACjC,IAAI,CAAC,SAAS,CAAC,EAAE;IAgBpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAChD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,YAAY,CACV,MAAM,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,mBAAmB,GAC5D,IAAI;IACP,YAAY,CACV,MAAM,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,mBAAmB,GAC5D,IAAI;IAgBP;;;;;;;OAOG;IACG,IAAI,CACR,UAAU,EAAE,mBAAmB,EAC/B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC;IA4BV,iBAAiB,CACrB,UAAU,EAAE,mBAAmB,EAC/B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC;IAchB;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlE;;;OAGG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,OAAO,CAAC,sBAAsB;YAUhB,YAAY;IAyD1B,OAAO,CAAC,mBAAmB;CAY5B"}
|
package/dist/index.js
CHANGED
|
@@ -145,6 +145,24 @@ var normalizeIframe = (iframe) => {
|
|
|
145
145
|
}
|
|
146
146
|
};
|
|
147
147
|
|
|
148
|
+
// src/utils/comparePackagesVersions.ts
|
|
149
|
+
function compareVersions(v1, v2) {
|
|
150
|
+
var _a, _b;
|
|
151
|
+
const versionToArray = (v) => v.split(".").map((x) => Number(x) || 0);
|
|
152
|
+
const v1Array = versionToArray(v1);
|
|
153
|
+
const v2Array = versionToArray(v2);
|
|
154
|
+
const len = Math.max(v1Array.length, v2Array.length);
|
|
155
|
+
for (let i = 0; i < len; i++) {
|
|
156
|
+
const n1 = (_a = v1Array[i]) != null ? _a : 0;
|
|
157
|
+
const n2 = (_b = v2Array[i]) != null ? _b : 0;
|
|
158
|
+
if (n1 > n2)
|
|
159
|
+
return 1;
|
|
160
|
+
if (n1 < n2)
|
|
161
|
+
return -1;
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
148
166
|
// src/port.ts
|
|
149
167
|
var defaultOptions = {
|
|
150
168
|
timeout: 2e4,
|
|
@@ -164,6 +182,8 @@ var Port = class extends uixCore.Emitter {
|
|
|
164
182
|
super(config.id);
|
|
165
183
|
this.hostApis = {};
|
|
166
184
|
this.isLoaded = false;
|
|
185
|
+
this.isGuestReady = false;
|
|
186
|
+
this.guestReadyMessageHandler = null;
|
|
167
187
|
this.subscriptions = [];
|
|
168
188
|
const { timeout, debug } = { ...defaultOptions, ...config.options || {} };
|
|
169
189
|
this.timeout = timeout;
|
|
@@ -226,10 +246,17 @@ var Port = class extends uixCore.Emitter {
|
|
|
226
246
|
);
|
|
227
247
|
}
|
|
228
248
|
/**
|
|
229
|
-
* True when
|
|
249
|
+
* True when all extensions have loaded.
|
|
230
250
|
*/
|
|
231
251
|
isReady() {
|
|
232
|
-
|
|
252
|
+
if (this.guestVersion && this.guestVersion.length > 0) {
|
|
253
|
+
if (compareVersions(this.guestVersion, "1.1.3") >= 0) {
|
|
254
|
+
return this.isLoaded && !this.error && this.isGuestReady;
|
|
255
|
+
} else {
|
|
256
|
+
return this.isLoaded && !this.error;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
233
260
|
}
|
|
234
261
|
/**
|
|
235
262
|
* Loads the extension. Returns a promise which resolves when the extension
|
|
@@ -262,6 +289,17 @@ var Port = class extends uixCore.Emitter {
|
|
|
262
289
|
* Disconnect from the extension.
|
|
263
290
|
*/
|
|
264
291
|
async unload() {
|
|
292
|
+
if (this.guestReadyMessageHandler) {
|
|
293
|
+
window.removeEventListener("message", this.guestReadyMessageHandler);
|
|
294
|
+
this.guestReadyMessageHandler = null;
|
|
295
|
+
this.isGuestReady = false;
|
|
296
|
+
}
|
|
297
|
+
for (const unsubscribe of this.subscriptions) {
|
|
298
|
+
if (typeof unsubscribe === "function") {
|
|
299
|
+
unsubscribe();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
this.subscriptions = [];
|
|
265
303
|
if (this.guestServerFrame && this.guestServerFrame.parentElement) {
|
|
266
304
|
this.guestServerFrame.parentElement.removeChild(this.guestServerFrame);
|
|
267
305
|
this.guestServerFrame = void 0;
|
|
@@ -316,7 +354,6 @@ var Port = class extends uixCore.Emitter {
|
|
|
316
354
|
}
|
|
317
355
|
attachFrame(iframe, addedMethods = {}) {
|
|
318
356
|
normalizeIframe(iframe);
|
|
319
|
-
this.logger.log("attachFrame", iframe);
|
|
320
357
|
return uixCore.connectIframe(
|
|
321
358
|
iframe,
|
|
322
359
|
{
|
|
@@ -325,14 +362,23 @@ var Port = class extends uixCore.Emitter {
|
|
|
325
362
|
timeout: this.timeout
|
|
326
363
|
},
|
|
327
364
|
{
|
|
328
|
-
getSharedContext: () =>
|
|
329
|
-
|
|
365
|
+
getSharedContext: () => {
|
|
366
|
+
return this.sharedContext;
|
|
367
|
+
},
|
|
368
|
+
getConfiguration: () => {
|
|
369
|
+
return this.configuration;
|
|
370
|
+
},
|
|
330
371
|
invokeHostMethod: (address) => this.invokeHostMethod(address, addedMethods),
|
|
331
372
|
...addedMethods
|
|
373
|
+
},
|
|
374
|
+
(version) => {
|
|
375
|
+
this.guestVersion = version;
|
|
332
376
|
}
|
|
333
377
|
);
|
|
334
378
|
}
|
|
335
379
|
async connect() {
|
|
380
|
+
var _a;
|
|
381
|
+
let timeoutId;
|
|
336
382
|
const serverFrame = this.runtimeContainer.ownerDocument.createElement("iframe");
|
|
337
383
|
normalizeIframe(serverFrame);
|
|
338
384
|
serverFrame.setAttribute("aria-hidden", "true");
|
|
@@ -345,11 +391,35 @@ var Port = class extends uixCore.Emitter {
|
|
|
345
391
|
this
|
|
346
392
|
);
|
|
347
393
|
}
|
|
348
|
-
|
|
394
|
+
try {
|
|
395
|
+
this.guestServer = await this.attachFrame(serverFrame);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
(_a = this.logger) == null ? void 0 : _a.error(
|
|
398
|
+
`Failed to attach guest server for ${this.id}:`,
|
|
399
|
+
error
|
|
400
|
+
);
|
|
401
|
+
clearTimeout(timeoutId);
|
|
402
|
+
}
|
|
403
|
+
const handleMessage = (event) => {
|
|
404
|
+
var _a2;
|
|
405
|
+
if (event.data && event.data.type === "guest-ready" && event.source === serverFrame.contentWindow) {
|
|
406
|
+
(_a2 = this.logger) == null ? void 0 : _a2.log(
|
|
407
|
+
`[Port ${this.id}] Received guest-ready from our iframe (guest: ${event.data.guestId || "unknown"})`
|
|
408
|
+
);
|
|
409
|
+
this.isGuestReady = true;
|
|
410
|
+
if (this.logger) {
|
|
411
|
+
this.logger.info(`Guest ${this.id} reported ready status`);
|
|
412
|
+
}
|
|
413
|
+
this.emit("guestready", { guestPort: this });
|
|
414
|
+
window.removeEventListener("message", handleMessage);
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
window.addEventListener("message", handleMessage);
|
|
418
|
+
this.guestReadyMessageHandler = handleMessage;
|
|
349
419
|
this.isLoaded = true;
|
|
350
420
|
if (this.logger) {
|
|
351
421
|
this.logger.info(
|
|
352
|
-
`Guest ${this.id} established connection, received methods`,
|
|
422
|
+
`Guest ${this.id} established connection, received methods, and reported ready`,
|
|
353
423
|
this.apis,
|
|
354
424
|
this
|
|
355
425
|
);
|
|
@@ -544,11 +614,102 @@ function addMetrics(host) {
|
|
|
544
614
|
});
|
|
545
615
|
}
|
|
546
616
|
|
|
617
|
+
// src/utils/compareExtensions.ts
|
|
618
|
+
function compareExtensions(extensions1, extensions2) {
|
|
619
|
+
const result = {
|
|
620
|
+
added: {},
|
|
621
|
+
removed: {},
|
|
622
|
+
modified: {},
|
|
623
|
+
hasChanges: false
|
|
624
|
+
};
|
|
625
|
+
const keys1 = new Set(Object.keys(extensions1));
|
|
626
|
+
const keys2 = new Set(Object.keys(extensions2));
|
|
627
|
+
const allKeys = /* @__PURE__ */ new Set([...keys1, ...keys2]);
|
|
628
|
+
for (const key of allKeys) {
|
|
629
|
+
const exists1 = keys1.has(key);
|
|
630
|
+
const exists2 = keys2.has(key);
|
|
631
|
+
if (!exists1 && exists2) {
|
|
632
|
+
result.added[key] = extensions2[key];
|
|
633
|
+
result.hasChanges = true;
|
|
634
|
+
} else if (exists1 && !exists2) {
|
|
635
|
+
result.removed[key] = extensions1[key];
|
|
636
|
+
result.hasChanges = true;
|
|
637
|
+
} else if (exists1 && exists2) {
|
|
638
|
+
const ext1 = extensions1[key];
|
|
639
|
+
const ext2 = extensions2[key];
|
|
640
|
+
if (!areExtensionsEqual(ext1, ext2)) {
|
|
641
|
+
result.modified[key] = {
|
|
642
|
+
old: ext1,
|
|
643
|
+
new: ext2
|
|
644
|
+
};
|
|
645
|
+
result.hasChanges = true;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return result;
|
|
650
|
+
}
|
|
651
|
+
function areExtensionsEqual(ext1, ext2) {
|
|
652
|
+
if (typeof ext1 !== typeof ext2) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
if (typeof ext1 === "string" && typeof ext2 === "string") {
|
|
656
|
+
return ext1 === ext2;
|
|
657
|
+
}
|
|
658
|
+
if (typeof ext1 === "object" && typeof ext2 === "object") {
|
|
659
|
+
if (ext1.id !== ext2.id || ext1.url !== ext2.url) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
const ep1 = ext1.extensionPoints || [];
|
|
663
|
+
const ep2 = ext2.extensionPoints || [];
|
|
664
|
+
if (ep1.length !== ep2.length) {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
const sortedEp1 = [...ep1].sort();
|
|
668
|
+
const sortedEp2 = [...ep2].sort();
|
|
669
|
+
for (let i = 0; i < sortedEp1.length; i++) {
|
|
670
|
+
if (sortedEp1[i] !== sortedEp2[i]) {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return deepEqual(ext1.configuration, ext2.configuration);
|
|
675
|
+
}
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
function deepEqual(obj1, obj2) {
|
|
679
|
+
if (obj1 === obj2) {
|
|
680
|
+
return true;
|
|
681
|
+
}
|
|
682
|
+
if (obj1 == null || obj2 == null) {
|
|
683
|
+
return obj1 === obj2;
|
|
684
|
+
}
|
|
685
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object") {
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
const keys1 = Object.keys(obj1);
|
|
689
|
+
const keys2 = Object.keys(obj2);
|
|
690
|
+
if (keys1.length !== keys2.length) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
for (const key of keys1) {
|
|
694
|
+
if (!keys2.includes(key)) {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
if (!deepEqual(
|
|
698
|
+
obj1[key],
|
|
699
|
+
obj2[key]
|
|
700
|
+
)) {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
|
|
547
707
|
// src/host.ts
|
|
548
708
|
var passAllGuests = () => true;
|
|
549
709
|
var _Host = class extends uixCore.Emitter {
|
|
550
710
|
constructor(config) {
|
|
551
711
|
super(config.hostName);
|
|
712
|
+
this.lastExtenstionList = {};
|
|
552
713
|
/**
|
|
553
714
|
* `true` if any extension in {@link Host.guests} has created a {@link
|
|
554
715
|
* @adobe/uix-guest#GuestServer}, but the Guest has not yet loaded.
|
|
@@ -609,6 +770,30 @@ var _Host = class extends uixCore.Emitter {
|
|
|
609
770
|
*/
|
|
610
771
|
async load(extensions, options) {
|
|
611
772
|
this.runtimeContainer = this.runtimeContainer || this.createRuntimeContainer(window);
|
|
773
|
+
const result = compareExtensions(this.lastExtenstionList, extensions);
|
|
774
|
+
this.lastExtenstionList = extensions;
|
|
775
|
+
const extensionsToAdd = Object.entries(result.added);
|
|
776
|
+
const extensionsToRemove = Object.entries(result.removed);
|
|
777
|
+
if (result.hasChanges && extensionsToAdd.length > 0) {
|
|
778
|
+
this.logger.log(
|
|
779
|
+
`Host ${this.hostName} loading extensions:`,
|
|
780
|
+
extensionsToAdd
|
|
781
|
+
);
|
|
782
|
+
await this.addLoadsNewGuests(result.added, options);
|
|
783
|
+
}
|
|
784
|
+
if (result.hasChanges && extensionsToRemove.length > 0) {
|
|
785
|
+
this.logger.log(
|
|
786
|
+
`Host ${this.hostName} removing extensions:`,
|
|
787
|
+
extensionsToRemove
|
|
788
|
+
);
|
|
789
|
+
extensionsToRemove.forEach(async ([id, ext]) => {
|
|
790
|
+
if (typeof ext === "object" && ext !== null && "url" in ext) {
|
|
791
|
+
await this.removeGuest(id, ext);
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
async addLoadsNewGuests(extensions, options) {
|
|
612
797
|
const failed = [];
|
|
613
798
|
const loaded = [];
|
|
614
799
|
this.loading = true;
|
|
@@ -621,6 +806,18 @@ var _Host = class extends uixCore.Emitter {
|
|
|
621
806
|
this.loading = false;
|
|
622
807
|
this.emit("loadallguests", { host: this, failed, loaded });
|
|
623
808
|
}
|
|
809
|
+
/**
|
|
810
|
+
* Unload and remove a specific extension by its ID.
|
|
811
|
+
*/
|
|
812
|
+
async removeGuest(id, extension) {
|
|
813
|
+
const guest = this.guests.get(id);
|
|
814
|
+
if (guest) {
|
|
815
|
+
this.emit("guestbeforeunload", { guest, host: this });
|
|
816
|
+
await guest.unload();
|
|
817
|
+
this.guests.delete(id);
|
|
818
|
+
this.emit("guestunload", { guest, host: this });
|
|
819
|
+
}
|
|
820
|
+
}
|
|
624
821
|
/**
|
|
625
822
|
* Unload all extensions and remove their frames/workers. Use this to unmount
|
|
626
823
|
* a UI or when switching to a different extensible UI.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/@adobe/exc-app/src/Global.ts","../../../node_modules/@adobe/exc-app/metrics/Events.ts","../../../node_modules/@adobe/exc-app/metrics/Level.ts","../../../node_modules/@adobe/exc-app/metrics.ts","../src/host.ts","../src/port.ts","../src/dom-utils/attribute-normalizers.ts","../src/dom-utils/iframe-normalizers.ts","../src/debug-host.ts","../src/metrics.ts","../src/extensions-provider/extension-registry.ts","../src/extensions-provider/composition.ts","../src/extensions-provider/mute.ts"],"names":["Events","Level","Emitter","log","event","host","metrics","MetricsApi","window"],"mappings":"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","sourcesContent":[null,null,null,null,"/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport type {\n Extension,\n GuestEmitter,\n NamedEvent,\n Emits,\n GuestApis,\n} from \"@adobe/uix-core\";\nimport type { CapabilitySpec } from \"./port.js\";\nimport { Emitter, quietConsole } from \"@adobe/uix-core\";\nimport { Port, PortOptions } from \"./port.js\";\nimport { debugHost } from \"./debug-host.js\";\nimport { addMetrics } from \"./metrics.js\";\n\n/**\n * Dictionary of {@link Port} objects by extension ID.\n * @public\n */\nexport type PortMap = Map<string, Port>;\n\n/** @public */\nexport type HostEvent<\n Type extends string = string,\n Detail = Record<string, unknown>\n> = NamedEvent<Type, Detail & Record<string, unknown> & { host: Host }>;\n/** @public */\ntype HostGuestEvent<Type extends string> = HostEvent<\n `guest${Type}`,\n { guest: Port }\n>;\n\n/**\n * All guests requested by host have been loaded and connected.\n * @public\n */\nexport type HostEventLoadAllGuests = HostEvent<\n \"loadallguests\",\n { failed: Port[]; loaded: Port[] }\n>;\n\n/**\n * Shared context has been set or updated; all guests receive this event too.\n * @public\n */\n\nexport type HostEventContextChange = HostEvent<\n \"contextchange\",\n { context: SharedContextValues }\n>;\n\n/**\n * An error has occurred during loading or unloading of guests.\n * @public\n */\nexport type HostEventError = HostEvent<\"error\", { error: Error }>;\n\n/** @public */\nexport type HostEvents =\n | HostGuestEvent<\"beforeload\">\n | HostGuestEvent<\"load\">\n | HostEvent<\"beforeunload\">\n | HostEvent<\"unload\">\n | HostEventLoadAllGuests\n | HostEventContextChange\n | HostEventError;\n\n/** @public */\nexport type InstalledExtensions = Record<\n Extension[\"id\"],\n Extension[\"url\"] | Extension\n>;\n/** @public */\nexport type ExtensionsProvider = () => Promise<InstalledExtensions>;\n\n/**\n * Values for shared context. Must be a plain object, serializable to JSON.\n * @public\n */\nexport type SharedContextValues = Record<string, unknown>;\n\n/** @public */\nexport interface HostConfig {\n /**\n * Human-readable \"slug\" name of the extensible area--often an entire app.\n * This string serves as a namespace for extension points within the area.\n */\n hostName: string;\n /**\n * A DOM element _outside_ of the React root. This is necessary to preserve\n * the lifetime of the iframes which are running extension objects; if they\n * live inside the React root, then React could unexpectedly re-render the\n * iframe tags themselves at any time, causing a reload of the frame.\n */\n runtimeContainer?: HTMLElement;\n /**\n * Copiously log lifecycle events.\n */\n debug?: boolean;\n /**\n * Default options to use for every guest Port.\n *\n * If `config.debug` is true, then the guest options will have `debug: true`\n * unless `debug: false` is explicitly passed in `guestOptions`.\n */\n guestOptions?: PortOptions;\n /**\n * A read-only dictionary of values that the host will supply to all the\n * guests.\n */\n sharedContext?: SharedContextValues;\n /**\n * Disables built-in metrics of UIX SDK\n */\n disableMetrics?: boolean;\n}\n\n/**\n * Callback to use to filter the list returned from {@link Host.(getLoadedGuests:2)}\n * @public\n */\ntype GuestFilter = (item: GuestEmitter) => boolean;\n\nconst passAllGuests = () => true;\n\n/**\n * Manager object for connecting to {@link @adobe/uix-guest#GuestServer |\n * GuestServers} and {@link @adobe/uix-guest#GuestUI | GuestUIs}, providing and\n * receiving their APIs, and providing them to the app for interacting with UI.\n *\n * @remarks\n * The Host object is the main connection manager for all UIX Guests.\n * Making an app extensible requires creating a Host object.\n *\n * The extensible app using the Hostis responsible for providing a list of\n * extension references to the Host object. Use {@link\n * createExtensionRegistryProvider} for that purpose. Once you have retrieved a\n * list of extensions available to the host app, pass it to {@link Host.load}.\n *\n * When a Host creates a Guest, it must create an `<iframe>` element to contain\n * the Guest's main {@link @adobe/uix-guest#GuestServer} runtime, which runs\n * invisibly in the background. To do this, the Host creates a hidden container\n * in the body of the document. It is a `<div>` element with the attribute\n * `data-uix-guest-container`. Loaded GuestServers will be injected into this\n * hidden element and removed as necessary. When {@link Host.unload} is called,\n * the Host removes the hidden container from the document after unloading.\n *\n * @public\n */\nexport class Host extends Emitter<HostEvents> {\n /**\n * {@inheritDoc HostEventLoadAllGuests}\n * @eventProperty\n */\n public loadallguests: HostEventLoadAllGuests;\n\n /**\n * One guest has loaded.\n * @eventProperty\n */\n public guestload: HostGuestEvent<\"load\">;\n\n /**\n * About to attempt to load and connect to a Guest.\n * @eventProperty\n */\n public guestbeforeload: HostGuestEvent<\"beforeload\">;\n\n /**\n * About to unload a guest and remove its {@link @adobe/uix-guest#GuestServer}\n * instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.\n * @eventProperty\n */\n public guestbeforeunload: HostGuestEvent<\"beforeunload\">;\n\n /**\n * Unloaded a guest and removed its {@link @adobe/uix-guest#GuestServer}\n * instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.\n * @eventProperty\n */\n public guestunload: HostGuestEvent<\"unload\">;\n\n /**\n * {@inheritDoc HostEventContextChange}\n * @eventProperty\n */\n public contextchange: HostEventContextChange;\n\n /**\n * {@inheritDoc HostEventError}\n * @eventProperty\n */\n public error: HostEventError;\n\n private static containerStyle = {\n position: \"fixed\",\n width: \"1px\",\n height: \"1px\",\n pointerEvents: \"none\",\n opacity: 0,\n top: 0,\n left: \"-1px\",\n };\n /**\n * Unique string identifying the Host object.\n */\n hostName: string;\n /**\n * `true` if any extension in {@link Host.guests} has created a {@link\n * @adobe/uix-guest#GuestServer}, but the Guest has not yet loaded.\n */\n loading = false;\n /**\n * A Map of of the loaded guests.\n */\n guests: PortMap = new Map();\n private cachedCapabilityLists: WeakMap<object, Port[]> = new WeakMap();\n private runtimeContainer: HTMLElement;\n private guestOptions: PortOptions;\n private logger: Console = quietConsole;\n private sharedContext: SharedContextValues;\n constructor(config: HostConfig) {\n super(config.hostName);\n const { guestOptions = {} } = config;\n this.guestOptions = {\n ...guestOptions,\n debug: guestOptions.debug === false ? false : !!config.debug,\n };\n this.hostName = config.hostName;\n this.sharedContext = config.sharedContext || {};\n this.runtimeContainer = config.runtimeContainer;\n if (config.debug) {\n this.logger = debugHost(this);\n }\n if (!config.disableMetrics) {\n addMetrics(this);\n }\n }\n /**\n * Return all loaded guests.\n */\n getLoadedGuests<T = unknown>(): Port<T>[];\n /**\n * Return loaded guests which satisfy the passed test function.\n */\n getLoadedGuests<T = unknown>(filter: GuestFilter): Port<T>[];\n /**\n * Return loaded guests which expose the provided {@link CapabilitySpec}.\n */\n getLoadedGuests<Apis extends GuestApis>(\n capabilities: CapabilitySpec<Apis>\n ): Port<GuestApis>[];\n getLoadedGuests<Apis extends GuestApis = never>(\n filterOrCapabilities?: CapabilitySpec<Apis> | GuestFilter\n ): Port<GuestApis>[] {\n if (typeof filterOrCapabilities === \"object\") {\n return this.getLoadedGuestsWith<Apis>(filterOrCapabilities);\n }\n const filter = filterOrCapabilities || passAllGuests;\n const result = [];\n for (const guest of this.guests.values()) {\n if (guest.isReady() && filter(guest)) {\n result.push(guest as Port<GuestApis>);\n }\n }\n return result;\n }\n /**\n * Set the object of shared values that all Guests can access via {@link @adobe/uix-guest#GuestServer.sharedContext}.\n * This overwrites any previous object.\n *\n * @example Exposes `authToken` to all Guests. Guests can call `this.sharedContext.get('authToken')` to retrieve this value.\n * ```javascript\n * host.shareContext({\n * authToken: '82ba19b'\n * });\n * ```\n *\n * @example Overwrites the previous sharedContext, deleting `authToken` and providing `secret` and `auth` instead.\n * ```javascript\n * host.shareContext({\n * secret: 'squirrel',\n * auth: false\n * });\n * ```\n */\n shareContext(context: SharedContextValues): void;\n /**\n * Update the object of shared values that all Guests can access via {@link\n * @adobe/uix-guest#GuestServer.sharedContext}. This method takes a callback\n * which receives the previous context and may return an entirely new context,\n * or new values merged with the old context.\n *\n * @remarks This callback pattern allows the shared context values to be\n * mutable while the internal context object references are immutable, which\n * is important for synchronizing. with guests.\n *\n * @example Overwrites a context object based on the previous one.\n * ```javascript\n * host.shareContext(oldContext => ({\n * counter: oldContext.counter + 1\n * }))\n * ```\n *\n * @example Updates a context while preserving other existing values.\n * ```javascript\n * host.shareContext(oldContext => ({\n * ...oldContext,\n * counter: oldContext.counter + 1\n * }))\n * ```\n */\n shareContext(\n setter: (context: SharedContextValues) => SharedContextValues\n ): void;\n shareContext(\n setter: (context: SharedContextValues) => SharedContextValues\n ): void;\n shareContext(\n setterOrContext:\n | ((context: SharedContextValues) => SharedContextValues)\n | SharedContextValues\n ) {\n if (typeof setterOrContext === \"function\") {\n this.sharedContext = setterOrContext(this.sharedContext);\n } else {\n this.sharedContext = setterOrContext;\n }\n this.emit(\"contextchange\", {\n host: this,\n context: this.sharedContext,\n });\n }\n /**\n * Load extension into host application from provided extension description.\n * Returned promise resolves when all extensions are loaded and registered.\n *\n * @param extensions - List of extension descriptors. Normally, the Host should receive this value from an {@link ExtensionsProvider}.\n * @param options - Custom options to be used as defaults for each {@link Port} object created for each guest.\n * @returns Promise which resolves when all guests have been loaded.\n */\n async load(\n extensions: InstalledExtensions,\n options?: PortOptions\n ): Promise<void> {\n this.runtimeContainer =\n this.runtimeContainer || this.createRuntimeContainer(window);\n const failed: Port[] = [];\n const loaded: Port[] = [];\n this.loading = true;\n await Promise.all(\n Object.entries(extensions).map(async ([id, extension]) => {\n const port = await this.loadOneGuest(id, extension, options);\n (port.error ? failed : loaded).push(port);\n })\n );\n this.loading = false;\n this.emit(\"loadallguests\", { host: this, failed, loaded });\n }\n /**\n * Unload all extensions and remove their frames/workers. Use this to unmount\n * a UI or when switching to a different extensible UI.\n */\n async unload(): Promise<void> {\n this.emit(\"beforeunload\", { host: this });\n await Promise.all([...this.guests.values()].map((guest) => guest.unload()));\n this.guests.clear();\n this.runtimeContainer.parentElement.removeChild(this.runtimeContainer);\n this.emit(\"unload\", { host: this });\n }\n private createRuntimeContainer(window: Window) {\n const { document } = window;\n const container = document.createElement(\"div\");\n container.setAttribute(\"data-uix-guest-container\", this.hostName);\n container.setAttribute(\"role\", \"presentation\");\n container.setAttribute(\"aria-hidden\", \"true\");\n Object.assign(container.style, Host.containerStyle);\n document.body.appendChild(container);\n return container;\n }\n private async loadOneGuest<T = unknown>(\n id: string,\n extension: string | Extension,\n options: PortOptions = {}\n ): Promise<Port<T>> {\n let guest = this.guests.get(id);\n if (!guest) {\n const isExtension = (item: any): item is Extension => {\n return typeof item === \"object\" && item !== null && \"url\" in item;\n };\n\n const isExtensionObject = isExtension(extension);\n const extensionUrl = isExtensionObject ? extension.url : extension;\n const extensionConfiguration = isExtensionObject\n ? extension.configuration\n : undefined;\n\n const extensionPoints = isExtensionObject\n ? extension.extensionPoints\n : [];\n\n const url = new URL(extensionUrl);\n guest = new Port({\n owner: this.hostName,\n id,\n url,\n runtimeContainer: this.runtimeContainer,\n options: {\n ...this.guestOptions,\n ...options,\n },\n logger: this.logger,\n sharedContext: this.sharedContext,\n configuration: extensionConfiguration,\n extensionPoints,\n events: this as Emits,\n });\n this.guests.set(id, guest);\n }\n this.emit(\"guestbeforeload\", { guest, host: this });\n try {\n await guest.load();\n } catch (e: unknown) {\n const error = new Error(\n `Guest ${guest.id} failed to load: at ${guest.url}: ${\n e instanceof Error ? e.stack : String(e)\n }`\n );\n this.emit(\"error\", { host: this, guest, error });\n return guest;\n }\n // this new guest might have new capabilities, so the identities of the\n // cached capability sets will need to change, to alert subscribers\n this.cachedCapabilityLists = new WeakMap();\n this.emit(\"guestload\", { guest, host: this });\n return guest;\n }\n private getLoadedGuestsWith<Apis extends GuestApis>(\n capabilities: CapabilitySpec<Apis>\n ) {\n if (this.cachedCapabilityLists.has(capabilities)) {\n return this.cachedCapabilityLists.get(capabilities);\n }\n const guestsWithCapabilities = this.getLoadedGuests((guest) =>\n guest.hasCapabilities(capabilities)\n );\n this.cachedCapabilityLists.set(capabilities, guestsWithCapabilities);\n return guestsWithCapabilities;\n }\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport type {\n Emits,\n GuestConnection,\n GuestConnectionEvents,\n HostMethodAddress,\n GuestApis,\n CrossRealmObject,\n Unsubscriber,\n VirtualApi,\n UIHostMethods,\n GuestMetadata,\n} from \"@adobe/uix-core\";\nimport { Emitter, connectIframe } from \"@adobe/uix-core\";\nimport { normalizeIframe } from \"./dom-utils\";\n\n/**\n * A specifier for methods to be expected on a remote interface.\n *\n * @remarks\n * A CapabilitySpec is a description of an interface, like a very simplified\n * type definition. It specifies an object structure and the paths in that\n * structure that must be functions. (It doesn't specify anything about the\n * signatures or return values of those functions.)\n *\n * Use CapabilitySpec objects as queries, or filters, to get a subset of\n * installed extensions which have registered methods which match the spec.\n *\n * @example\n * As an extensible app developer, you are making an extension point for spell\n * check. Your code expects extensions to register an API `spellCheck` with\n * methods called `spellCheck.correct(text)` and `spellCheck.suggest(text)`.\n *\n * ```javascript\n * async function correctText(text) {\n * const spellCheckers = host.getLoadedGuests({\n * spellCheck: [\n * 'correct',\n * 'suggest'\n * ]\n * });\n * let correcting = text;\n * for (const checker of spellCheckers) {\n * correcting = await checker.apis.spellCheck.correct(correcting);\n * }\n * return Promise.all(checkers.map(checker =>\n * checker.apis.spellCheck.suggest(correcting)\n * ));\n * }\n * ```\n *\n * @public\n */\nexport type CapabilitySpec<T extends GuestApis> = {\n [Name in keyof T]+?: (keyof T[Name])[];\n};\n\n/**\n * Interface for decoupling of guest Penpal object\n * @internal\n */\ninterface GuestProxyWrapper {\n // #region Properties (1)\n\n /**\n * Methods from guest\n */\n apis: VirtualApi;\n\n // #endregion Properties (1)\n\n // #region Public Methods (1)\n\n /**\n * Emit an event in the guest frame\n */\n emit(type: string, detail: unknown): Promise<void>;\n\n metadata: GuestMetadata;\n\n // #endregion Public Methods (1)\n}\n\n/** @public */\nexport type PortOptions = {\n /**\n * Time in milliseconds to wait for the guest to connect before throwing.\n */\n timeout?: number;\n /**\n * Set true to log copiously in the console.\n */\n debug?: boolean;\n};\n\nconst defaultOptions = {\n timeout: 20000,\n debug: false,\n};\n\nconst WRAPPER_MARKER = \"$_UISDK_FN_WRAPPER\";\n/**\n * Marker interface for detection of wrapped functions\n */\ntype WrappedFunction = {\n (...args: unknown[]): unknown;\n [WRAPPER_MARKER]: boolean;\n};\n\n/**\n * Function typeguard\n *\n * @param v\n * @returns boolean\n */\nconst isFunction = (v: unknown): v is CallableFunction => {\n return typeof v === \"function\";\n};\n\n/**\n * Typeguard for wrapped functions\n *\n * @param v\n * @returns\n */\nconst isWrapperFunction = (v: unknown): v is WrappedFunction => {\n return (\n typeof v === \"function\" && (v as WrappedFunction)[WRAPPER_MARKER] === true\n );\n};\n\n/**\n * A Port is the Host-maintained object representing an extension running as a\n * guest. It exposes methods registered by the Guest, and can provide Host\n * methods back to the guest.\n *\n * @remarks\n * When the Host object loads extensions via {@link Host.load}, it creates a\n * Port object for each extension. When retrieving and filtering extensions\n * via {@link Host.(getLoadedGuests:2)}, a list of Port objects is returned. From\n * the point of view of the extensible app using the Host object, extensions\n * are always Port objects, which expose the methods registered by the\n * extension at the {@link Port.apis} property.\n *\n * @privateRemarks\n * We've gone through several possible names for this object. GuestProxy,\n * GuestInterface, GuestConnection, etc. \"Port\" is not ideal, but it conflicted\n * the least with other types we defined in early drafts. It's definitely\n * something we should review.\n * @public\n */\nexport class Port<GuestApi = unknown>\n extends Emitter<GuestConnectionEvents>\n implements GuestConnection\n{\n public get apis() {\n if (this.isReady() && this.guestServer) {\n const server = this.guestServer.getRemoteApi();\n return server && this.addApiMiddleware(server.apis);\n }\n }\n\n public get metadata(): GuestMetadata {\n if (this.isReady() && this.guestServer) {\n const server = this.guestServer.getRemoteApi();\n return server && server.metadata;\n }\n }\n\n // #region Properties (13)\n\n private debug: boolean;\n private logger?: Console;\n private guestServerFrame: HTMLIFrameElement;\n private hostApis: VirtualApi = {};\n private isLoaded = false;\n private runtimeContainer: HTMLElement;\n private sharedContext: Record<string, unknown>;\n private configuration?: Record<string, unknown>;\n private subscriptions: Unsubscriber[] = [];\n private timeout: number;\n\n /**\n * If any errors occurred during the loading of guests, this property will\n * contain the error that was raised.\n * @public\n */\n error?: Error;\n /**\n * The URL of the guest provided by the extension registry. The Host will\n * load this URL in the background, in the invisible the bootstrap frame, so\n * this URL must point to a page that calls {@link @adobe/uix-guest#register}\n * when it loads.\n */\n public url: URL;\n public extensionPoints: string[];\n private guestServer: CrossRealmObject<GuestProxyWrapper>;\n\n // #endregion Properties (13)\n\n // #region Constructors (1)\n\n constructor(config: {\n owner: string;\n id: string;\n url: URL;\n /**\n * An alternate DOM element to use for invisible iframes. Will create its\n * own if this option is not populated with a DOM element.\n */\n runtimeContainer: HTMLElement;\n options: PortOptions;\n logger?: Console;\n /**\n * Initial object to populate the shared context with. Once the guest\n * connects, it will be able to access these properties.\n */\n sharedContext: Record<string, unknown>;\n /**\n * A guest (extension) configuration\n */\n configuration?: Record<string, unknown>;\n /**\n * Guest (extension) extension points\n */\n extensionPoints?: string[];\n events: Emits;\n }) {\n super(config.id);\n const { timeout, debug } = { ...defaultOptions, ...(config.options || {}) };\n this.timeout = timeout;\n this.debug = debug;\n this.logger = config.logger;\n this.id = config.id;\n this.url = config.url;\n this.runtimeContainer = config.runtimeContainer;\n this.sharedContext = config.sharedContext;\n this.configuration = config.configuration;\n this.extensionPoints = config.extensionPoints;\n this.subscriptions.push(\n config.events.addEventListener(\"contextchange\", async (event) => {\n this.sharedContext = (\n (event as CustomEvent).detail as unknown as Record<string, unknown>\n ).context as Record<string, unknown>;\n await this.load();\n await this.guestServer\n .getRemoteApi()\n .emit(\"contextchange\", { context: this.sharedContext });\n })\n );\n }\n\n // #endregion Constructors (1)\n\n // #region Public Methods (6)\n\n /**\n * Connect an iframe element which is displaying another page in the extension\n * with the extension's bootstrap frame, so they can share context and events.\n */\n public attachUI<T = unknown>(\n iframe: HTMLIFrameElement,\n privateMethods: VirtualApi\n ): Promise<CrossRealmObject<T>> {\n return this.attachFrame(iframe, {\n onIframeResize: (dimensions: { height: number; width: number }) => {\n this.emit(\"guestresize\", {\n dimensions,\n guestPort: this,\n iframe: iframe,\n });\n },\n ...privateMethods,\n } as UIHostMethods);\n }\n\n /**\n * Returns true if the guest has registered methods matching the provided\n * capability spec. A capability spec is simply an object whose properties are\n * declared in an array of keys, description the names of the functions and\n * methods that the Port will expose.\n */\n public hasCapabilities(requiredCapabilities: CapabilitySpec<GuestApis>) {\n this.assertReady();\n return (\n this.apis &&\n Object.entries(requiredCapabilities).every(([apiName, methodNames]) =>\n this.hasCapability(apiName, methodNames as string[])\n )\n );\n }\n\n /**\n * True when al extensions have loaded.\n */\n public isReady(): boolean {\n return this.isLoaded && !this.error;\n }\n\n /**\n * Loads the extension. Returns a promise which resolves when the extension\n * has loaded. The Host calls this method after retrieving extensions.\n */\n public async load() {\n try {\n if (!this.isLoaded) {\n await this.connect();\n }\n } catch (e) {\n this.guestServer = null;\n this.error = e instanceof Error ? e : new Error(String(e));\n throw e;\n }\n }\n\n /**\n * The host-side equivalent of {@link @adobe/uix-guest#register}. Pass a set\n * of methods down to the guest as proxies.\n * Merges at the first level, the API level. Overwrites a deeper levels.\n */\n public provide(apis: VirtualApi) {\n for (const [apiNamespace, methods] of Object.entries(apis)) {\n this.hostApis[apiNamespace] = this.hostApis[apiNamespace] || {};\n Object.assign(this.hostApis[apiNamespace], methods);\n }\n this.emit(\"hostprovide\", { guestPort: this, apis });\n }\n\n /**\n * Disconnect from the extension.\n */\n public async unload(): Promise<void> {\n if (this.guestServerFrame && this.guestServerFrame.parentElement) {\n this.guestServerFrame.parentElement.removeChild(this.guestServerFrame);\n this.guestServerFrame = undefined;\n }\n this.emit(\"unload\", { guestPort: this });\n }\n\n // #endregion Public Methods (6)\n\n // #region Private Methods (6)\n\n /**\n * Recursive method that wraps every function in apis object and adds\n * an event\n */\n private addApiMiddleware(subject: any, path: string[] = []): VirtualApi {\n if (typeof subject === \"object\") {\n for (const [key, value] of Object.entries(subject)) {\n if (typeof value === \"object\") {\n subject[key] = this.addApiMiddleware(value, [...path, key]);\n } else if (isWrapperFunction(value)) {\n // Remote function is already wrapped. Nothing to do...\n continue;\n } else if (isFunction(value)) {\n const wrapper = async (...args: any) => {\n this.emit(\"beforecallguestmethod\", {\n guestPort: this,\n path: [...path, key],\n args,\n });\n const res = await (value as CallableFunction)(...args);\n /*\n * Wraps response in middleware so consequent calls could be intercepted\n * E.g. headerMenu.getButtons().onClick()\n */\n return this.addApiMiddleware(res, [...path, key]);\n };\n (wrapper as WrappedFunction)[WRAPPER_MARKER] = true;\n subject[key] = wrapper;\n }\n }\n }\n\n return subject;\n }\n\n private hasCapability(apiName: string, methodNames: string[]) {\n const api = this.apis[apiName];\n return (\n api &&\n methodNames.every(\n (methodName: keyof typeof api) =>\n Reflect.has(api, methodName) && typeof api[methodName] === \"function\"\n )\n );\n }\n\n private assert(\n condition: boolean,\n errorMessage: () => string\n ): asserts condition {\n if (!condition) {\n throw new Error(\n `Error in guest extension \"${this.id}\": ${errorMessage()}`\n );\n }\n }\n\n private assertReady() {\n this.assert(this.isReady(), () => \"Attempted to interact before loaded\");\n }\n\n private attachFrame<T = unknown>(\n iframe: HTMLIFrameElement,\n addedMethods: object = {}\n ) {\n // at least this is necessary\n normalizeIframe(iframe);\n this.logger.log(\"attachFrame\", iframe);\n return connectIframe<T>(\n iframe,\n {\n logger: this.logger,\n targetOrigin: this.url.origin,\n timeout: this.timeout,\n },\n {\n getSharedContext: () => this.sharedContext,\n getConfiguration: () => this.configuration,\n invokeHostMethod: (address: HostMethodAddress) =>\n this.invokeHostMethod(address, addedMethods as VirtualApi),\n ...addedMethods,\n }\n );\n }\n\n private async connect() {\n const serverFrame =\n this.runtimeContainer.ownerDocument.createElement(\"iframe\");\n normalizeIframe(serverFrame);\n serverFrame.setAttribute(\"aria-hidden\", \"true\");\n serverFrame.setAttribute(\"src\", this.url.href);\n this.guestServerFrame = serverFrame;\n this.runtimeContainer.appendChild(serverFrame);\n if (this.logger) {\n this.logger.info(\n `Guest ${this.id} attached iframe of ${this.url.href}`,\n this\n );\n }\n this.guestServer = await this.attachFrame<GuestProxyWrapper>(serverFrame);\n this.isLoaded = true;\n if (this.logger) {\n this.logger.info(\n `Guest ${this.id} established connection, received methods`,\n this.apis,\n this\n );\n }\n }\n\n private getHostMethodCallee<T = unknown>(\n { name, path }: HostMethodAddress,\n methodSource: VirtualApi\n ): VirtualApi {\n const dots = (level: number) => `host.${path.slice(0, level).join(\".\")}`;\n const methodCallee = path.reduce((current, prop, level) => {\n this.assert(\n Reflect.has(current, prop),\n () => `${dots(level)} has no property \"${prop}\"`\n );\n const next = current[prop];\n this.assert(\n typeof next === \"object\",\n () =>\n `${dots(\n level\n )}.${prop} is not an object; namespaces must be objects with methods`\n );\n return next as VirtualApi;\n }, methodSource);\n this.assert(\n typeof methodCallee[name] === \"function\" &&\n Reflect.has(methodCallee, name),\n () => `\"${dots(path.length - 1)}.${name}\" is not a function`\n );\n return methodCallee;\n }\n\n private invokeHostMethod<T = unknown>(\n address: HostMethodAddress,\n privateMethods?: VirtualApi\n ): T {\n const { name, path, args = [] } = address;\n this.assert(name && typeof name === \"string\", () => \"Method name required\");\n this.assert(\n path.length > 0,\n () =>\n `Cannot call a method directly on the host; \".${name}()\" must be in a namespace.`\n );\n let methodCallee;\n if (privateMethods) {\n try {\n methodCallee = this.getHostMethodCallee(address, privateMethods);\n } catch (e) {\n // private method not found, continue and try other way of accessing it\n }\n }\n if (!methodCallee) {\n methodCallee = this.getHostMethodCallee(address, this.hostApis);\n }\n const method = methodCallee[name] as (...args: unknown[]) => T;\n this.emit(\"beforecallhostmethod\", { guestPort: this, name, path, args });\n return method.apply(methodCallee, [\n { id: this.id, url: this.url },\n ...args,\n ]) as T;\n }\n\n // #endregion Private Methods (6)\n}\n","/**\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/**\n * Strings to be used as values in a space-separated HTML attribute.\n * @internal\n */\nexport type AttrTokens<T> = string | T[];\n\n/**\n * Normalize an argument that may be either a space-separated HTML attribute\n * value or an array of those attribute values into an array of those values.\n * @internal\n */\nexport const tokenizeAttrValues = <T>(tokens: AttrTokens<T>) =>\n (typeof tokens === \"string\" ? tokens.split(\" \") : tokens) as T[];\n\n/**\n * Merge, deduplicate and typecheck a set of strings for an HTML attribute that\n * requires those values to be space-separated tokens.\n * @internal\n *\n * @remarks\n * Useful as a typed interface for any DOM property that is a DOMTokenList.\n * While the DOMTokenList does its own deduplication, it's slightly slower,\n * and while it may do validation of legal tokens, it only does so at runtime.\n * Using {@link AttrTokens} and this function adds typing and autocomplete.\n *\n *\n * @example\n * ```typescript\n * type AllowedClasses =\n * | \"primary\"\n * | \"light\"\n * | \"large\"\n * | \"quiet\";\n *\n * // combine with existing classes and set attribute directly\n * function setStyles(elm: HTMLElement, styles: AttrTokens<AllowedClasses>) {\n * const classNames = mergeAttrValues(\n * elm.className as AttrTokens<AllowedClasses>,\n * styles\n * );\n * elm.className = classNames.join(' ');\n * }\n *\n * // use DOM property directly, but now it's typed!\n * function setSandbox(\n * iframe: HTMLIframeElement,\n * allowedSandboxes: AttrTokens<\"allow-scripts\" | \"allow-popups\">\n * ) {\n * mergeAttrValues(allowedSandboxes).forEach(val => iframe.sandbox.add(val));\n * }\n * ```\n */\nexport const mergeAttrValues = <T>(...tokenLists: AttrTokens<T>[]) => {\n const allMerged = new Set<T>();\n for (const tokenList of tokenLists) {\n for (const token of tokenizeAttrValues(tokenList)) {\n allMerged.add(token);\n }\n }\n return [...allMerged];\n};\n","/**\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { HTMLAttributeReferrerPolicy } from \"react\";\nimport { AttrTokens, mergeAttrValues } from \"./attribute-normalizers\";\n\n/**\n * Sandbox permissions that guest iframes are allowed to have.\n * @internal\n */\ntype SandboxPermission =\n | \"downloads\"\n | \"orientation-lock\"\n | \"pointer-lock\"\n | \"popups\"\n | \"presentation\"\n | \"same-origin\"\n | \"scripts\"\n | \"storage-access-by-user-activation\"\n | \"top-navigation-by-user-activation\";\n\n/**\n * Character strings allowed in \"sandbox=\" attribute.\n * @internal\n */\nexport type SandboxToken = `allow-${SandboxPermission}`;\n\n/**\n * Merge lists of attrs together\n * @internal\n */\nexport const makeSandboxAttrs = (...sandboxes: AttrTokens<SandboxToken>[]) =>\n mergeAttrValues<SandboxToken>(...sandboxes);\n\n/**\n * Limit provided set of \"sandbox\" attributes to a list of legal ones.\n * @internal\n */\nexport const requiredIframeProps = {\n // must not require this until app builder supports CSP\n // csp: \"frame-ancestors 'self'\",\n \"data-uix-guest\": \"true\",\n role: \"presentation\",\n referrerPolicy: \"strict-origin\" as HTMLAttributeReferrerPolicy,\n};\n\nconst requiredIframeAttrEntries = Object.entries(requiredIframeProps);\n\n/**\n * Set and/or verify the required properties for use with uix-sdk on an iframe.\n * @internal\n */\nexport const normalizeIframe = (iframe: HTMLIFrameElement) => {\n for (const [attr, value] of requiredIframeAttrEntries) {\n iframe.setAttribute(attr, value);\n }\n};\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/**\n * Adapter to attach console logging listeners to a Host running in an app\n * @hidden\n */\nimport {\n debugEmitter,\n EmitterDebugLogger,\n Emits,\n GuestEmitter,\n} from \"@adobe/uix-core\";\nimport type { HostEventLoadAllGuests, HostEvents } from \"./host.js\";\n\nexport function debugHost(host: Emits<HostEvents>): EmitterDebugLogger {\n const hostLogger = debugEmitter(host, {\n theme: \"blue medium\",\n type: \"Host\",\n });\n hostLogger\n .listen(\"guestbeforeload\", (log, event) => {\n const { detail } = event;\n const guest = detail.guest as GuestEmitter;\n log.info(event, `Guest ID ${guest.id}`);\n const portLogger = debugEmitter(guest, {\n theme: \"green medium\",\n type: \"Port\",\n id: `${host.id} ➔ ${guest.id}`,\n });\n portLogger\n .listen(\"hostprovide\", (log, event) => {\n log.info(\"received APIs\", event.detail.apis);\n })\n .listen(\"beforecallhostmethod\", (log, event) => {\n log.info(event.detail);\n })\n .listen(\"guestresize\", (log, event) => {\n log.info(event.detail);\n })\n .listen(\"unload\", (log, event) => {\n log.info(event.detail);\n log.detach();\n })\n .listen(\"beforecallguestmethod\", (log, event) => {\n log.info(event.detail);\n });\n })\n .listen(\"guestload\", (log, e) => {\n log.info(e.detail.guest.id, e.detail.guest);\n })\n .listen(\"error\", (log, e) => {\n log.error(`Error: ${e.detail.error.message}`, e);\n })\n .listen(\n \"loadallguests\",\n (log, { detail: { failed, loaded, host } }: HostEventLoadAllGuests) => {\n if (failed.length > 0) {\n log.error(\"%d guests failed to load!\", failed.length);\n }\n log.info(\"%d guests loaded\", loaded.length, host);\n }\n )\n .listen(\"unload\", (log) => {\n log.info(\"Unloaded guest and container.\");\n log.detach();\n });\n return hostLogger;\n}\n","/*\nCopyright 2024 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/**\n * Adapter to attach console logging listeners to a Host running in an app\n * @hidden\n */\nimport { Emitter } from \"@adobe/uix-core\";\nimport type { HostEvents } from \"./host.js\";\nimport type { Metrics } from \"@adobe/exc-app/metrics\";\nimport MetricsApi from \"@adobe/exc-app/metrics\";\n\ntype EventPayload = {\n event: string;\n args: any;\n};\n\n/**\n * Wrapper class for handling metrics and event tracking.\n */\nclass MetricsWrapper {\n private eventPool: EventPayload[] = [];\n private metricsInstance?: Readonly<Metrics> | undefined = undefined;\n\n /**\n * Sends collected events to the metrics instance.\n */\n private flush(): void {\n if (!this.metricsInstance) {\n return;\n }\n\n this.eventPool.forEach((eventPayload) => {\n this.metricsInstance.event(eventPayload.event, eventPayload.args);\n });\n this.eventPool = [];\n }\n\n /**\n * Gets the current metrics instance.\n */\n public get mertricsInstance(): Readonly<Metrics> | undefined {\n return this.metricsInstance;\n }\n\n /**\n * Sets the metrics instance and flushes any pending events.\n */\n public set mertricsInstance(metrics: Readonly<Metrics>) {\n this.metricsInstance = metrics;\n this.metricsInstance && this.flush();\n }\n\n /**\n * Tracks an event using the metrics instance, or adds it to the event pool if no instance is set.\n */\n public event(event: string, args: any): void {\n if (this.metricsInstance) {\n this.metricsInstance.event(event, args);\n } else {\n this.eventPool.push({ event, args });\n }\n }\n}\nconst metrics = new MetricsWrapper();\n\nconst seenGuests = new Set();\nconst runtimeWaitTimeout = 10000;\nconst createMetricsInstance = () => MetricsApi.create(\"exc.uix.core\");\n\nconst startTime = Date.now();\n/**\n * Monitors the availability of the runtime module and creates a metrics instance when it becomes available.\n * If the runtime module is not found within the specified timeout, it exits and no events will be sent.\n * @returns {void}\n */\nconst runtimeSpy = () => {\n if (startTime + runtimeWaitTimeout < Date.now()) {\n // Timeout, time to hang up\n return;\n }\n if (\"exc-module-runtime\" in window) {\n metrics.mertricsInstance = createMetricsInstance();\n return;\n }\n setTimeout(runtimeSpy, 1000);\n};\nruntimeSpy();\n\n/**\n * Adds metrics tracking to the host.\n *\n * @param host - The host emitter to attach the metrics to.\n */\nexport function addMetrics(host: Emitter<HostEvents>): void {\n host.addEventListener(\"guestload\", (evt) => {\n const guest = evt.detail.guest;\n if (seenGuests.has(guest)) {\n return;\n }\n seenGuests.add(guest);\n const addGuestId = (payload: any): any => {\n payload[\"guestId\"] = guest.id;\n return payload;\n };\n\n metrics.event(\"load\", addGuestId({}));\n\n guest.addEventListener(\"beforecallguestmethod\", (callDetails) => {\n const { path } = callDetails.detail;\n metrics.event(\n \"callguestmethod\",\n addGuestId({\n path: (path as string[]).join(\".\"),\n })\n );\n });\n guest.addEventListener(\"beforecallhostmethod\", (callDetails) => {\n const { path, name } = callDetails.detail;\n path.push(name);\n metrics.event(\n \"callhostmethod\",\n addGuestId({\n path: (path as string[]).join(\".\"),\n })\n );\n });\n });\n\n host.addEventListener(\"error\", () => {\n metrics.event(\"error\", {});\n });\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { InstalledExtensions, ExtensionsProvider } from \"../host.js\";\n\ninterface ExtensionDefinition {\n name: string;\n title: string;\n description: string;\n icon: string;\n publisher: string;\n endpoints: Record<string, EndpointDefinition>;\n xrInfo: ExtensionInfo;\n status: string;\n}\n\ntype EndpointDefinition = Record<string, Array<OperationDefinition>>;\n\ninterface ExtensionInfo {\n supportEmail: string;\n appId: string;\n}\n\ninterface OperationDefinition {\n href: string;\n metadata: OperationMetadata;\n}\n\ninterface OperationMetadata {\n services: Array<object>;\n profile: OperationProfile;\n}\n\ninterface OperationProfile {\n client_id: string;\n scope: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryEndpointRegistration {\n service: string;\n extensionPoint: string;\n version: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryExtensionRegistration\n extends ExtensionRegistryEndpointRegistration {\n imsOrg: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryConnection {\n baseUrl?: string;\n apiKey: string;\n workspace?: string;\n filter?: (extension: ExtensionDefinition) => boolean;\n auth: {\n schema: \"Basic\" | \"Bearer\";\n imsToken: string;\n };\n}\n\n/** @public */\nexport interface ExtensionRegistryConfig\n extends ExtensionRegistryExtensionRegistration,\n ExtensionRegistryConnection {}\n\nfunction buildEndpointPath(\n config: ExtensionRegistryEndpointRegistration\n): string {\n return `${config.service}/${config.extensionPoint}/${config.version}`;\n}\n\nfunction ensureProtocolSpecified(url: string) {\n if (url.startsWith(\"https://\")) {\n return url;\n }\n if (url.startsWith(\"http://\")) {\n return url;\n }\n return `https://${url}`;\n}\n\nexport async function fetchExtensionsFromRegistry(\n config: ExtensionRegistryConfig\n): Promise<Array<ExtensionDefinition>> {\n const workspaceParam = config.workspace\n ? `&workspace=${config.workspace}`\n : \"\";\n const resp = await fetch(\n `${ensureProtocolSpecified(\n config.baseUrl || \"appregistry.adobe.io\"\n )}/myxchng/v1/org/${encodeURIComponent(\n config.imsOrg\n )}/xtn/${buildEndpointPath(config)}?auth=true${workspaceParam}`,\n {\n headers: {\n Accept: \"application/json\",\n Authorization: `${config.auth.schema} ${config.auth.imsToken}`, // todo: check if auth schema needed (initial implementation was without it)\n \"X-Api-Key\": config.apiKey,\n },\n }\n );\n\n if (resp.status != 200) {\n throw new Error(\n `extension registry returned non-200 response (${\n resp.status\n }): ${await resp.text()}`\n );\n }\n\n return await resp.json();\n}\n\n/**\n * @deprecated\n */\nfunction extensionRegistryExtensionsProvider(\n config: ExtensionRegistryConfig\n): Promise<InstalledExtensions> {\n const erEndpoint = buildEndpointPath(config);\n return fetchExtensionsFromRegistry(config).then((out) =>\n out.reduce((a, e: ExtensionDefinition) => {\n if (e.status !== \"PUBLISHED\") {\n return a;\n }\n\n return {\n ...a,\n // todo: make safer way to extract href\n [e.name]: e.endpoints[erEndpoint].view[0].href,\n };\n }, {})\n );\n\n return Promise.resolve({});\n}\n\n/**\n * Fetch & return published extension objects from registry\n */\nfunction extensionRegistryExtensionsAsObjectsProvider(\n config: ExtensionRegistryConfig\n): Promise<InstalledExtensions> {\n const erEndpoint = buildEndpointPath(config);\n return fetchExtensionsFromRegistry(config).then((out) =>\n out.reduce((a, e: ExtensionDefinition) => {\n if (config.filter && typeof config.filter === \"function\") {\n if (!config.filter(e)) {\n return a;\n }\n } else if (e.status !== \"PUBLISHED\") {\n return a;\n }\n\n return {\n ...a,\n [e.name]: {\n id: e.name,\n url: e.endpoints[erEndpoint].view[0].href,\n extensionPoints: [erEndpoint],\n },\n };\n }, {})\n );\n}\n\n/**\n * Create a callback that fetches extensions from the registry.\n * @public\n * @deprecated use `createExtensionRegistryAsObjectsProvider()`\n */\nexport function createExtensionRegistryProvider(\n config: ExtensionRegistryConfig\n): ExtensionsProvider {\n return function () {\n return extensionRegistryExtensionsProvider(config);\n };\n}\n\n/**\n * Create a callback that fetches extensions as objects from the registry.\n * @public\n */\nexport function createExtensionRegistryAsObjectsProvider(\n config: ExtensionRegistryConfig\n): ExtensionsProvider {\n return function () {\n return extensionRegistryExtensionsAsObjectsProvider(config);\n };\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { InstalledExtensions, ExtensionsProvider } from \"../host.js\";\n\n/**\n * Combine multiple {@link @adobe/uix-host#ExtensionsProvider} callbacks into a\n * single callback, which aggregates and dedupes all extensions from all\n * providers into one namespaced object.\n * @public\n */\nexport function combineExtensionsFromProviders(\n ...providers: Array<ExtensionsProvider>\n): ExtensionsProvider {\n return () =>\n Promise.all(providers.map((ep: ExtensionsProvider) => ep())).then(\n (extensionsBatches: Array<InstalledExtensions>) => {\n return Object.assign({}, ...extensionsBatches);\n }\n );\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { ExtensionsProvider } from \"../host.js\";\n\n/**\n * Mute any errors produced by provider.\n * This function would execute given provider and return its results as is, if any error occurs this provider will log it\n * any return an empty array of extensions.\n * @public\n */\nexport function mutedProvider(\n provider: ExtensionsProvider\n): ExtensionsProvider {\n return async () => {\n try {\n return await provider();\n } catch (error) {\n console.error(`Extension provider has failed: ${error.message}`, {\n error,\n });\n return {};\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/@adobe/exc-app/src/Global.ts","../../../node_modules/@adobe/exc-app/metrics/Events.ts","../../../node_modules/@adobe/exc-app/metrics/Level.ts","../../../node_modules/@adobe/exc-app/metrics.ts","../src/host.ts","../src/port.ts","../src/dom-utils/attribute-normalizers.ts","../src/dom-utils/iframe-normalizers.ts","../src/utils/comparePackagesVersions.ts","../src/debug-host.ts","../src/metrics.ts","../src/utils/compareExtensions.ts","../src/extensions-provider/extension-registry.ts","../src/extensions-provider/composition.ts","../src/extensions-provider/mute.ts"],"names":["Events","Level","Emitter","_a","log","event","host","metrics","MetricsApi","window"],"mappings":"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","sourcesContent":[null,null,null,null,"/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport type {\n Extension,\n GuestEmitter,\n NamedEvent,\n Emits,\n GuestApis,\n} from \"@adobe/uix-core\";\nimport type { CapabilitySpec } from \"./port.js\";\nimport { Emitter, quietConsole } from \"@adobe/uix-core\";\nimport { Port, PortOptions } from \"./port.js\";\nimport { debugHost } from \"./debug-host.js\";\nimport { addMetrics } from \"./metrics.js\";\nimport { compareExtensions } from \"./utils/compareExtensions.js\";\n\n/**\n * Dictionary of {@link Port} objects by extension ID.\n * @public\n */\nexport type PortMap = Map<string, Port>;\n\n/** @public */\nexport type HostEvent<\n Type extends string = string,\n Detail = Record<string, unknown>\n> = NamedEvent<Type, Detail & Record<string, unknown> & { host: Host }>;\n/** @public */\ntype HostGuestEvent<Type extends string> = HostEvent<\n `guest${Type}`,\n { guest: Port }\n>;\n\n/**\n * All guests requested by host have been loaded and connected.\n * @public\n */\nexport type HostEventLoadAllGuests = HostEvent<\n \"loadallguests\",\n { failed: Port[]; loaded: Port[] }\n>;\n\n/**\n * Shared context has been set or updated; all guests receive this event too.\n * @public\n */\n\nexport type HostEventContextChange = HostEvent<\n \"contextchange\",\n { context: SharedContextValues }\n>;\n\n/**\n * An error has occurred during loading or unloading of guests.\n * @public\n */\nexport type HostEventError = HostEvent<\"error\", { error: Error }>;\n\n/** @public */\nexport type HostEvents =\n | HostGuestEvent<\"beforeload\">\n | HostGuestEvent<\"load\">\n | HostGuestEvent<\"beforeunload\">\n | HostGuestEvent<\"unload\">\n | HostEvent<\"beforeunload\">\n | HostEvent<\"unload\">\n | HostEventLoadAllGuests\n | HostEventContextChange\n | HostEventError;\n\n/** @public */\nexport type InstalledExtensions = Record<\n Extension[\"id\"],\n Extension[\"url\"] | Extension\n>;\n\n/** @public */\nexport type ExtensionsArray = Array<[string, Extension | string]>;\n\n/** @public */\nexport type ExtensionsProvider = () => Promise<InstalledExtensions>;\n\n/**\n * Values for shared context. Must be a plain object, serializable to JSON.\n * @public\n */\nexport type SharedContextValues = Record<string, unknown>;\n\n/** @public */\nexport interface HostConfig {\n /**\n * Human-readable \"slug\" name of the extensible area--often an entire app.\n * This string serves as a namespace for extension points within the area.\n */\n hostName: string;\n /**\n * A DOM element _outside_ of the React root. This is necessary to preserve\n * the lifetime of the iframes which are running extension objects; if they\n * live inside the React root, then React could unexpectedly re-render the\n * iframe tags themselves at any time, causing a reload of the frame.\n */\n runtimeContainer?: HTMLElement;\n /**\n * Copiously log lifecycle events.\n */\n debug?: boolean;\n /**\n * Default options to use for every guest Port.\n *\n * If `config.debug` is true, then the guest options will have `debug: true`\n * unless `debug: false` is explicitly passed in `guestOptions`.\n */\n guestOptions?: PortOptions;\n /**\n * A read-only dictionary of values that the host will supply to all the\n * guests.\n */\n sharedContext?: SharedContextValues;\n /**\n * Disables built-in metrics of UIX SDK\n */\n disableMetrics?: boolean;\n}\n\n/**\n * Callback to use to filter the list returned from {@link Host.(getLoadedGuests:2)}\n * @public\n */\ntype GuestFilter = (item: GuestEmitter) => boolean;\n\nconst passAllGuests = () => true;\n\n/**\n * Manager object for connecting to {@link @adobe/uix-guest#GuestServer |\n * GuestServers} and {@link @adobe/uix-guest#GuestUI | GuestUIs}, providing and\n * receiving their APIs, and providing them to the app for interacting with UI.\n *\n * @remarks\n * The Host object is the main connection manager for all UIX Guests.\n * Making an app extensible requires creating a Host object.\n *\n * The extensible app using the Hostis responsible for providing a list of\n * extension references to the Host object. Use {@link\n * createExtensionRegistryProvider} for that purpose. Once you have retrieved a\n * list of extensions available to the host app, pass it to {@link Host.load}.\n *\n * When a Host creates a Guest, it must create an `<iframe>` element to contain\n * the Guest's main {@link @adobe/uix-guest#GuestServer} runtime, which runs\n * invisibly in the background. To do this, the Host creates a hidden container\n * in the body of the document. It is a `<div>` element with the attribute\n * `data-uix-guest-container`. Loaded GuestServers will be injected into this\n * hidden element and removed as necessary. When {@link Host.unload} is called,\n * the Host removes the hidden container from the document after unloading.\n *\n * @public\n */\nexport class Host extends Emitter<HostEvents> {\n /**\n * {@inheritDoc HostEventLoadAllGuests}\n * @eventProperty\n */\n public loadallguests: HostEventLoadAllGuests;\n\n /**\n * One guest has loaded.\n * @eventProperty\n */\n public guestload: HostGuestEvent<\"load\">;\n\n /**\n * About to attempt to load and connect to a Guest.\n * @eventProperty\n */\n public guestbeforeload: HostGuestEvent<\"beforeload\">;\n\n /**\n * About to unload a guest and remove its {@link @adobe/uix-guest#GuestServer}\n * instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.\n * @eventProperty\n */\n public guestbeforeunload: HostGuestEvent<\"beforeunload\">;\n\n /**\n * Unloaded a guest and removed its {@link @adobe/uix-guest#GuestServer}\n * instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.\n * @eventProperty\n */\n public guestunload: HostGuestEvent<\"unload\">;\n\n /**\n * {@inheritDoc HostEventContextChange}\n * @eventProperty\n */\n public contextchange: HostEventContextChange;\n\n /**\n * {@inheritDoc HostEventError}\n * @eventProperty\n */\n public error: HostEventError;\n\n private static containerStyle = {\n position: \"fixed\",\n width: \"1px\",\n height: \"1px\",\n pointerEvents: \"none\",\n opacity: 0,\n top: 0,\n left: \"-1px\",\n };\n\n private lastExtenstionList: InstalledExtensions = {};\n /**\n * Unique string identifying the Host object.\n */\n hostName: string;\n /**\n * `true` if any extension in {@link Host.guests} has created a {@link\n * @adobe/uix-guest#GuestServer}, but the Guest has not yet loaded.\n */\n loading = false;\n /**\n * A Map of of the loaded guests.\n */\n guests: PortMap = new Map();\n private cachedCapabilityLists: WeakMap<object, Port[]> = new WeakMap();\n private runtimeContainer: HTMLElement;\n private guestOptions: PortOptions;\n private logger: Console = quietConsole;\n private sharedContext: SharedContextValues;\n constructor(config: HostConfig) {\n super(config.hostName);\n const { guestOptions = {} } = config;\n this.guestOptions = {\n ...guestOptions,\n debug: guestOptions.debug === false ? false : !!config.debug,\n };\n this.hostName = config.hostName;\n this.sharedContext = config.sharedContext || {};\n this.runtimeContainer = config.runtimeContainer;\n if (config.debug) {\n this.logger = debugHost(this);\n }\n if (!config.disableMetrics) {\n addMetrics(this);\n }\n }\n /**\n * Return all loaded guests.\n */\n getLoadedGuests<T = unknown>(): Port<T>[];\n /**\n * Return loaded guests which satisfy the passed test function.\n */\n getLoadedGuests<T = unknown>(filter: GuestFilter): Port<T>[];\n /**\n * Return loaded guests which expose the provided {@link CapabilitySpec}.\n */\n getLoadedGuests<Apis extends GuestApis>(\n capabilities: CapabilitySpec<Apis>\n ): Port<GuestApis>[];\n getLoadedGuests<Apis extends GuestApis = never>(\n filterOrCapabilities?: CapabilitySpec<Apis> | GuestFilter\n ): Port<GuestApis>[] {\n if (typeof filterOrCapabilities === \"object\") {\n return this.getLoadedGuestsWith<Apis>(filterOrCapabilities);\n }\n const filter = filterOrCapabilities || passAllGuests;\n const result = [];\n for (const guest of this.guests.values()) {\n if (guest.isReady() && filter(guest)) {\n result.push(guest as Port<GuestApis>);\n }\n }\n return result;\n }\n /**\n * Set the object of shared values that all Guests can access via {@link @adobe/uix-guest#GuestServer.sharedContext}.\n * This overwrites any previous object.\n *\n * @example Exposes `authToken` to all Guests. Guests can call `this.sharedContext.get('authToken')` to retrieve this value.\n * ```javascript\n * host.shareContext({\n * authToken: '82ba19b'\n * });\n * ```\n *\n * @example Overwrites the previous sharedContext, deleting `authToken` and providing `secret` and `auth` instead.\n * ```javascript\n * host.shareContext({\n * secret: 'squirrel',\n * auth: false\n * });\n * ```\n */\n shareContext(context: SharedContextValues): void;\n /**\n * Update the object of shared values that all Guests can access via {@link\n * @adobe/uix-guest#GuestServer.sharedContext}. This method takes a callback\n * which receives the previous context and may return an entirely new context,\n * or new values merged with the old context.\n *\n * @remarks This callback pattern allows the shared context values to be\n * mutable while the internal context object references are immutable, which\n * is important for synchronizing. with guests.\n *\n * @example Overwrites a context object based on the previous one.\n * ```javascript\n * host.shareContext(oldContext => ({\n * counter: oldContext.counter + 1\n * }))\n * ```\n *\n * @example Updates a context while preserving other existing values.\n * ```javascript\n * host.shareContext(oldContext => ({\n * ...oldContext,\n * counter: oldContext.counter + 1\n * }))\n * ```\n */\n shareContext(\n setter: (context: SharedContextValues) => SharedContextValues\n ): void;\n shareContext(\n setter: (context: SharedContextValues) => SharedContextValues\n ): void;\n shareContext(\n setterOrContext:\n | ((context: SharedContextValues) => SharedContextValues)\n | SharedContextValues\n ) {\n if (typeof setterOrContext === \"function\") {\n this.sharedContext = setterOrContext(this.sharedContext);\n } else {\n this.sharedContext = setterOrContext;\n }\n this.emit(\"contextchange\", {\n host: this,\n context: this.sharedContext,\n });\n }\n /**\n * Load extension into host application from provided extension description.\n * Returned promise resolves when all extensions are loaded and registered.\n *\n * @param extensions - List of extension descriptors. Normally, the Host should receive this value from an {@link ExtensionsProvider}.\n * @param options - Custom options to be used as defaults for each {@link Port} object created for each guest.\n * @returns Promise which resolves when all guests have been loaded.\n */\n async load(\n extensions: InstalledExtensions,\n options?: PortOptions\n ): Promise<void> {\n this.runtimeContainer =\n this.runtimeContainer || this.createRuntimeContainer(window);\n const result = compareExtensions(this.lastExtenstionList, extensions);\n this.lastExtenstionList = extensions;\n const extensionsToAdd = Object.entries(result.added);\n const extensionsToRemove = Object.entries(result.removed);\n if (result.hasChanges && extensionsToAdd.length > 0) {\n this.logger.log(\n `Host ${this.hostName} loading extensions:`,\n extensionsToAdd\n );\n await this.addLoadsNewGuests(result.added, options);\n }\n\n if (result.hasChanges && extensionsToRemove.length > 0) {\n this.logger.log(\n `Host ${this.hostName} removing extensions:`,\n extensionsToRemove\n );\n extensionsToRemove.forEach(async ([id, ext]) => {\n if (typeof ext === \"object\" && ext !== null && \"url\" in ext) {\n await this.removeGuest(id, ext as Extension);\n }\n });\n }\n }\n\n async addLoadsNewGuests(\n extensions: InstalledExtensions,\n options?: PortOptions\n ): Promise<void> {\n const failed: Port[] = [];\n const loaded: Port[] = [];\n this.loading = true;\n await Promise.all(\n Object.entries(extensions).map(async ([id, extension]) => {\n const port = await this.loadOneGuest(id, extension, options);\n (port.error ? failed : loaded).push(port);\n })\n );\n this.loading = false;\n this.emit(\"loadallguests\", { host: this, failed, loaded });\n }\n\n /**\n * Unload and remove a specific extension by its ID.\n */\n async removeGuest(id: string, extension: Extension): Promise<void> {\n const guest = this.guests.get(id);\n if (guest) {\n this.emit(\"guestbeforeunload\", { guest, host: this });\n await guest.unload();\n this.guests.delete(id);\n this.emit(\"guestunload\", { guest, host: this });\n }\n }\n\n /**\n * Unload all extensions and remove their frames/workers. Use this to unmount\n * a UI or when switching to a different extensible UI.\n */\n async unload(): Promise<void> {\n this.emit(\"beforeunload\", { host: this });\n await Promise.all([...this.guests.values()].map((guest) => guest.unload()));\n this.guests.clear();\n this.runtimeContainer.parentElement.removeChild(this.runtimeContainer);\n this.emit(\"unload\", { host: this });\n }\n\n private createRuntimeContainer(window: Window) {\n const { document } = window;\n const container = document.createElement(\"div\");\n container.setAttribute(\"data-uix-guest-container\", this.hostName);\n container.setAttribute(\"role\", \"presentation\");\n container.setAttribute(\"aria-hidden\", \"true\");\n Object.assign(container.style, Host.containerStyle);\n document.body.appendChild(container);\n return container;\n }\n private async loadOneGuest<T = unknown>(\n id: string,\n extension: string | Extension,\n options: PortOptions = {}\n ): Promise<Port<T>> {\n let guest = this.guests.get(id);\n if (!guest) {\n const isExtension = (item: any): item is Extension => {\n return typeof item === \"object\" && item !== null && \"url\" in item;\n };\n\n const isExtensionObject = isExtension(extension);\n const extensionUrl = isExtensionObject ? extension.url : extension;\n const extensionConfiguration = isExtensionObject\n ? extension.configuration\n : undefined;\n\n const extensionPoints = isExtensionObject\n ? extension.extensionPoints\n : [];\n\n const url = new URL(extensionUrl);\n guest = new Port({\n owner: this.hostName,\n id,\n url,\n runtimeContainer: this.runtimeContainer,\n options: {\n ...this.guestOptions,\n ...options,\n },\n logger: this.logger,\n sharedContext: this.sharedContext,\n configuration: extensionConfiguration,\n extensionPoints,\n events: this as Emits,\n });\n this.guests.set(id, guest);\n }\n this.emit(\"guestbeforeload\", { guest, host: this });\n try {\n await guest.load();\n } catch (e: unknown) {\n const error = new Error(\n `Guest ${guest.id} failed to load: at ${guest.url}: ${\n e instanceof Error ? e.stack : String(e)\n }`\n );\n this.emit(\"error\", { host: this, guest, error });\n return guest;\n }\n // this new guest might have new capabilities, so the identities of the\n // cached capability sets will need to change, to alert subscribers\n this.cachedCapabilityLists = new WeakMap();\n this.emit(\"guestload\", { guest, host: this });\n return guest;\n }\n private getLoadedGuestsWith<Apis extends GuestApis>(\n capabilities: CapabilitySpec<Apis>\n ) {\n if (this.cachedCapabilityLists.has(capabilities)) {\n return this.cachedCapabilityLists.get(capabilities);\n }\n const guestsWithCapabilities = this.getLoadedGuests((guest) =>\n guest.hasCapabilities(capabilities)\n );\n this.cachedCapabilityLists.set(capabilities, guestsWithCapabilities);\n return guestsWithCapabilities;\n }\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport type {\n Emits,\n GuestConnection,\n GuestConnectionEvents,\n HostMethodAddress,\n GuestApis,\n CrossRealmObject,\n Unsubscriber,\n VirtualApi,\n UIHostMethods,\n GuestMetadata,\n} from \"@adobe/uix-core\";\nimport { Emitter, connectIframe } from \"@adobe/uix-core\";\nimport { normalizeIframe } from \"./dom-utils\";\nimport { compareVersions } from \"./utils/comparePackagesVersions\";\n\n/**\n * A specifier for methods to be expected on a remote interface.\n *\n * @remarks\n * A CapabilitySpec is a description of an interface, like a very simplified\n * type definition. It specifies an object structure and the paths in that\n * structure that must be functions. (It doesn't specify anything about the\n * signatures or return values of those functions.)\n *\n * Use CapabilitySpec objects as queries, or filters, to get a subset of\n * installed extensions which have registered methods which match the spec.\n *\n * @example\n * As an extensible app developer, you are making an extension point for spell\n * check. Your code expects extensions to register an API `spellCheck` with\n * methods called `spellCheck.correct(text)` and `spellCheck.suggest(text)`.\n *\n * ```javascript\n * async function correctText(text) {\n * const spellCheckers = host.getLoadedGuests({\n * spellCheck: [\n * 'correct',\n * 'suggest'\n * ]\n * });\n * let correcting = text;\n * for (const checker of spellCheckers) {\n * correcting = await checker.apis.spellCheck.correct(correcting);\n * }\n * return Promise.all(checkers.map(checker =>\n * checker.apis.spellCheck.suggest(correcting)\n * ));\n * }\n * ```\n *\n * @public\n */\nexport type CapabilitySpec<T extends GuestApis> = {\n [Name in keyof T]+?: (keyof T[Name])[];\n};\n\n/**\n * Interface for decoupling of guest Penpal object\n * @internal\n */\ninterface GuestProxyWrapper {\n // #region Properties (1)\n\n /**\n * Methods from guest\n */\n apis: VirtualApi;\n\n // #endregion Properties (1)\n\n // #region Public Methods (1)\n\n /**\n * Emit an event in the guest frame\n */\n emit(type: string, detail: unknown): Promise<void>;\n\n metadata: GuestMetadata;\n\n // #endregion Public Methods (1)\n}\n\n/** @public */\nexport type PortOptions = {\n /**\n * Time in milliseconds to wait for the guest to connect before throwing.\n */\n timeout?: number;\n /**\n * Set true to log copiously in the console.\n */\n debug?: boolean;\n};\n\nconst defaultOptions = {\n timeout: 20000,\n debug: false,\n};\n\nconst WRAPPER_MARKER = \"$_UISDK_FN_WRAPPER\";\n/**\n * Marker interface for detection of wrapped functions\n */\ntype WrappedFunction = {\n (...args: unknown[]): unknown;\n [WRAPPER_MARKER]: boolean;\n};\n\n/**\n * Function typeguard\n *\n * @param v\n * @returns boolean\n */\nconst isFunction = (v: unknown): v is CallableFunction => {\n return typeof v === \"function\";\n};\n\n/**\n * Typeguard for wrapped functions\n *\n * @param v\n * @returns\n */\nconst isWrapperFunction = (v: unknown): v is WrappedFunction => {\n return (\n typeof v === \"function\" && (v as WrappedFunction)[WRAPPER_MARKER] === true\n );\n};\n\n/**\n * A Port is the Host-maintained object representing an extension running as a\n * guest. It exposes methods registered by the Guest, and can provide Host\n * methods back to the guest.\n *\n * @remarks\n * When the Host object loads extensions via {@link Host.load}, it creates a\n * Port object for each extension. When retrieving and filtering extensions\n * via {@link Host.(getLoadedGuests:2)}, a list of Port objects is returned. From\n * the point of view of the extensible app using the Host object, extensions\n * are always Port objects, which expose the methods registered by the\n * extension at the {@link Port.apis} property.\n *\n * @privateRemarks\n * We've gone through several possible names for this object. GuestProxy,\n * GuestInterface, GuestConnection, etc. \"Port\" is not ideal, but it conflicted\n * the least with other types we defined in early drafts. It's definitely\n * something we should review.\n * @public\n */\nexport class Port<GuestApi = unknown>\n extends Emitter<GuestConnectionEvents>\n implements GuestConnection\n{\n public get apis() {\n if (this.isReady() && this.guestServer) {\n const server = this.guestServer.getRemoteApi();\n return server && this.addApiMiddleware(server.apis);\n }\n }\n\n public get metadata(): GuestMetadata {\n if (this.isReady() && this.guestServer) {\n const server = this.guestServer.getRemoteApi();\n return server && server.metadata;\n }\n }\n\n // #region Properties (13)\n\n private debug: boolean;\n private logger?: Console;\n private guestServerFrame: HTMLIFrameElement;\n private hostApis: VirtualApi = {};\n private isLoaded = false;\n private isGuestReady = false;\n private guestReadyMessageHandler: ((event: MessageEvent) => void) | null =\n null;\n private runtimeContainer: HTMLElement;\n private sharedContext: Record<string, unknown>;\n private configuration?: Record<string, unknown>;\n private subscriptions: Unsubscriber[] = [];\n private timeout: number;\n\n /**\n * If any errors occurred during the loading of guests, this property will\n * contain the error that was raised.\n * @public\n */\n error?: Error;\n /**\n * The URL of the guest provided by the extension registry. The Host will\n * load this URL in the background, in the invisible the bootstrap frame, so\n * this URL must point to a page that calls {@link @adobe/uix-guest#register}\n * when it loads.\n */\n public url: URL;\n public extensionPoints: string[];\n private guestServer: CrossRealmObject<GuestProxyWrapper>;\n private guestVersion: string | undefined;\n\n // #endregion Properties (13)\n\n // #region Constructors (1)\n\n constructor(config: {\n owner: string;\n id: string;\n url: URL;\n /**\n * An alternate DOM element to use for invisible iframes. Will create its\n * own if this option is not populated with a DOM element.\n */\n runtimeContainer: HTMLElement;\n options: PortOptions;\n logger?: Console;\n /**\n * Initial object to populate the shared context with. Once the guest\n * connects, it will be able to access these properties.\n */\n sharedContext: Record<string, unknown>;\n /**\n * A guest (extension) configuration\n */\n configuration?: Record<string, unknown>;\n /**\n * Guest (extension) extension points\n */\n extensionPoints?: string[];\n events: Emits;\n }) {\n super(config.id);\n const { timeout, debug } = { ...defaultOptions, ...(config.options || {}) };\n this.timeout = timeout;\n this.debug = debug;\n this.logger = config.logger;\n this.id = config.id;\n this.url = config.url;\n this.runtimeContainer = config.runtimeContainer;\n this.sharedContext = config.sharedContext;\n this.configuration = config.configuration;\n this.extensionPoints = config.extensionPoints;\n this.subscriptions.push(\n config.events.addEventListener(\"contextchange\", async (event) => {\n this.sharedContext = (\n (event as CustomEvent).detail as unknown as Record<string, unknown>\n ).context as Record<string, unknown>;\n await this.load();\n await this.guestServer\n .getRemoteApi()\n .emit(\"contextchange\", { context: this.sharedContext });\n })\n );\n }\n\n // #endregion Constructors (1)\n\n // #region Public Methods (6)\n\n /**\n * Connect an iframe element which is displaying another page in the extension\n * with the extension's bootstrap frame, so they can share context and events.\n */\n public attachUI<T = unknown>(\n iframe: HTMLIFrameElement,\n privateMethods: VirtualApi\n ): Promise<CrossRealmObject<T>> {\n return this.attachFrame(iframe, {\n onIframeResize: (dimensions: { height: number; width: number }) => {\n this.emit(\"guestresize\", {\n dimensions,\n guestPort: this,\n iframe: iframe,\n });\n },\n ...privateMethods,\n } as UIHostMethods);\n }\n\n /**\n * Returns true if the guest has registered methods matching the provided\n * capability spec. A capability spec is simply an object whose properties are\n * declared in an array of keys, description the names of the functions and\n * methods that the Port will expose.\n */\n public hasCapabilities(requiredCapabilities: CapabilitySpec<GuestApis>) {\n this.assertReady();\n return (\n this.apis &&\n Object.entries(requiredCapabilities).every(([apiName, methodNames]) =>\n this.hasCapability(apiName, methodNames as string[])\n )\n );\n }\n\n /**\n * True when all extensions have loaded.\n */\n public isReady(): boolean {\n if (this.guestVersion && this.guestVersion.length > 0) {\n if (compareVersions(this.guestVersion, \"1.1.3\") >= 0) {\n return this.isLoaded && !this.error && this.isGuestReady;\n } else {\n return this.isLoaded && !this.error;\n }\n }\n return false;\n }\n\n /**\n * Loads the extension. Returns a promise which resolves when the extension\n * has loaded. The Host calls this method after retrieving extensions.\n */\n public async load() {\n try {\n if (!this.isLoaded) {\n await this.connect();\n }\n } catch (e) {\n this.guestServer = null;\n this.error = e instanceof Error ? e : new Error(String(e));\n throw e;\n }\n }\n\n /**\n * The host-side equivalent of {@link @adobe/uix-guest#register}. Pass a set\n * of methods down to the guest as proxies.\n * Merges at the first level, the API level. Overwrites a deeper levels.\n */\n public provide(apis: VirtualApi) {\n for (const [apiNamespace, methods] of Object.entries(apis)) {\n this.hostApis[apiNamespace] = this.hostApis[apiNamespace] || {};\n Object.assign(this.hostApis[apiNamespace], methods);\n }\n this.emit(\"hostprovide\", { guestPort: this, apis });\n }\n\n /**\n * Disconnect from the extension.\n */\n public async unload(): Promise<void> {\n // Clean up guest ready message handler if it exists\n if (this.guestReadyMessageHandler) {\n window.removeEventListener(\"message\", this.guestReadyMessageHandler);\n this.guestReadyMessageHandler = null;\n this.isGuestReady = false;\n }\n\n for (const unsubscribe of this.subscriptions) {\n if (typeof unsubscribe === \"function\") {\n unsubscribe();\n }\n }\n this.subscriptions = [];\n\n if (this.guestServerFrame && this.guestServerFrame.parentElement) {\n this.guestServerFrame.parentElement.removeChild(this.guestServerFrame);\n this.guestServerFrame = undefined;\n }\n\n this.emit(\"unload\", { guestPort: this });\n }\n\n // #endregion Public Methods (6)\n\n // #region Private Methods (6)\n\n /**\n * Recursive method that wraps every function in apis object and adds\n * an event\n */\n private addApiMiddleware(subject: any, path: string[] = []): VirtualApi {\n if (typeof subject === \"object\") {\n for (const [key, value] of Object.entries(subject)) {\n if (typeof value === \"object\") {\n subject[key] = this.addApiMiddleware(value, [...path, key]);\n } else if (isWrapperFunction(value)) {\n // Remote function is already wrapped. Nothing to do...\n continue;\n } else if (isFunction(value)) {\n const wrapper = async (...args: any) => {\n this.emit(\"beforecallguestmethod\", {\n guestPort: this,\n path: [...path, key],\n args,\n });\n const res = await (value as CallableFunction)(...args);\n /*\n * Wraps response in middleware so consequent calls could be intercepted\n * E.g. headerMenu.getButtons().onClick()\n */\n return this.addApiMiddleware(res, [...path, key]);\n };\n (wrapper as WrappedFunction)[WRAPPER_MARKER] = true;\n subject[key] = wrapper;\n }\n }\n }\n\n return subject;\n }\n\n private hasCapability(apiName: string, methodNames: string[]) {\n const api = this.apis[apiName];\n return (\n api &&\n methodNames.every(\n (methodName: keyof typeof api) =>\n Reflect.has(api, methodName) && typeof api[methodName] === \"function\"\n )\n );\n }\n\n private assert(\n condition: boolean,\n errorMessage: () => string\n ): asserts condition {\n if (!condition) {\n throw new Error(\n `Error in guest extension \"${this.id}\": ${errorMessage()}`\n );\n }\n }\n\n private assertReady() {\n this.assert(this.isReady(), () => \"Attempted to interact before loaded\");\n }\n\n private attachFrame<T = unknown>(\n iframe: HTMLIFrameElement,\n addedMethods: object = {}\n ) {\n // at least this is necessary\n normalizeIframe(iframe);\n return connectIframe<T>(\n iframe,\n {\n logger: this.logger,\n targetOrigin: this.url.origin,\n timeout: this.timeout,\n },\n {\n getSharedContext: () => {\n return this.sharedContext;\n },\n getConfiguration: () => {\n return this.configuration;\n },\n invokeHostMethod: (address: HostMethodAddress) =>\n this.invokeHostMethod(address, addedMethods as VirtualApi),\n ...addedMethods,\n },\n (version: string) => {\n this.guestVersion = version;\n }\n );\n }\n\n private async connect() {\n let timeoutId: ReturnType<typeof setTimeout>;\n const serverFrame =\n this.runtimeContainer.ownerDocument.createElement(\"iframe\");\n normalizeIframe(serverFrame);\n serverFrame.setAttribute(\"aria-hidden\", \"true\");\n serverFrame.setAttribute(\"src\", this.url.href);\n this.guestServerFrame = serverFrame;\n this.runtimeContainer.appendChild(serverFrame);\n if (this.logger) {\n this.logger.info(\n `Guest ${this.id} attached iframe of ${this.url.href}`,\n this\n );\n }\n try {\n this.guestServer = await this.attachFrame<GuestProxyWrapper>(serverFrame);\n } catch (error) {\n this.logger?.error(\n `Failed to attach guest server for ${this.id}:`,\n error\n );\n clearTimeout(timeoutId);\n }\n\n const handleMessage = (event: MessageEvent) => {\n // Check if this is a guest-ready message from our specific iframe\n if (\n event.data &&\n event.data.type === \"guest-ready\" &&\n event.source === serverFrame.contentWindow\n ) {\n this.logger?.log(\n `[Port ${this.id}] Received guest-ready from our iframe (guest: ${\n event.data.guestId || \"unknown\"\n })`\n );\n this.isGuestReady = true;\n if (this.logger) {\n this.logger.info(`Guest ${this.id} reported ready status`);\n }\n this.emit(\"guestready\", { guestPort: this });\n\n // Clean up listener and resolve\n window.removeEventListener(\"message\", handleMessage);\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n\n // Store cleanup function\n this.guestReadyMessageHandler = handleMessage;\n\n this.isLoaded = true;\n if (this.logger) {\n this.logger.info(\n `Guest ${this.id} established connection, received methods, and reported ready`,\n this.apis,\n this\n );\n }\n }\n\n private getHostMethodCallee<T = unknown>(\n { name, path }: HostMethodAddress,\n methodSource: VirtualApi\n ): VirtualApi {\n const dots = (level: number) => `host.${path.slice(0, level).join(\".\")}`;\n const methodCallee = path.reduce((current, prop, level) => {\n this.assert(\n Reflect.has(current, prop),\n () => `${dots(level)} has no property \"${prop}\"`\n );\n const next = current[prop];\n this.assert(\n typeof next === \"object\",\n () =>\n `${dots(\n level\n )}.${prop} is not an object; namespaces must be objects with methods`\n );\n return next as VirtualApi;\n }, methodSource);\n this.assert(\n typeof methodCallee[name] === \"function\" &&\n Reflect.has(methodCallee, name),\n () => `\"${dots(path.length - 1)}.${name}\" is not a function`\n );\n return methodCallee;\n }\n\n private invokeHostMethod<T = unknown>(\n address: HostMethodAddress,\n privateMethods?: VirtualApi\n ): T {\n const { name, path, args = [] } = address;\n this.assert(name && typeof name === \"string\", () => \"Method name required\");\n this.assert(\n path.length > 0,\n () =>\n `Cannot call a method directly on the host; \".${name}()\" must be in a namespace.`\n );\n let methodCallee;\n if (privateMethods) {\n try {\n methodCallee = this.getHostMethodCallee(address, privateMethods);\n } catch (e) {\n // private method not found, continue and try other way of accessing it\n }\n }\n if (!methodCallee) {\n methodCallee = this.getHostMethodCallee(address, this.hostApis);\n }\n const method = methodCallee[name] as (...args: unknown[]) => T;\n this.emit(\"beforecallhostmethod\", { guestPort: this, name, path, args });\n return method.apply(methodCallee, [\n { id: this.id, url: this.url },\n ...args,\n ]) as T;\n }\n\n // #endregion Private Methods (6)\n}\n","/**\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/**\n * Strings to be used as values in a space-separated HTML attribute.\n * @internal\n */\nexport type AttrTokens<T> = string | T[];\n\n/**\n * Normalize an argument that may be either a space-separated HTML attribute\n * value or an array of those attribute values into an array of those values.\n * @internal\n */\nexport const tokenizeAttrValues = <T>(tokens: AttrTokens<T>) =>\n (typeof tokens === \"string\" ? tokens.split(\" \") : tokens) as T[];\n\n/**\n * Merge, deduplicate and typecheck a set of strings for an HTML attribute that\n * requires those values to be space-separated tokens.\n * @internal\n *\n * @remarks\n * Useful as a typed interface for any DOM property that is a DOMTokenList.\n * While the DOMTokenList does its own deduplication, it's slightly slower,\n * and while it may do validation of legal tokens, it only does so at runtime.\n * Using {@link AttrTokens} and this function adds typing and autocomplete.\n *\n *\n * @example\n * ```typescript\n * type AllowedClasses =\n * | \"primary\"\n * | \"light\"\n * | \"large\"\n * | \"quiet\";\n *\n * // combine with existing classes and set attribute directly\n * function setStyles(elm: HTMLElement, styles: AttrTokens<AllowedClasses>) {\n * const classNames = mergeAttrValues(\n * elm.className as AttrTokens<AllowedClasses>,\n * styles\n * );\n * elm.className = classNames.join(' ');\n * }\n *\n * // use DOM property directly, but now it's typed!\n * function setSandbox(\n * iframe: HTMLIframeElement,\n * allowedSandboxes: AttrTokens<\"allow-scripts\" | \"allow-popups\">\n * ) {\n * mergeAttrValues(allowedSandboxes).forEach(val => iframe.sandbox.add(val));\n * }\n * ```\n */\nexport const mergeAttrValues = <T>(...tokenLists: AttrTokens<T>[]) => {\n const allMerged = new Set<T>();\n for (const tokenList of tokenLists) {\n for (const token of tokenizeAttrValues(tokenList)) {\n allMerged.add(token);\n }\n }\n return [...allMerged];\n};\n","/**\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { HTMLAttributeReferrerPolicy } from \"react\";\nimport { AttrTokens, mergeAttrValues } from \"./attribute-normalizers\";\n\n/**\n * Sandbox permissions that guest iframes are allowed to have.\n * @internal\n */\ntype SandboxPermission =\n | \"downloads\"\n | \"orientation-lock\"\n | \"pointer-lock\"\n | \"popups\"\n | \"presentation\"\n | \"same-origin\"\n | \"scripts\"\n | \"storage-access-by-user-activation\"\n | \"top-navigation-by-user-activation\";\n\n/**\n * Character strings allowed in \"sandbox=\" attribute.\n * @internal\n */\nexport type SandboxToken = `allow-${SandboxPermission}`;\n\n/**\n * Merge lists of attrs together\n * @internal\n */\nexport const makeSandboxAttrs = (...sandboxes: AttrTokens<SandboxToken>[]) =>\n mergeAttrValues<SandboxToken>(...sandboxes);\n\n/**\n * Limit provided set of \"sandbox\" attributes to a list of legal ones.\n * @internal\n */\nexport const requiredIframeProps = {\n // must not require this until app builder supports CSP\n // csp: \"frame-ancestors 'self'\",\n \"data-uix-guest\": \"true\",\n role: \"presentation\",\n referrerPolicy: \"strict-origin\" as HTMLAttributeReferrerPolicy,\n};\n\nconst requiredIframeAttrEntries = Object.entries(requiredIframeProps);\n\n/**\n * Set and/or verify the required properties for use with uix-sdk on an iframe.\n * @internal\n */\nexport const normalizeIframe = (iframe: HTMLIFrameElement) => {\n for (const [attr, value] of requiredIframeAttrEntries) {\n iframe.setAttribute(attr, value);\n }\n};\n","export function compareVersions(v1: string, v2: string): number {\n const versionToArray = (v: string) => v.split(\".\").map((x) => Number(x) || 0);\n const v1Array = versionToArray(v1);\n const v2Array = versionToArray(v2);\n const len = Math.max(v1Array.length, v2Array.length);\n for (let i = 0; i < len; i++) {\n const n1 = v1Array[i] ?? 0;\n const n2 = v2Array[i] ?? 0;\n if (n1 > n2) return 1;\n if (n1 < n2) return -1;\n }\n return 0;\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/**\n * Adapter to attach console logging listeners to a Host running in an app\n * @hidden\n */\nimport {\n debugEmitter,\n EmitterDebugLogger,\n Emits,\n GuestEmitter,\n} from \"@adobe/uix-core\";\nimport type { HostEventLoadAllGuests, HostEvents } from \"./host.js\";\n\nexport function debugHost(host: Emits<HostEvents>): EmitterDebugLogger {\n const hostLogger = debugEmitter(host, {\n theme: \"blue medium\",\n type: \"Host\",\n });\n hostLogger\n .listen(\"guestbeforeload\", (log, event) => {\n const { detail } = event;\n const guest = detail.guest as GuestEmitter;\n log.info(event, `Guest ID ${guest.id}`);\n const portLogger = debugEmitter(guest, {\n theme: \"green medium\",\n type: \"Port\",\n id: `${host.id} ➔ ${guest.id}`,\n });\n portLogger\n .listen(\"hostprovide\", (log, event) => {\n log.info(\"received APIs\", event.detail.apis);\n })\n .listen(\"beforecallhostmethod\", (log, event) => {\n log.info(event.detail);\n })\n .listen(\"guestresize\", (log, event) => {\n log.info(event.detail);\n })\n .listen(\"unload\", (log, event) => {\n log.info(event.detail);\n log.detach();\n })\n .listen(\"beforecallguestmethod\", (log, event) => {\n log.info(event.detail);\n });\n })\n .listen(\"guestload\", (log, e) => {\n log.info(e.detail.guest.id, e.detail.guest);\n })\n .listen(\"error\", (log, e) => {\n log.error(`Error: ${e.detail.error.message}`, e);\n })\n .listen(\n \"loadallguests\",\n (log, { detail: { failed, loaded, host } }: HostEventLoadAllGuests) => {\n if (failed.length > 0) {\n log.error(\"%d guests failed to load!\", failed.length);\n }\n log.info(\"%d guests loaded\", loaded.length, host);\n }\n )\n .listen(\"unload\", (log) => {\n log.info(\"Unloaded guest and container.\");\n log.detach();\n });\n return hostLogger;\n}\n","/*\nCopyright 2024 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/**\n * Adapter to attach console logging listeners to a Host running in an app\n * @hidden\n */\nimport { Emitter } from \"@adobe/uix-core\";\nimport type { HostEvents } from \"./host.js\";\nimport type { Metrics } from \"@adobe/exc-app/metrics\";\nimport MetricsApi from \"@adobe/exc-app/metrics\";\n\ntype EventPayload = {\n event: string;\n args: any;\n};\n\n/**\n * Wrapper class for handling metrics and event tracking.\n */\nclass MetricsWrapper {\n private eventPool: EventPayload[] = [];\n private metricsInstance?: Readonly<Metrics> | undefined = undefined;\n\n /**\n * Sends collected events to the metrics instance.\n */\n private flush(): void {\n if (!this.metricsInstance) {\n return;\n }\n\n this.eventPool.forEach((eventPayload) => {\n this.metricsInstance.event(eventPayload.event, eventPayload.args);\n });\n this.eventPool = [];\n }\n\n /**\n * Gets the current metrics instance.\n */\n public get mertricsInstance(): Readonly<Metrics> | undefined {\n return this.metricsInstance;\n }\n\n /**\n * Sets the metrics instance and flushes any pending events.\n */\n public set mertricsInstance(metrics: Readonly<Metrics>) {\n this.metricsInstance = metrics;\n this.metricsInstance && this.flush();\n }\n\n /**\n * Tracks an event using the metrics instance, or adds it to the event pool if no instance is set.\n */\n public event(event: string, args: any): void {\n if (this.metricsInstance) {\n this.metricsInstance.event(event, args);\n } else {\n this.eventPool.push({ event, args });\n }\n }\n}\nconst metrics = new MetricsWrapper();\n\nconst seenGuests = new Set();\nconst runtimeWaitTimeout = 10000;\nconst createMetricsInstance = () => MetricsApi.create(\"exc.uix.core\");\n\nconst startTime = Date.now();\n/**\n * Monitors the availability of the runtime module and creates a metrics instance when it becomes available.\n * If the runtime module is not found within the specified timeout, it exits and no events will be sent.\n * @returns {void}\n */\nconst runtimeSpy = () => {\n if (startTime + runtimeWaitTimeout < Date.now()) {\n // Timeout, time to hang up\n return;\n }\n if (\"exc-module-runtime\" in window) {\n metrics.mertricsInstance = createMetricsInstance();\n return;\n }\n setTimeout(runtimeSpy, 1000);\n};\nruntimeSpy();\n\n/**\n * Adds metrics tracking to the host.\n *\n * @param host - The host emitter to attach the metrics to.\n */\nexport function addMetrics(host: Emitter<HostEvents>): void {\n host.addEventListener(\"guestload\", (evt) => {\n const guest = evt.detail.guest;\n if (seenGuests.has(guest)) {\n return;\n }\n seenGuests.add(guest);\n const addGuestId = (payload: any): any => {\n payload[\"guestId\"] = guest.id;\n return payload;\n };\n\n metrics.event(\"load\", addGuestId({}));\n\n guest.addEventListener(\"beforecallguestmethod\", (callDetails) => {\n const { path } = callDetails.detail;\n metrics.event(\n \"callguestmethod\",\n addGuestId({\n path: (path as string[]).join(\".\"),\n })\n );\n });\n guest.addEventListener(\"beforecallhostmethod\", (callDetails) => {\n const { path, name } = callDetails.detail;\n path.push(name);\n metrics.event(\n \"callhostmethod\",\n addGuestId({\n path: (path as string[]).join(\".\"),\n })\n );\n });\n });\n\n host.addEventListener(\"error\", () => {\n metrics.event(\"error\", {});\n });\n}\n","/*\nCopyright 2025 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { Extension } from \"@adobe/uix-core\";\nimport { InstalledExtensions } from \"../host\";\n\nexport interface ExtensionsDifference {\n added: Record<string, Extension[\"url\"] | Extension>;\n removed: Record<string, Extension[\"url\"] | Extension>;\n modified: Record<\n string,\n {\n old: Extension[\"url\"] | Extension;\n new: Extension[\"url\"] | Extension;\n }\n >;\n hasChanges: boolean;\n}\n\nexport function compareExtensions(\n extensions1: InstalledExtensions,\n extensions2: InstalledExtensions\n): ExtensionsDifference {\n const result: ExtensionsDifference = {\n added: {},\n removed: {},\n modified: {},\n hasChanges: false,\n };\n\n const keys1 = new Set(Object.keys(extensions1));\n const keys2 = new Set(Object.keys(extensions2));\n const allKeys = new Set([...keys1, ...keys2]);\n\n for (const key of allKeys) {\n const exists1 = keys1.has(key);\n const exists2 = keys2.has(key);\n\n if (!exists1 && exists2) {\n result.added[key] = extensions2[key];\n result.hasChanges = true;\n } else if (exists1 && !exists2) {\n result.removed[key] = extensions1[key];\n result.hasChanges = true;\n } else if (exists1 && exists2) {\n const ext1 = extensions1[key];\n const ext2 = extensions2[key];\n\n if (!areExtensionsEqual(ext1, ext2)) {\n result.modified[key] = {\n old: ext1,\n new: ext2,\n };\n result.hasChanges = true;\n }\n }\n }\n\n return result;\n}\n\nfunction areExtensionsEqual(\n ext1: Extension[\"url\"] | Extension,\n ext2: Extension[\"url\"] | Extension\n): boolean {\n if (typeof ext1 !== typeof ext2) {\n return false;\n }\n\n if (typeof ext1 === \"string\" && typeof ext2 === \"string\") {\n return ext1 === ext2;\n }\n\n if (typeof ext1 === \"object\" && typeof ext2 === \"object\") {\n if (ext1.id !== ext2.id || ext1.url !== ext2.url) {\n return false;\n }\n\n const ep1 = ext1.extensionPoints || [];\n const ep2 = ext2.extensionPoints || [];\n\n if (ep1.length !== ep2.length) {\n return false;\n }\n\n const sortedEp1 = [...ep1].sort();\n const sortedEp2 = [...ep2].sort();\n\n for (let i = 0; i < sortedEp1.length; i++) {\n if (sortedEp1[i] !== sortedEp2[i]) {\n return false;\n }\n }\n\n return deepEqual(ext1.configuration, ext2.configuration);\n }\n\n return false;\n}\n\nfunction deepEqual(obj1: unknown, obj2: unknown): boolean {\n if (obj1 === obj2) {\n return true;\n }\n\n if (obj1 == null || obj2 == null) {\n return obj1 === obj2;\n }\n\n if (typeof obj1 !== \"object\" || typeof obj2 !== \"object\") {\n return false;\n }\n\n const keys1 = Object.keys(obj1 as Record<string, unknown>);\n const keys2 = Object.keys(obj2 as Record<string, unknown>);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (!keys2.includes(key)) {\n return false;\n }\n\n if (\n !deepEqual(\n (obj1 as Record<string, unknown>)[key],\n (obj2 as Record<string, unknown>)[key]\n )\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function areExtensionsDifferent(\n extensions1: InstalledExtensions,\n extensions2: InstalledExtensions\n): boolean {\n return compareExtensions(extensions1, extensions2).hasChanges;\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { InstalledExtensions, ExtensionsProvider } from \"../host.js\";\n\ninterface ExtensionDefinition {\n name: string;\n title: string;\n description: string;\n icon: string;\n publisher: string;\n endpoints: Record<string, EndpointDefinition>;\n xrInfo: ExtensionInfo;\n status: string;\n}\n\ntype EndpointDefinition = Record<string, Array<OperationDefinition>>;\n\ninterface ExtensionInfo {\n supportEmail: string;\n appId: string;\n}\n\ninterface OperationDefinition {\n href: string;\n metadata: OperationMetadata;\n}\n\ninterface OperationMetadata {\n services: Array<object>;\n profile: OperationProfile;\n}\n\ninterface OperationProfile {\n client_id: string;\n scope: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryEndpointRegistration {\n service: string;\n extensionPoint: string;\n version: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryExtensionRegistration\n extends ExtensionRegistryEndpointRegistration {\n imsOrg: string;\n}\n\n/** @public */\nexport interface ExtensionRegistryConnection {\n baseUrl?: string;\n apiKey: string;\n workspace?: string;\n filter?: (extension: ExtensionDefinition) => boolean;\n auth: {\n schema: \"Basic\" | \"Bearer\";\n imsToken: string;\n };\n}\n\n/** @public */\nexport interface ExtensionRegistryConfig\n extends ExtensionRegistryExtensionRegistration,\n ExtensionRegistryConnection {}\n\nfunction buildEndpointPath(\n config: ExtensionRegistryEndpointRegistration\n): string {\n return `${config.service}/${config.extensionPoint}/${config.version}`;\n}\n\nfunction ensureProtocolSpecified(url: string) {\n if (url.startsWith(\"https://\")) {\n return url;\n }\n if (url.startsWith(\"http://\")) {\n return url;\n }\n return `https://${url}`;\n}\n\nexport async function fetchExtensionsFromRegistry(\n config: ExtensionRegistryConfig\n): Promise<Array<ExtensionDefinition>> {\n const workspaceParam = config.workspace\n ? `&workspace=${config.workspace}`\n : \"\";\n const resp = await fetch(\n `${ensureProtocolSpecified(\n config.baseUrl || \"appregistry.adobe.io\"\n )}/myxchng/v1/org/${encodeURIComponent(\n config.imsOrg\n )}/xtn/${buildEndpointPath(config)}?auth=true${workspaceParam}`,\n {\n headers: {\n Accept: \"application/json\",\n Authorization: `${config.auth.schema} ${config.auth.imsToken}`, // todo: check if auth schema needed (initial implementation was without it)\n \"X-Api-Key\": config.apiKey,\n },\n }\n );\n\n if (resp.status != 200) {\n throw new Error(\n `extension registry returned non-200 response (${\n resp.status\n }): ${await resp.text()}`\n );\n }\n\n return await resp.json();\n}\n\n/**\n * @deprecated\n */\nfunction extensionRegistryExtensionsProvider(\n config: ExtensionRegistryConfig\n): Promise<InstalledExtensions> {\n const erEndpoint = buildEndpointPath(config);\n return fetchExtensionsFromRegistry(config).then((out) =>\n out.reduce((a, e: ExtensionDefinition) => {\n if (e.status !== \"PUBLISHED\") {\n return a;\n }\n\n return {\n ...a,\n // todo: make safer way to extract href\n [e.name]: e.endpoints[erEndpoint].view[0].href,\n };\n }, {})\n );\n\n return Promise.resolve({});\n}\n\n/**\n * Fetch & return published extension objects from registry\n */\nfunction extensionRegistryExtensionsAsObjectsProvider(\n config: ExtensionRegistryConfig\n): Promise<InstalledExtensions> {\n const erEndpoint = buildEndpointPath(config);\n return fetchExtensionsFromRegistry(config).then((out) =>\n out.reduce((a, e: ExtensionDefinition) => {\n if (config.filter && typeof config.filter === \"function\") {\n if (!config.filter(e)) {\n return a;\n }\n } else if (e.status !== \"PUBLISHED\") {\n return a;\n }\n\n return {\n ...a,\n [e.name]: {\n id: e.name,\n url: e.endpoints[erEndpoint].view[0].href,\n extensionPoints: [erEndpoint],\n },\n };\n }, {})\n );\n}\n\n/**\n * Create a callback that fetches extensions from the registry.\n * @public\n * @deprecated use `createExtensionRegistryAsObjectsProvider()`\n */\nexport function createExtensionRegistryProvider(\n config: ExtensionRegistryConfig\n): ExtensionsProvider {\n return function () {\n return extensionRegistryExtensionsProvider(config);\n };\n}\n\n/**\n * Create a callback that fetches extensions as objects from the registry.\n * @public\n */\nexport function createExtensionRegistryAsObjectsProvider(\n config: ExtensionRegistryConfig\n): ExtensionsProvider {\n return function () {\n return extensionRegistryExtensionsAsObjectsProvider(config);\n };\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { InstalledExtensions, ExtensionsProvider } from \"../host.js\";\n\n/**\n * Combine multiple {@link @adobe/uix-host#ExtensionsProvider} callbacks into a\n * single callback, which aggregates and dedupes all extensions from all\n * providers into one namespaced object.\n * @public\n */\nexport function combineExtensionsFromProviders(\n ...providers: Array<ExtensionsProvider>\n): ExtensionsProvider {\n return () =>\n Promise.all(providers.map((ep: ExtensionsProvider) => ep())).then(\n (extensionsBatches: Array<InstalledExtensions>) => {\n return Object.assign({}, ...extensionsBatches);\n }\n );\n}\n","/*\nCopyright 2022 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { ExtensionsProvider } from \"../host.js\";\n\n/**\n * Mute any errors produced by provider.\n * This function would execute given provider and return its results as is, if any error occurs this provider will log it\n * any return an empty array of extensions.\n * @public\n */\nexport function mutedProvider(\n provider: ExtensionsProvider\n): ExtensionsProvider {\n return async () => {\n try {\n return await provider();\n } catch (error) {\n console.error(`Extension provider has failed: ${error.message}`, {\n error,\n });\n return {};\n }\n };\n}\n"]}
|
package/dist/port.d.ts
CHANGED
|
@@ -79,6 +79,8 @@ export declare class Port<GuestApi = unknown> extends Emitter<GuestConnectionEve
|
|
|
79
79
|
private guestServerFrame;
|
|
80
80
|
private hostApis;
|
|
81
81
|
private isLoaded;
|
|
82
|
+
private isGuestReady;
|
|
83
|
+
private guestReadyMessageHandler;
|
|
82
84
|
private runtimeContainer;
|
|
83
85
|
private sharedContext;
|
|
84
86
|
private configuration?;
|
|
@@ -99,6 +101,7 @@ export declare class Port<GuestApi = unknown> extends Emitter<GuestConnectionEve
|
|
|
99
101
|
url: URL;
|
|
100
102
|
extensionPoints: string[];
|
|
101
103
|
private guestServer;
|
|
104
|
+
private guestVersion;
|
|
102
105
|
constructor(config: {
|
|
103
106
|
owner: string;
|
|
104
107
|
id: string;
|
|
@@ -138,7 +141,7 @@ export declare class Port<GuestApi = unknown> extends Emitter<GuestConnectionEve
|
|
|
138
141
|
*/
|
|
139
142
|
hasCapabilities(requiredCapabilities: CapabilitySpec<GuestApis>): boolean;
|
|
140
143
|
/**
|
|
141
|
-
* True when
|
|
144
|
+
* True when all extensions have loaded.
|
|
142
145
|
*/
|
|
143
146
|
isReady(): boolean;
|
|
144
147
|
/**
|
package/dist/port.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,KAAK,EACL,eAAe,EACf,qBAAqB,EAErB,SAAS,EACT,gBAAgB,EAEhB,UAAU,EAEV,aAAa,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAiB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Extension } from "@adobe/uix-core";
|
|
2
|
+
import { InstalledExtensions } from "../host";
|
|
3
|
+
export interface ExtensionsDifference {
|
|
4
|
+
added: Record<string, Extension["url"] | Extension>;
|
|
5
|
+
removed: Record<string, Extension["url"] | Extension>;
|
|
6
|
+
modified: Record<string, {
|
|
7
|
+
old: Extension["url"] | Extension;
|
|
8
|
+
new: Extension["url"] | Extension;
|
|
9
|
+
}>;
|
|
10
|
+
hasChanges: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function compareExtensions(extensions1: InstalledExtensions, extensions2: InstalledExtensions): ExtensionsDifference;
|
|
13
|
+
export declare function areExtensionsDifferent(extensions1: InstalledExtensions, extensions2: InstalledExtensions): boolean;
|
|
14
|
+
//# sourceMappingURL=compareExtensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compareExtensions.d.ts","sourceRoot":"","sources":["../../src/utils/compareExtensions.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;IACtD,QAAQ,EAAE,MAAM,CACd,MAAM,EACN;QACE,GAAG,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;QAClC,GAAG,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;KACnC,CACF,CAAC;IACF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,mBAAmB,EAChC,WAAW,EAAE,mBAAmB,GAC/B,oBAAoB,CAqCtB;AA+ED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,mBAAmB,EAChC,WAAW,EAAE,mBAAmB,GAC/B,OAAO,CAET"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparePackagesVersions.d.ts","sourceRoot":"","sources":["../../src/utils/comparePackagesVersions.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAY9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/uix-host",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"bugs": "https://github.com/adobe/uix-sdk/issues",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@adobe/uix-core": "^1.1.
|
|
23
|
+
"@adobe/uix-core": "^1.1.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/jest": "^29.5.12",
|
package/src/host.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { Emitter, quietConsole } from "@adobe/uix-core";
|
|
|
22
22
|
import { Port, PortOptions } from "./port.js";
|
|
23
23
|
import { debugHost } from "./debug-host.js";
|
|
24
24
|
import { addMetrics } from "./metrics.js";
|
|
25
|
+
import { compareExtensions } from "./utils/compareExtensions.js";
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Dictionary of {@link Port} objects by extension ID.
|
|
@@ -69,6 +70,8 @@ export type HostEventError = HostEvent<"error", { error: Error }>;
|
|
|
69
70
|
export type HostEvents =
|
|
70
71
|
| HostGuestEvent<"beforeload">
|
|
71
72
|
| HostGuestEvent<"load">
|
|
73
|
+
| HostGuestEvent<"beforeunload">
|
|
74
|
+
| HostGuestEvent<"unload">
|
|
72
75
|
| HostEvent<"beforeunload">
|
|
73
76
|
| HostEvent<"unload">
|
|
74
77
|
| HostEventLoadAllGuests
|
|
@@ -80,6 +83,10 @@ export type InstalledExtensions = Record<
|
|
|
80
83
|
Extension["id"],
|
|
81
84
|
Extension["url"] | Extension
|
|
82
85
|
>;
|
|
86
|
+
|
|
87
|
+
/** @public */
|
|
88
|
+
export type ExtensionsArray = Array<[string, Extension | string]>;
|
|
89
|
+
|
|
83
90
|
/** @public */
|
|
84
91
|
export type ExtensionsProvider = () => Promise<InstalledExtensions>;
|
|
85
92
|
|
|
@@ -211,6 +218,8 @@ export class Host extends Emitter<HostEvents> {
|
|
|
211
218
|
top: 0,
|
|
212
219
|
left: "-1px",
|
|
213
220
|
};
|
|
221
|
+
|
|
222
|
+
private lastExtenstionList: InstalledExtensions = {};
|
|
214
223
|
/**
|
|
215
224
|
* Unique string identifying the Host object.
|
|
216
225
|
*/
|
|
@@ -355,6 +364,35 @@ export class Host extends Emitter<HostEvents> {
|
|
|
355
364
|
): Promise<void> {
|
|
356
365
|
this.runtimeContainer =
|
|
357
366
|
this.runtimeContainer || this.createRuntimeContainer(window);
|
|
367
|
+
const result = compareExtensions(this.lastExtenstionList, extensions);
|
|
368
|
+
this.lastExtenstionList = extensions;
|
|
369
|
+
const extensionsToAdd = Object.entries(result.added);
|
|
370
|
+
const extensionsToRemove = Object.entries(result.removed);
|
|
371
|
+
if (result.hasChanges && extensionsToAdd.length > 0) {
|
|
372
|
+
this.logger.log(
|
|
373
|
+
`Host ${this.hostName} loading extensions:`,
|
|
374
|
+
extensionsToAdd
|
|
375
|
+
);
|
|
376
|
+
await this.addLoadsNewGuests(result.added, options);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (result.hasChanges && extensionsToRemove.length > 0) {
|
|
380
|
+
this.logger.log(
|
|
381
|
+
`Host ${this.hostName} removing extensions:`,
|
|
382
|
+
extensionsToRemove
|
|
383
|
+
);
|
|
384
|
+
extensionsToRemove.forEach(async ([id, ext]) => {
|
|
385
|
+
if (typeof ext === "object" && ext !== null && "url" in ext) {
|
|
386
|
+
await this.removeGuest(id, ext as Extension);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async addLoadsNewGuests(
|
|
393
|
+
extensions: InstalledExtensions,
|
|
394
|
+
options?: PortOptions
|
|
395
|
+
): Promise<void> {
|
|
358
396
|
const failed: Port[] = [];
|
|
359
397
|
const loaded: Port[] = [];
|
|
360
398
|
this.loading = true;
|
|
@@ -367,6 +405,20 @@ export class Host extends Emitter<HostEvents> {
|
|
|
367
405
|
this.loading = false;
|
|
368
406
|
this.emit("loadallguests", { host: this, failed, loaded });
|
|
369
407
|
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Unload and remove a specific extension by its ID.
|
|
411
|
+
*/
|
|
412
|
+
async removeGuest(id: string, extension: Extension): Promise<void> {
|
|
413
|
+
const guest = this.guests.get(id);
|
|
414
|
+
if (guest) {
|
|
415
|
+
this.emit("guestbeforeunload", { guest, host: this });
|
|
416
|
+
await guest.unload();
|
|
417
|
+
this.guests.delete(id);
|
|
418
|
+
this.emit("guestunload", { guest, host: this });
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
370
422
|
/**
|
|
371
423
|
* Unload all extensions and remove their frames/workers. Use this to unmount
|
|
372
424
|
* a UI or when switching to a different extensible UI.
|
|
@@ -378,6 +430,7 @@ export class Host extends Emitter<HostEvents> {
|
|
|
378
430
|
this.runtimeContainer.parentElement.removeChild(this.runtimeContainer);
|
|
379
431
|
this.emit("unload", { host: this });
|
|
380
432
|
}
|
|
433
|
+
|
|
381
434
|
private createRuntimeContainer(window: Window) {
|
|
382
435
|
const { document } = window;
|
|
383
436
|
const container = document.createElement("div");
|
package/src/port.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
} from "@adobe/uix-core";
|
|
25
25
|
import { Emitter, connectIframe } from "@adobe/uix-core";
|
|
26
26
|
import { normalizeIframe } from "./dom-utils";
|
|
27
|
+
import { compareVersions } from "./utils/comparePackagesVersions";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* A specifier for methods to be expected on a remote interface.
|
|
@@ -185,6 +186,9 @@ export class Port<GuestApi = unknown>
|
|
|
185
186
|
private guestServerFrame: HTMLIFrameElement;
|
|
186
187
|
private hostApis: VirtualApi = {};
|
|
187
188
|
private isLoaded = false;
|
|
189
|
+
private isGuestReady = false;
|
|
190
|
+
private guestReadyMessageHandler: ((event: MessageEvent) => void) | null =
|
|
191
|
+
null;
|
|
188
192
|
private runtimeContainer: HTMLElement;
|
|
189
193
|
private sharedContext: Record<string, unknown>;
|
|
190
194
|
private configuration?: Record<string, unknown>;
|
|
@@ -206,6 +210,7 @@ export class Port<GuestApi = unknown>
|
|
|
206
210
|
public url: URL;
|
|
207
211
|
public extensionPoints: string[];
|
|
208
212
|
private guestServer: CrossRealmObject<GuestProxyWrapper>;
|
|
213
|
+
private guestVersion: string | undefined;
|
|
209
214
|
|
|
210
215
|
// #endregion Properties (13)
|
|
211
216
|
|
|
@@ -302,10 +307,17 @@ export class Port<GuestApi = unknown>
|
|
|
302
307
|
}
|
|
303
308
|
|
|
304
309
|
/**
|
|
305
|
-
* True when
|
|
310
|
+
* True when all extensions have loaded.
|
|
306
311
|
*/
|
|
307
312
|
public isReady(): boolean {
|
|
308
|
-
|
|
313
|
+
if (this.guestVersion && this.guestVersion.length > 0) {
|
|
314
|
+
if (compareVersions(this.guestVersion, "1.1.3") >= 0) {
|
|
315
|
+
return this.isLoaded && !this.error && this.isGuestReady;
|
|
316
|
+
} else {
|
|
317
|
+
return this.isLoaded && !this.error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
309
321
|
}
|
|
310
322
|
|
|
311
323
|
/**
|
|
@@ -341,10 +353,25 @@ export class Port<GuestApi = unknown>
|
|
|
341
353
|
* Disconnect from the extension.
|
|
342
354
|
*/
|
|
343
355
|
public async unload(): Promise<void> {
|
|
356
|
+
// Clean up guest ready message handler if it exists
|
|
357
|
+
if (this.guestReadyMessageHandler) {
|
|
358
|
+
window.removeEventListener("message", this.guestReadyMessageHandler);
|
|
359
|
+
this.guestReadyMessageHandler = null;
|
|
360
|
+
this.isGuestReady = false;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
for (const unsubscribe of this.subscriptions) {
|
|
364
|
+
if (typeof unsubscribe === "function") {
|
|
365
|
+
unsubscribe();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
this.subscriptions = [];
|
|
369
|
+
|
|
344
370
|
if (this.guestServerFrame && this.guestServerFrame.parentElement) {
|
|
345
371
|
this.guestServerFrame.parentElement.removeChild(this.guestServerFrame);
|
|
346
372
|
this.guestServerFrame = undefined;
|
|
347
373
|
}
|
|
374
|
+
|
|
348
375
|
this.emit("unload", { guestPort: this });
|
|
349
376
|
}
|
|
350
377
|
|
|
@@ -419,7 +446,6 @@ export class Port<GuestApi = unknown>
|
|
|
419
446
|
) {
|
|
420
447
|
// at least this is necessary
|
|
421
448
|
normalizeIframe(iframe);
|
|
422
|
-
this.logger.log("attachFrame", iframe);
|
|
423
449
|
return connectIframe<T>(
|
|
424
450
|
iframe,
|
|
425
451
|
{
|
|
@@ -428,16 +454,24 @@ export class Port<GuestApi = unknown>
|
|
|
428
454
|
timeout: this.timeout,
|
|
429
455
|
},
|
|
430
456
|
{
|
|
431
|
-
getSharedContext: () =>
|
|
432
|
-
|
|
457
|
+
getSharedContext: () => {
|
|
458
|
+
return this.sharedContext;
|
|
459
|
+
},
|
|
460
|
+
getConfiguration: () => {
|
|
461
|
+
return this.configuration;
|
|
462
|
+
},
|
|
433
463
|
invokeHostMethod: (address: HostMethodAddress) =>
|
|
434
464
|
this.invokeHostMethod(address, addedMethods as VirtualApi),
|
|
435
465
|
...addedMethods,
|
|
466
|
+
},
|
|
467
|
+
(version: string) => {
|
|
468
|
+
this.guestVersion = version;
|
|
436
469
|
}
|
|
437
470
|
);
|
|
438
471
|
}
|
|
439
472
|
|
|
440
473
|
private async connect() {
|
|
474
|
+
let timeoutId: ReturnType<typeof setTimeout>;
|
|
441
475
|
const serverFrame =
|
|
442
476
|
this.runtimeContainer.ownerDocument.createElement("iframe");
|
|
443
477
|
normalizeIframe(serverFrame);
|
|
@@ -451,11 +485,48 @@ export class Port<GuestApi = unknown>
|
|
|
451
485
|
this
|
|
452
486
|
);
|
|
453
487
|
}
|
|
454
|
-
|
|
488
|
+
try {
|
|
489
|
+
this.guestServer = await this.attachFrame<GuestProxyWrapper>(serverFrame);
|
|
490
|
+
} catch (error) {
|
|
491
|
+
this.logger?.error(
|
|
492
|
+
`Failed to attach guest server for ${this.id}:`,
|
|
493
|
+
error
|
|
494
|
+
);
|
|
495
|
+
clearTimeout(timeoutId);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const handleMessage = (event: MessageEvent) => {
|
|
499
|
+
// Check if this is a guest-ready message from our specific iframe
|
|
500
|
+
if (
|
|
501
|
+
event.data &&
|
|
502
|
+
event.data.type === "guest-ready" &&
|
|
503
|
+
event.source === serverFrame.contentWindow
|
|
504
|
+
) {
|
|
505
|
+
this.logger?.log(
|
|
506
|
+
`[Port ${this.id}] Received guest-ready from our iframe (guest: ${
|
|
507
|
+
event.data.guestId || "unknown"
|
|
508
|
+
})`
|
|
509
|
+
);
|
|
510
|
+
this.isGuestReady = true;
|
|
511
|
+
if (this.logger) {
|
|
512
|
+
this.logger.info(`Guest ${this.id} reported ready status`);
|
|
513
|
+
}
|
|
514
|
+
this.emit("guestready", { guestPort: this });
|
|
515
|
+
|
|
516
|
+
// Clean up listener and resolve
|
|
517
|
+
window.removeEventListener("message", handleMessage);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
window.addEventListener("message", handleMessage);
|
|
522
|
+
|
|
523
|
+
// Store cleanup function
|
|
524
|
+
this.guestReadyMessageHandler = handleMessage;
|
|
525
|
+
|
|
455
526
|
this.isLoaded = true;
|
|
456
527
|
if (this.logger) {
|
|
457
528
|
this.logger.info(
|
|
458
|
-
`Guest ${this.id} established connection, received methods`,
|
|
529
|
+
`Guest ${this.id} established connection, received methods, and reported ready`,
|
|
459
530
|
this.apis,
|
|
460
531
|
this
|
|
461
532
|
);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Extension } from "@adobe/uix-core";
|
|
14
|
+
import { InstalledExtensions } from "../host";
|
|
15
|
+
|
|
16
|
+
export interface ExtensionsDifference {
|
|
17
|
+
added: Record<string, Extension["url"] | Extension>;
|
|
18
|
+
removed: Record<string, Extension["url"] | Extension>;
|
|
19
|
+
modified: Record<
|
|
20
|
+
string,
|
|
21
|
+
{
|
|
22
|
+
old: Extension["url"] | Extension;
|
|
23
|
+
new: Extension["url"] | Extension;
|
|
24
|
+
}
|
|
25
|
+
>;
|
|
26
|
+
hasChanges: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function compareExtensions(
|
|
30
|
+
extensions1: InstalledExtensions,
|
|
31
|
+
extensions2: InstalledExtensions
|
|
32
|
+
): ExtensionsDifference {
|
|
33
|
+
const result: ExtensionsDifference = {
|
|
34
|
+
added: {},
|
|
35
|
+
removed: {},
|
|
36
|
+
modified: {},
|
|
37
|
+
hasChanges: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const keys1 = new Set(Object.keys(extensions1));
|
|
41
|
+
const keys2 = new Set(Object.keys(extensions2));
|
|
42
|
+
const allKeys = new Set([...keys1, ...keys2]);
|
|
43
|
+
|
|
44
|
+
for (const key of allKeys) {
|
|
45
|
+
const exists1 = keys1.has(key);
|
|
46
|
+
const exists2 = keys2.has(key);
|
|
47
|
+
|
|
48
|
+
if (!exists1 && exists2) {
|
|
49
|
+
result.added[key] = extensions2[key];
|
|
50
|
+
result.hasChanges = true;
|
|
51
|
+
} else if (exists1 && !exists2) {
|
|
52
|
+
result.removed[key] = extensions1[key];
|
|
53
|
+
result.hasChanges = true;
|
|
54
|
+
} else if (exists1 && exists2) {
|
|
55
|
+
const ext1 = extensions1[key];
|
|
56
|
+
const ext2 = extensions2[key];
|
|
57
|
+
|
|
58
|
+
if (!areExtensionsEqual(ext1, ext2)) {
|
|
59
|
+
result.modified[key] = {
|
|
60
|
+
old: ext1,
|
|
61
|
+
new: ext2,
|
|
62
|
+
};
|
|
63
|
+
result.hasChanges = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function areExtensionsEqual(
|
|
72
|
+
ext1: Extension["url"] | Extension,
|
|
73
|
+
ext2: Extension["url"] | Extension
|
|
74
|
+
): boolean {
|
|
75
|
+
if (typeof ext1 !== typeof ext2) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (typeof ext1 === "string" && typeof ext2 === "string") {
|
|
80
|
+
return ext1 === ext2;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof ext1 === "object" && typeof ext2 === "object") {
|
|
84
|
+
if (ext1.id !== ext2.id || ext1.url !== ext2.url) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const ep1 = ext1.extensionPoints || [];
|
|
89
|
+
const ep2 = ext2.extensionPoints || [];
|
|
90
|
+
|
|
91
|
+
if (ep1.length !== ep2.length) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const sortedEp1 = [...ep1].sort();
|
|
96
|
+
const sortedEp2 = [...ep2].sort();
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < sortedEp1.length; i++) {
|
|
99
|
+
if (sortedEp1[i] !== sortedEp2[i]) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return deepEqual(ext1.configuration, ext2.configuration);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function deepEqual(obj1: unknown, obj2: unknown): boolean {
|
|
111
|
+
if (obj1 === obj2) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (obj1 == null || obj2 == null) {
|
|
116
|
+
return obj1 === obj2;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object") {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const keys1 = Object.keys(obj1 as Record<string, unknown>);
|
|
124
|
+
const keys2 = Object.keys(obj2 as Record<string, unknown>);
|
|
125
|
+
|
|
126
|
+
if (keys1.length !== keys2.length) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (const key of keys1) {
|
|
131
|
+
if (!keys2.includes(key)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (
|
|
136
|
+
!deepEqual(
|
|
137
|
+
(obj1 as Record<string, unknown>)[key],
|
|
138
|
+
(obj2 as Record<string, unknown>)[key]
|
|
139
|
+
)
|
|
140
|
+
) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function areExtensionsDifferent(
|
|
149
|
+
extensions1: InstalledExtensions,
|
|
150
|
+
extensions2: InstalledExtensions
|
|
151
|
+
): boolean {
|
|
152
|
+
return compareExtensions(extensions1, extensions2).hasChanges;
|
|
153
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function compareVersions(v1: string, v2: string): number {
|
|
2
|
+
const versionToArray = (v: string) => v.split(".").map((x) => Number(x) || 0);
|
|
3
|
+
const v1Array = versionToArray(v1);
|
|
4
|
+
const v2Array = versionToArray(v2);
|
|
5
|
+
const len = Math.max(v1Array.length, v2Array.length);
|
|
6
|
+
for (let i = 0; i < len; i++) {
|
|
7
|
+
const n1 = v1Array[i] ?? 0;
|
|
8
|
+
const n2 = v2Array[i] ?? 0;
|
|
9
|
+
if (n1 > n2) return 1;
|
|
10
|
+
if (n1 < n2) return -1;
|
|
11
|
+
}
|
|
12
|
+
return 0;
|
|
13
|
+
}
|