@adobe/uix-host 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +1 -0
- package/dist/debug-host.d.ts +8 -0
- package/dist/debug-host.d.ts.map +1 -0
- package/dist/esm/index.js +408 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/extensions-provider/composition.d.ts +9 -0
- package/dist/extensions-provider/composition.d.ts.map +1 -0
- package/dist/extensions-provider/extension-registry.d.ts +29 -0
- package/dist/extensions-provider/extension-registry.d.ts.map +1 -0
- package/dist/extensions-provider/index.d.ts +3 -0
- package/dist/extensions-provider/index.d.ts.map +1 -0
- package/dist/host.d.ts +247 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +1 -0
- package/dist/port.d.ts +173 -0
- package/dist/port.d.ts.map +1 -0
- package/package.json +39 -0
- package/src/debug-host.ts +79 -0
- package/src/extensions-provider/composition.ts +30 -0
- package/src/extensions-provider/extension-registry.ts +152 -0
- package/src/extensions-provider/index.ts +14 -0
- package/src/host.ts +429 -0
- package/src/index.ts +76 -0
- package/src/port.ts +430 -0
- package/tsconfig.json +19 -0
package/src/host.ts
ADDED
@@ -0,0 +1,429 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2022 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 type {
|
14
|
+
Extension,
|
15
|
+
GuestConnection,
|
16
|
+
NamedEvent,
|
17
|
+
Emits,
|
18
|
+
GuestApis,
|
19
|
+
} from "@adobe/uix-core";
|
20
|
+
import type { CapabilitySpec } from "./port.js";
|
21
|
+
import { Emitter, quietConsole } from "@adobe/uix-core";
|
22
|
+
import { Port, PortOptions } from "./port.js";
|
23
|
+
import { debugHost } from "./debug-host.js";
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Dictionary of {@link Port} objects by extension ID.
|
27
|
+
* @public
|
28
|
+
*/
|
29
|
+
export type PortMap = Map<string, GuestConnection>;
|
30
|
+
|
31
|
+
/** @public */
|
32
|
+
export type HostEvent<
|
33
|
+
Type extends string = string,
|
34
|
+
Detail = Record<string, unknown>
|
35
|
+
> = NamedEvent<Type, Detail & Record<string, unknown> & { host: Host }>;
|
36
|
+
/** @public */
|
37
|
+
type HostGuestEvent<Type extends string> = HostEvent<
|
38
|
+
`guest${Type}`,
|
39
|
+
{ guest: GuestConnection }
|
40
|
+
>;
|
41
|
+
|
42
|
+
/**
|
43
|
+
* All guests requested by host have been loaded and connected.
|
44
|
+
* @public
|
45
|
+
*/
|
46
|
+
export type HostEventLoadAllGuests = HostEvent<
|
47
|
+
"loadallguests",
|
48
|
+
{ failed: GuestConnection[]; loaded: GuestConnection[] }
|
49
|
+
>;
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Shared context has been set or updated; all guests receive this event too.
|
53
|
+
* @public
|
54
|
+
*/
|
55
|
+
|
56
|
+
export type HostEventContextChange = HostEvent<
|
57
|
+
"contextchange",
|
58
|
+
{ context: SharedContextValues }
|
59
|
+
>;
|
60
|
+
|
61
|
+
/**
|
62
|
+
* An error has occurred during loading or unloading of guests.
|
63
|
+
* @public
|
64
|
+
*/
|
65
|
+
export type HostEventError = HostEvent<"error", { error: Error }>;
|
66
|
+
|
67
|
+
/** @public */
|
68
|
+
export type HostEvents =
|
69
|
+
| HostGuestEvent<"beforeload">
|
70
|
+
| HostGuestEvent<"load">
|
71
|
+
| HostEvent<"beforeunload">
|
72
|
+
| HostEvent<"unload">
|
73
|
+
| HostEventLoadAllGuests
|
74
|
+
| HostEventContextChange
|
75
|
+
| HostEventError;
|
76
|
+
|
77
|
+
/** @public */
|
78
|
+
export type InstalledExtensions = Record<Extension["id"], Extension["url"]>;
|
79
|
+
/** @public */
|
80
|
+
export type ExtensionsProvider = () => Promise<InstalledExtensions>;
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Values for shared context. Must be a plain object, serializable to JSON.
|
84
|
+
* @public
|
85
|
+
*/
|
86
|
+
export type SharedContextValues = Record<string, unknown>;
|
87
|
+
|
88
|
+
/** @public */
|
89
|
+
export interface HostConfig {
|
90
|
+
/**
|
91
|
+
* Human-readable "slug" name of the extensible area--often an entire app.
|
92
|
+
* This string serves as a namespace for extension points within the area.
|
93
|
+
*/
|
94
|
+
hostName: string;
|
95
|
+
/**
|
96
|
+
* A DOM element _outside_ of the React root. This is necessary to preserve
|
97
|
+
* the lifetime of the iframes which are running extension objects; if they
|
98
|
+
* live inside the React root, then React could unexpectedly re-render the
|
99
|
+
* iframe tags themselves at any time, causing a reload of the frame.
|
100
|
+
*/
|
101
|
+
runtimeContainer?: HTMLElement;
|
102
|
+
/**
|
103
|
+
* Copiously log lifecycle events.
|
104
|
+
*/
|
105
|
+
debug?: boolean;
|
106
|
+
/**
|
107
|
+
* Default options to use for every guest Port.
|
108
|
+
*
|
109
|
+
* If `config.debug` is true, then the guest options will have `debug: true`
|
110
|
+
* unless `debug: false` is explicitly passed in `guestOptions`.
|
111
|
+
*/
|
112
|
+
guestOptions?: PortOptions;
|
113
|
+
/**
|
114
|
+
* A read-only dictionary of values that the host will supply to all the
|
115
|
+
* guests.
|
116
|
+
*/
|
117
|
+
sharedContext?: SharedContextValues;
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Callback to use to filter the list returned from {@link Host.(getLoadedGuests:2)}
|
122
|
+
* @public
|
123
|
+
*/
|
124
|
+
type GuestFilter = (item: GuestConnection) => boolean;
|
125
|
+
|
126
|
+
const passAllGuests = () => true;
|
127
|
+
|
128
|
+
/**
|
129
|
+
* Manager object for connecting to {@link @adobe/uix-guest#GuestServer |
|
130
|
+
* GuestServers} and {@link @adobe/uix-guest#GuestUI | GuestUIs}, providing and
|
131
|
+
* receiving their APIs, and providing them to the app for interacting with UI.
|
132
|
+
*
|
133
|
+
* @remarks
|
134
|
+
* The Host object is the main connection manager for all UIX Guests.
|
135
|
+
* Making an app extensible requires creating a Host object.
|
136
|
+
*
|
137
|
+
* The extensible app using the Hostis responsible for providing a list of
|
138
|
+
* extension references to the Host object. Use {@link
|
139
|
+
* createExtensionRegistryProvider} for that purpose. Once you have retrieved a
|
140
|
+
* list of extensions available to the host app, pass it to {@link Host.load}.
|
141
|
+
*
|
142
|
+
* When a Host creates a Guest, it must create an `<iframe>` element to contain
|
143
|
+
* the Guest's main {@link @adobe/uix-guest#GuestServer} runtime, which runs
|
144
|
+
* invisibly in the background. To do this, the Host creates a hidden container
|
145
|
+
* in the body of the document. It is a `<div>` element with the attribute
|
146
|
+
* `data-uix-guest-container`. Loaded GuestServers will be injected into this
|
147
|
+
* hidden element and removed as necessary. When {@link Host.unload} is called,
|
148
|
+
* the Host removes the hidden container from the document after unloading.
|
149
|
+
*
|
150
|
+
* @public
|
151
|
+
*/
|
152
|
+
export class Host extends Emitter<HostEvents> {
|
153
|
+
/**
|
154
|
+
* {@inheritDoc HostEventLoadAllGuests}
|
155
|
+
* @eventProperty
|
156
|
+
*/
|
157
|
+
public loadallguests: HostEventLoadAllGuests;
|
158
|
+
|
159
|
+
/**
|
160
|
+
* One guest has loaded.
|
161
|
+
* @eventProperty
|
162
|
+
*/
|
163
|
+
public guestload: HostGuestEvent<"load">;
|
164
|
+
|
165
|
+
/**
|
166
|
+
* About to attempt to load and connect to a Guest.
|
167
|
+
* @eventProperty
|
168
|
+
*/
|
169
|
+
public guestbeforeload: HostGuestEvent<"beforeload">;
|
170
|
+
|
171
|
+
/**
|
172
|
+
* About to unload a guest and remove its {@link @adobe/uix-guest#GuestServer}
|
173
|
+
* instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.
|
174
|
+
* @eventProperty
|
175
|
+
*/
|
176
|
+
public guestbeforeunload: HostGuestEvent<"beforeunload">;
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Unloaded a guest and removed its {@link @adobe/uix-guest#GuestServer}
|
180
|
+
* instance as well as all its {@link @adobe/uix-guest#GuestUI} instances.
|
181
|
+
* @eventProperty
|
182
|
+
*/
|
183
|
+
public guestunload: HostGuestEvent<"unload">;
|
184
|
+
|
185
|
+
/**
|
186
|
+
* {@inheritDoc HostEventContextChange}
|
187
|
+
* @eventProperty
|
188
|
+
*/
|
189
|
+
public contextchange: HostEventContextChange;
|
190
|
+
|
191
|
+
/**
|
192
|
+
* {@inheritDoc HostEventError}
|
193
|
+
* @eventProperty
|
194
|
+
*/
|
195
|
+
public error: HostEventError;
|
196
|
+
|
197
|
+
private static containerStyle = {
|
198
|
+
position: "fixed",
|
199
|
+
width: "1px",
|
200
|
+
height: "1px",
|
201
|
+
pointerEvents: "none",
|
202
|
+
opacity: 0,
|
203
|
+
top: 0,
|
204
|
+
left: "-1px",
|
205
|
+
};
|
206
|
+
/**
|
207
|
+
* Unique string identifying the Host object.
|
208
|
+
*/
|
209
|
+
hostName: string;
|
210
|
+
/**
|
211
|
+
* `true` if any extension in {@link Host.guests} has created a {@link
|
212
|
+
* @adobe/uix-guest#GuestServer}, but the Guest has not yet loaded.
|
213
|
+
*/
|
214
|
+
loading = false;
|
215
|
+
/**
|
216
|
+
* A Map of of the loaded guests.
|
217
|
+
*/
|
218
|
+
guests: PortMap = new Map();
|
219
|
+
private cachedCapabilityLists: WeakMap<object, GuestConnection[]> =
|
220
|
+
new WeakMap();
|
221
|
+
private runtimeContainer: HTMLElement;
|
222
|
+
private guestOptions: PortOptions;
|
223
|
+
private debugLogger: Console = quietConsole;
|
224
|
+
private sharedContext: SharedContextValues;
|
225
|
+
constructor(config: HostConfig) {
|
226
|
+
super(config.hostName);
|
227
|
+
const { guestOptions = {} } = config;
|
228
|
+
this.guestOptions = {
|
229
|
+
...guestOptions,
|
230
|
+
debug: guestOptions.debug === false ? false : !!config.debug,
|
231
|
+
};
|
232
|
+
this.hostName = config.hostName;
|
233
|
+
this.sharedContext = config.sharedContext || {};
|
234
|
+
this.runtimeContainer = config.runtimeContainer;
|
235
|
+
if (config.debug) {
|
236
|
+
this.debugLogger = debugHost(this);
|
237
|
+
}
|
238
|
+
}
|
239
|
+
/**
|
240
|
+
* Return all loaded guests.
|
241
|
+
*/
|
242
|
+
getLoadedGuests(): GuestConnection[];
|
243
|
+
/**
|
244
|
+
* Return loaded guests which satisfy the passed test function.
|
245
|
+
*/
|
246
|
+
getLoadedGuests(filter: GuestFilter): GuestConnection[];
|
247
|
+
/**
|
248
|
+
* Return loaded guests which expose the provided {@link CapabilitySpec}.
|
249
|
+
*/
|
250
|
+
getLoadedGuests<Apis extends GuestApis>(
|
251
|
+
capabilities: CapabilitySpec<Apis>
|
252
|
+
): GuestConnection[];
|
253
|
+
getLoadedGuests<Apis extends GuestApis = never>(
|
254
|
+
filterOrCapabilities?: CapabilitySpec<Apis> | GuestFilter
|
255
|
+
): GuestConnection[] {
|
256
|
+
if (typeof filterOrCapabilities === "object") {
|
257
|
+
return this.getLoadedGuestsWith<Apis>(filterOrCapabilities);
|
258
|
+
}
|
259
|
+
const filter = filterOrCapabilities || passAllGuests;
|
260
|
+
const result = [];
|
261
|
+
for (const guest of this.guests.values()) {
|
262
|
+
if (guest.isReady() && filter(guest)) {
|
263
|
+
result.push(guest);
|
264
|
+
}
|
265
|
+
}
|
266
|
+
return result;
|
267
|
+
}
|
268
|
+
/**
|
269
|
+
* Set the object of shared values that all Guests can access via {@link @adobe/uix-guest#GuestServer.sharedContext}.
|
270
|
+
* This overwrites any previous object.
|
271
|
+
*
|
272
|
+
* @example Exposes `authToken` to all Guests. Guests can call `this.sharedContext.get('authToken')` to retrieve this value.
|
273
|
+
* ```javascript
|
274
|
+
* host.shareContext({
|
275
|
+
* authToken: '82ba19b'
|
276
|
+
* });
|
277
|
+
* ```
|
278
|
+
*
|
279
|
+
* @example Overwrites the previous sharedContext, deleting `authToken` and providing `secret` and `auth` instead.
|
280
|
+
* ```javascript
|
281
|
+
* host.shareContext({
|
282
|
+
* secret: 'squirrel',
|
283
|
+
* auth: false
|
284
|
+
* });
|
285
|
+
* ```
|
286
|
+
*/
|
287
|
+
shareContext(context: SharedContextValues): void;
|
288
|
+
/**
|
289
|
+
* Update the object of shared values that all Guests can access via {@link
|
290
|
+
* @adobe/uix-guest#GuestServer.sharedContext}. This method takes a callback
|
291
|
+
* which receives the previous context and may return an entirely new context,
|
292
|
+
* or new values merged with the old context.
|
293
|
+
*
|
294
|
+
* @remarks This callback pattern allows the shared context values to be
|
295
|
+
* mutable while the internal context object references are immutable, which
|
296
|
+
* is important for synchronizing. with guests.
|
297
|
+
*
|
298
|
+
* @example Overwrites a context object based on the previous one.
|
299
|
+
* ```javascript
|
300
|
+
* host.shareContext(oldContext => ({
|
301
|
+
* counter: oldContext.counter + 1
|
302
|
+
* }))
|
303
|
+
* ```
|
304
|
+
*
|
305
|
+
* @example Updates a context while preserving other existing values.
|
306
|
+
* ```javascript
|
307
|
+
* host.shareContext(oldContext => ({
|
308
|
+
* ...oldContext,
|
309
|
+
* counter: oldContext.counter + 1
|
310
|
+
* }))
|
311
|
+
* ```
|
312
|
+
*/
|
313
|
+
shareContext(
|
314
|
+
setter: (context: SharedContextValues) => SharedContextValues
|
315
|
+
): void;
|
316
|
+
shareContext(
|
317
|
+
setter: (context: SharedContextValues) => SharedContextValues
|
318
|
+
): void;
|
319
|
+
shareContext(
|
320
|
+
setterOrContext:
|
321
|
+
| ((context: SharedContextValues) => SharedContextValues)
|
322
|
+
| SharedContextValues
|
323
|
+
) {
|
324
|
+
if (typeof setterOrContext === "function") {
|
325
|
+
this.sharedContext = setterOrContext(this.sharedContext);
|
326
|
+
} else {
|
327
|
+
this.sharedContext = setterOrContext;
|
328
|
+
}
|
329
|
+
this.emit("contextchange", {
|
330
|
+
host: this,
|
331
|
+
context: this.sharedContext,
|
332
|
+
});
|
333
|
+
}
|
334
|
+
/**
|
335
|
+
* Load extension into host application from provided extension description.
|
336
|
+
* Returned promise resolves when all extensions are loaded and registered.
|
337
|
+
*
|
338
|
+
* @param extensions - List of extension descriptors. Normally, the Host should receive this value from an {@link ExtensionsProvider}.
|
339
|
+
* @param options - Custom options to be used as defaults for each {@link Port} object created for each guest.
|
340
|
+
* @returns Promise which resolves when all guests have been loaded.
|
341
|
+
*/
|
342
|
+
async load(
|
343
|
+
extensions: InstalledExtensions,
|
344
|
+
options?: PortOptions
|
345
|
+
): Promise<void> {
|
346
|
+
this.runtimeContainer =
|
347
|
+
this.runtimeContainer || this.createRuntimeContainer(window);
|
348
|
+
const failed: GuestConnection[] = [];
|
349
|
+
const loaded: GuestConnection[] = [];
|
350
|
+
this.loading = true;
|
351
|
+
await Promise.all(
|
352
|
+
Object.entries(extensions).map(async ([id, url]) => {
|
353
|
+
const port = await this.loadOneGuest(id, url, options);
|
354
|
+
(port.error ? failed : loaded).push(port);
|
355
|
+
})
|
356
|
+
);
|
357
|
+
this.loading = false;
|
358
|
+
this.emit("loadallguests", { host: this, failed, loaded });
|
359
|
+
}
|
360
|
+
/**
|
361
|
+
* Unload all extensions and remove their frames/workers. Use this to unmount
|
362
|
+
* a UI or when switching to a different extensible UI.
|
363
|
+
*/
|
364
|
+
async unload(): Promise<void> {
|
365
|
+
this.emit("beforeunload", { host: this });
|
366
|
+
await Promise.all([...this.guests.values()].map((guest) => guest.unload()));
|
367
|
+
this.guests.clear();
|
368
|
+
this.runtimeContainer.parentElement.removeChild(this.runtimeContainer);
|
369
|
+
this.emit("unload", { host: this });
|
370
|
+
}
|
371
|
+
private createRuntimeContainer(window: Window) {
|
372
|
+
const { document } = window;
|
373
|
+
const container = document.createElement("div");
|
374
|
+
container.setAttribute("data-uix-guest-container", this.hostName);
|
375
|
+
Object.assign(container.style, Host.containerStyle);
|
376
|
+
document.body.appendChild(container);
|
377
|
+
return container;
|
378
|
+
}
|
379
|
+
private async loadOneGuest(
|
380
|
+
id: string,
|
381
|
+
urlString: string,
|
382
|
+
options: PortOptions = {}
|
383
|
+
): Promise<GuestConnection> {
|
384
|
+
let guest = this.guests.get(id);
|
385
|
+
if (!guest) {
|
386
|
+
const url = new URL(urlString);
|
387
|
+
guest = new Port({
|
388
|
+
owner: this.hostName,
|
389
|
+
id,
|
390
|
+
url,
|
391
|
+
runtimeContainer: this.runtimeContainer,
|
392
|
+
options: {
|
393
|
+
...this.guestOptions,
|
394
|
+
...options,
|
395
|
+
},
|
396
|
+
debugLogger: this.debugLogger,
|
397
|
+
sharedContext: this.sharedContext,
|
398
|
+
events: this as Emits,
|
399
|
+
});
|
400
|
+
this.guests.set(id, guest);
|
401
|
+
}
|
402
|
+
this.emit("guestbeforeload", { guest, host: this });
|
403
|
+
try {
|
404
|
+
await guest.load();
|
405
|
+
} catch (e: unknown) {
|
406
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
407
|
+
this.emit("error", { host: this, guest, error });
|
408
|
+
console.warn("Failed to load extension at endpoint %s", guest.url);
|
409
|
+
return guest;
|
410
|
+
}
|
411
|
+
// this new guest might have new capabilities, so the identities of the
|
412
|
+
// cached capability sets will need to change, to alert subscribers
|
413
|
+
this.cachedCapabilityLists = new WeakMap();
|
414
|
+
this.emit("guestload", { guest, host: this });
|
415
|
+
return guest;
|
416
|
+
}
|
417
|
+
private getLoadedGuestsWith<Apis extends GuestApis>(
|
418
|
+
capabilities: CapabilitySpec<Apis>
|
419
|
+
) {
|
420
|
+
if (this.cachedCapabilityLists.has(capabilities)) {
|
421
|
+
return this.cachedCapabilityLists.get(capabilities);
|
422
|
+
}
|
423
|
+
const guestsWithCapabilities = this.getLoadedGuests((guest) =>
|
424
|
+
guest.hasCapabilities(capabilities)
|
425
|
+
);
|
426
|
+
this.cachedCapabilityLists.set(capabilities, guestsWithCapabilities);
|
427
|
+
return guestsWithCapabilities;
|
428
|
+
}
|
429
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2022 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
|
+
/**
|
14
|
+
* @packageDocumentation
|
15
|
+
* Tools for a web app to become a UI Extensibility Host. Use this library to
|
16
|
+
* create a {@link Host} object, which is your interface to declare extension
|
17
|
+
* points, instantiate {@link @adobe/uix-guest#GuestServer} objects, connect to
|
18
|
+
* them and communicate with them.
|
19
|
+
*
|
20
|
+
* @remarks
|
21
|
+
* A Host is an EventEmitter with a simple query interface. Provide it with a
|
22
|
+
* list of extensions from a registry (it will not fetch one itself) and it will
|
23
|
+
* load them, receive their registration calls, and make them available for
|
24
|
+
* retrieval and use by the extensible app.
|
25
|
+
*
|
26
|
+
* The Host objects are low-level objects; they are unopinionated with
|
27
|
+
* regards to event and lifecycle handling. For use in structured UI frameworks,
|
28
|
+
* it will be best to use binding libraries which use these underlying objects.
|
29
|
+
*
|
30
|
+
* @example
|
31
|
+
* Instantiate a Host and feed it some extensions, watching as each loads.
|
32
|
+
* ```javascript
|
33
|
+
* import { Host } from `@adobe/uix-host`
|
34
|
+
*
|
35
|
+
* const host = new Host({ hostName: 'example' });
|
36
|
+
*
|
37
|
+
* const extensions = await fetch(EXTENSION_REGISTRY).then(res => res.json());
|
38
|
+
*
|
39
|
+
* host.addEventListener('loadallguests', event => {
|
40
|
+
* const { failed, loaded } = event.detail;
|
41
|
+
* failed.forEach(error => console.error('Extension load failed!', error));
|
42
|
+
* loaded.forEach(extension => {
|
43
|
+
* await extension.apis.someNamespace.someMethod();
|
44
|
+
* })
|
45
|
+
* })
|
46
|
+
* ```
|
47
|
+
*
|
48
|
+
* @example
|
49
|
+
* Load only the guests which have registered the namespace 'appliances' and two
|
50
|
+
* specific methods on that namespace.
|
51
|
+
* ```javascript
|
52
|
+
* host.addEventListener('loadallguests', () => {
|
53
|
+
* const applianceGuests = host.getLoadedGuests({
|
54
|
+
* appliances: ['getRefrigeratorContents', 'getOvenTemp']
|
55
|
+
* });
|
56
|
+
* const ingredients = {};
|
57
|
+
* let allOvensOff = true;
|
58
|
+
* await Promise.all(applianceGuests.map(async guest => {
|
59
|
+
* const foods = await guest.apis.appliances.getRefrigeratorContents();
|
60
|
+
* Object.assign(ingredients, foods);
|
61
|
+
* if ((await guest.getOvenTemp()) > 27) {
|
62
|
+
* allOvensOff = alse;
|
63
|
+
* }
|
64
|
+
* }));
|
65
|
+
* })
|
66
|
+
* ```
|
67
|
+
*
|
68
|
+
* A React binding is currently available. See {@link
|
69
|
+
* @adobe/uix-host-react#Extensible}, {@link
|
70
|
+
* @adobe/uix-host-react#useExtensions}, and {@link
|
71
|
+
* @adobe/uix-host-react#GuestUIFrame}.
|
72
|
+
*
|
73
|
+
*/
|
74
|
+
export * from "./host.js";
|
75
|
+
export * from "./port.js";
|
76
|
+
export * from "./extensions-provider/index.js";
|