@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/dist/port.d.ts ADDED
@@ -0,0 +1,173 @@
1
+ import type { Emits, GuestConnection, HostMethodAddress, NamedEvent, RemoteHostApis, GuestApis } from "@adobe/uix-core";
2
+ import { Emitter } from "@adobe/uix-core";
3
+ import { Connection } from "penpal";
4
+ /**
5
+ * A specifier for methods to be expected on a remote interface.
6
+ *
7
+ * @remarks
8
+ * A CapabilitySpec is a description of an interface, like a very simplified
9
+ * type definition. It specifies an object structure and the paths in that
10
+ * structure that must be functions. (It doesn't specify anything about the
11
+ * signatures or return values of those functions.)
12
+ *
13
+ * Use CapabilitySpec objects as queries, or filters, to get a subset of
14
+ * installed extensions which have registered methods which match the spec.
15
+ *
16
+ * @example
17
+ * As an extensible app developer, you are making an extension point for spell
18
+ * check. Your code expects extensions to register an API `spellCheck` with
19
+ * methods called `spellCheck.correct(text)` and `spellCheck.suggest(text)`.
20
+ *
21
+ * ```javascript
22
+ * async function correctText(text) {
23
+ * const spellCheckers = host.getLoadedGuests({
24
+ * spellCheck: [
25
+ * 'correct',
26
+ * 'suggest'
27
+ * ]
28
+ * });
29
+ * let correcting = text;
30
+ * for (const checker of spellCheckers) {
31
+ * correcting = await checker.apis.spellCheck.correct(correcting);
32
+ * }
33
+ * return Promise.all(checkers.map(checker =>
34
+ * checker.apis.spellCheck.suggest(correcting)
35
+ * ));
36
+ * }
37
+ * ```
38
+ *
39
+ * @public
40
+ */
41
+ export declare type CapabilitySpec<T extends GuestApis> = {
42
+ [Name in keyof T]: (keyof T[Name])[];
43
+ };
44
+ /** @public */
45
+ declare type PortEvent<GuestApi, Type extends string = string, Detail = Record<string, unknown>> = NamedEvent<Type, Detail & Record<string, unknown> & {
46
+ guestPort: Port<GuestApi>;
47
+ }>;
48
+ /** @public */
49
+ export declare type PortEvents<GuestApi, HostApi extends Record<string, unknown> = Record<string, unknown>> = PortEvent<GuestApi, "hostprovide"> | PortEvent<GuestApi, "unload"> | PortEvent<GuestApi, "beforecallhostmethod", HostMethodAddress<HostApi>>;
50
+ /** @public */
51
+ export declare type PortOptions = {
52
+ /**
53
+ * Time in milliseconds to wait for the guest to connect before throwing.
54
+ */
55
+ timeout?: number;
56
+ /**
57
+ * Set true to log copiously in the console.
58
+ */
59
+ debug?: boolean;
60
+ };
61
+ /**
62
+ * A Port is the Host-maintained object representing an extension running as a
63
+ * guest. It exposes methods registered by the Guest, and can provide Host
64
+ * methods back to the guest.
65
+ *
66
+ * @remarks
67
+ * When the Host object loads extensions via {@link Host.load}, it creates a
68
+ * Port object for each extension. When retrieving and filtering extensions
69
+ * via {@link Host.(getLoadedGuests:2)}, a list of Port objects is returned. From
70
+ * the point of view of the extensible app using the Host object, extensions
71
+ * are always Port objects, which expose the methods registered by the
72
+ * extension at the {@link Port.apis} property.
73
+ *
74
+ * @privateRemarks
75
+ * We've gone through several possible names for this object. GuestProxy,
76
+ * GuestInterface, GuestConnection, etc. "Port" is not ideal, but it conflicted
77
+ * the least with other types we defined in early drafts. It's definitely
78
+ * something we should review.
79
+ * @public
80
+ */
81
+ export declare class Port<GuestApi> extends Emitter<PortEvents<GuestApi>> implements GuestConnection {
82
+ private connection;
83
+ private debug;
84
+ private debugLogger?;
85
+ private frame;
86
+ private guest;
87
+ private hostApis;
88
+ private isLoaded;
89
+ private runtimeContainer;
90
+ private sharedContext;
91
+ private subscriptions;
92
+ private timeout;
93
+ /**
94
+ * Dictionary of namespaced methods that were registered by this guest at the
95
+ * time of connection, using {@link @adobe/uix-guest#register}.
96
+ *
97
+ * @remarks
98
+ * These methods are proxy methods; you can only pass serializable objects to
99
+ * them, not class instances, methods or callbacks.
100
+ * @public
101
+ */
102
+ apis: RemoteHostApis;
103
+ /**
104
+ * If any errors occurred during the loading of guests, this property will
105
+ * contain the error that was raised.
106
+ * @public
107
+ */
108
+ error?: Error;
109
+ private uiConnections;
110
+ /**
111
+ * The URL of the guest provided by the extension registry. The Host will
112
+ * load this URL in the background, in the invisible the bootstrap frame, so
113
+ * this URL must point to a page that calls {@link @adobe/uix-guest#register}
114
+ * when it loads.
115
+ */
116
+ url: URL;
117
+ constructor(config: {
118
+ owner: string;
119
+ id: string;
120
+ url: URL;
121
+ /**
122
+ * An alternate DOM element to use for invisible iframes. Will create its
123
+ * own if this option is not populated with a DOM element.
124
+ */
125
+ runtimeContainer: HTMLElement;
126
+ options: PortOptions;
127
+ debugLogger?: Console;
128
+ /**
129
+ * Initial object to populate the shared context with. Once the guest
130
+ * connects, it will be able to access these properties.
131
+ */
132
+ sharedContext: Record<string, unknown>;
133
+ events: Emits;
134
+ });
135
+ /**
136
+ * Connect an iframe element which is displaying another page in the extension
137
+ * with the extension's bootstrap frame, so they can share context and events.
138
+ */
139
+ attachUI(iframe: HTMLIFrameElement): Connection<RemoteHostApis<GuestApi>>;
140
+ /**
141
+ * Returns true if the guest has registered methods matching the provided
142
+ * capability spec. A capability spec is simply an object whose properties are
143
+ * declared in an array of keys, description the names of the functions and
144
+ * methods that the Port will expose.
145
+ */
146
+ hasCapabilities(requiredMethods: CapabilitySpec<GuestApis>): boolean;
147
+ /**
148
+ * True when al extensions have loaded.
149
+ */
150
+ isReady(): boolean;
151
+ /**
152
+ * Loads the extension. Returns a promise which resolves when the extension
153
+ * has loaded. The Host calls this method after retrieving extensions.
154
+ */
155
+ load(): Promise<RemoteHostApis<import("@adobe/uix-core").VirtualApi>>;
156
+ /**
157
+ * The host-side equivalent of {@link @adobe/uix-guest#register}. Pass a set
158
+ * of methods down to the guest as proxies.
159
+ */
160
+ provide(apis: RemoteHostApis): void;
161
+ /**
162
+ * Disconnect from the extension.
163
+ */
164
+ unload(): Promise<void>;
165
+ private assert;
166
+ private assertReady;
167
+ private attachFrame;
168
+ private connect;
169
+ private getHostMethodCallee;
170
+ private invokeHostMethod;
171
+ }
172
+ export {};
173
+ //# sourceMappingURL=port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@adobe/uix-host",
3
+ "version": "0.6.3",
4
+ "description": "Tools for embedding UIX Extensions into Adobe apps",
5
+ "author": "Adobe, Inc,",
6
+ "type": "module",
7
+ "module": "dist/esm/index.js",
8
+ "main": "dist/index.js",
9
+ "exports": {
10
+ "import": "./dist/esm/index.js",
11
+ "require": "./dist/index.js"
12
+ },
13
+ "types": "dist/index.d.ts",
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "watch": "tsup --watch --silent"
17
+ },
18
+ "browserslist": [
19
+ "> 0.2%, last 2 versions, not dead"
20
+ ],
21
+ "bugs": "https://git.corp.adobe.com/dx-devex-acceleration/uix-sdk/issues",
22
+ "dependencies": {
23
+ "@adobe/uix-core": "^0.6.3",
24
+ "penpal": "~6.2.2"
25
+ },
26
+ "files": [
27
+ "README.md",
28
+ "dist",
29
+ "src",
30
+ "tsconfig.json"
31
+ ],
32
+ "homepage": "https://git.corp.adobe.com/dx-devex-acceleration/uix-sdk",
33
+ "license": "Apache-2.0",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://git.corp.adobe.com/dx-devex-acceleration/uix-sdk.git"
37
+ },
38
+ "sideEffects": false
39
+ }
@@ -0,0 +1,79 @@
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
+ /* eslint-disable @typescript-eslint/restrict-template-expressions */
14
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
15
+ /**
16
+ * Adapter to attach console logging listeners to a Host running in an app
17
+ * @hidden
18
+ */
19
+ import {
20
+ debugEmitter,
21
+ EmitterDebugLogger,
22
+ Emits,
23
+ GuestConnection,
24
+ } from "@adobe/uix-core";
25
+ import type { PortEvents } from "./port.js";
26
+ import type { HostEventLoadAllGuests, HostEvents } from "./host.js";
27
+
28
+ type GenericPortEvents = PortEvents<Record<string, unknown>>;
29
+
30
+ type Portlike = GuestConnection & Emits<GenericPortEvents>;
31
+
32
+ export function debugHost(host: Emits<HostEvents>): EmitterDebugLogger {
33
+ const hostLogger = debugEmitter(host, {
34
+ theme: "blue medium",
35
+ type: "Host",
36
+ });
37
+ hostLogger
38
+ .listen("guestbeforeload", (log, event) => {
39
+ const { detail } = event;
40
+ const guest = detail.guest as Portlike;
41
+ log.info(event, `Guest ID ${guest.id}`);
42
+ const portLogger = debugEmitter(guest, {
43
+ theme: "green medium",
44
+ type: "Port",
45
+ id: `${host.id} ➔ ${guest.id}`,
46
+ });
47
+ portLogger
48
+ .listen("hostprovide", (log, event) => {
49
+ log.info("received APIs", event.detail.apis);
50
+ })
51
+ .listen("beforecallhostmethod", (log, event) => {
52
+ log.info(event.detail);
53
+ })
54
+ .listen("unload", (log, event) => {
55
+ log.info(event.detail);
56
+ log.detach();
57
+ });
58
+ })
59
+ .listen("guestload", (log, e) => {
60
+ log.info(e.detail.guest.id, e.detail.guest);
61
+ })
62
+ .listen("error", (log, e) => {
63
+ log.error(`Error: ${e.detail.error.message}`, e);
64
+ })
65
+ .listen(
66
+ "loadallguests",
67
+ (log, { detail: { failed, loaded, host } }: HostEventLoadAllGuests) => {
68
+ if (failed.length > 0) {
69
+ log.error("%d guests failed to load!", failed.length);
70
+ }
71
+ log.info("%d guests loaded", loaded.length, host);
72
+ }
73
+ )
74
+ .listen("unload", (log) => {
75
+ log.info("Unloaded guest and container.");
76
+ log.detach();
77
+ });
78
+ return hostLogger;
79
+ }
@@ -0,0 +1,30 @@
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 { InstalledExtensions, ExtensionsProvider } from "../host.js";
14
+
15
+ /**
16
+ * Combine multiple {@link @adobe/uix-host#ExtensionsProvider} callbacks into a
17
+ * single callback, which aggregates and dedupes all extensions from all
18
+ * providers into one namespaced object.
19
+ * @public
20
+ */
21
+ export function combineExtensionsFromProviders(
22
+ ...providers: Array<ExtensionsProvider>
23
+ ): ExtensionsProvider {
24
+ return () =>
25
+ Promise.all(providers.map((ep: ExtensionsProvider) => ep())).then(
26
+ (extensionsBatches: Array<InstalledExtensions>) => {
27
+ return Object.assign({}, ...extensionsBatches);
28
+ }
29
+ );
30
+ }
@@ -0,0 +1,152 @@
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 { InstalledExtensions, ExtensionsProvider } from "../host.js";
14
+
15
+ interface ExtensionDefinition {
16
+ name: string;
17
+ title: string;
18
+ description: string;
19
+ icon: string;
20
+ publisher: string;
21
+ endpoints: Record<string, EndpointDefinition>;
22
+ xrInfo: ExtensionInfo;
23
+ status: string;
24
+ }
25
+
26
+ type EndpointDefinition = Record<string, Array<OperationDefinition>>;
27
+
28
+ interface ExtensionInfo {
29
+ supportEmail: string;
30
+ appId: string;
31
+ }
32
+
33
+ interface OperationDefinition {
34
+ href: string;
35
+ metadata: OperationMetadata;
36
+ }
37
+
38
+ interface OperationMetadata {
39
+ services: Array<object>;
40
+ profile: OperationProfile;
41
+ }
42
+
43
+ interface OperationProfile {
44
+ client_id: string;
45
+ scope: string;
46
+ }
47
+
48
+ /** @public */
49
+ export interface ExtensionRegistryEndpointRegistration {
50
+ service: string;
51
+ extensionPoint: string;
52
+ version: string;
53
+ }
54
+
55
+ /** @public */
56
+ export interface ExtensionRegistryExtensionRegistration
57
+ extends ExtensionRegistryEndpointRegistration {
58
+ imsOrg: string;
59
+ }
60
+
61
+ /** @public */
62
+ export interface ExtensionRegistryConnection {
63
+ baseUrl?: string;
64
+ apiKey: string;
65
+ auth: {
66
+ schema: "Basic" | "Bearer";
67
+ imsToken: string;
68
+ };
69
+ }
70
+
71
+ /** @public */
72
+ export interface ExtensionRegistryConfig
73
+ extends ExtensionRegistryExtensionRegistration,
74
+ ExtensionRegistryConnection {}
75
+
76
+ function buildEndpointPath(
77
+ config: ExtensionRegistryEndpointRegistration
78
+ ): string {
79
+ return `${config.service}/${config.extensionPoint}/${config.version}`;
80
+ }
81
+
82
+ function ensureProtocolSpecified(url: string) {
83
+ if (url.startsWith("https://")) {
84
+ return url;
85
+ }
86
+ if (url.startsWith("http://")) {
87
+ return url;
88
+ }
89
+ return `https://${url}`;
90
+ }
91
+
92
+ async function fetchExtensionsFromRegistry(
93
+ config: ExtensionRegistryConfig
94
+ ): Promise<Array<ExtensionDefinition>> {
95
+ const resp = await fetch(
96
+ `${ensureProtocolSpecified(
97
+ config.baseUrl || "appregistry.adobe.io"
98
+ )}/myxchng/v1/org/${encodeURIComponent(
99
+ config.imsOrg
100
+ )}/xtn/${buildEndpointPath(config)}?auth=true`,
101
+ {
102
+ headers: {
103
+ Accept: "application/json",
104
+ Authorization: `${config.auth.schema} ${config.auth.imsToken}`, // todo: check if auth schema needed (initial implementation was without it)
105
+ "X-Api-Key": config.apiKey,
106
+ },
107
+ }
108
+ );
109
+
110
+ if (resp.status != 200) {
111
+ throw new Error(
112
+ `extension registry returned non-200 response (${
113
+ resp.status
114
+ }): ${await resp.text()}`
115
+ );
116
+ }
117
+
118
+ return await resp.json();
119
+ }
120
+
121
+ function extensionRegistryExtensionsProvider(
122
+ config: ExtensionRegistryConfig
123
+ ): Promise<InstalledExtensions> {
124
+ const erEndpoint = buildEndpointPath(config);
125
+ return fetchExtensionsFromRegistry(config).then((out) =>
126
+ out.reduce((a, e: ExtensionDefinition) => {
127
+ if (e.status !== "PUBLISHED") {
128
+ return a;
129
+ }
130
+
131
+ return {
132
+ ...a,
133
+ // todo: make safer way to extract href
134
+ [e.name]: e.endpoints[erEndpoint].view[0].href,
135
+ };
136
+ }, {})
137
+ );
138
+
139
+ return Promise.resolve({});
140
+ }
141
+
142
+ /**
143
+ * Create a callback that fetches extensions from the registry.
144
+ * @public
145
+ */
146
+ export function createExtensionRegistryProvider(
147
+ config: ExtensionRegistryConfig
148
+ ): ExtensionsProvider {
149
+ return function () {
150
+ return extensionRegistryExtensionsProvider(config);
151
+ };
152
+ }
@@ -0,0 +1,14 @@
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
+ export * from "./extension-registry.js";
14
+ export * from "./composition.js";