@adobe/uix-host-react 1.1.10-nightly.20260722 → 1.1.10
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/components/GuestUIFrame.d.ts.map +1 -1
- package/dist/components/GuestUIFrame.test.d.ts +2 -0
- package/dist/components/GuestUIFrame.test.d.ts.map +1 -0
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/GuestUIFrame.test.tsx +183 -0
- package/src/components/GuestUIFrame.tsx +11 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GuestUIFrame.d.ts","sourceRoot":"","sources":["../../src/components/GuestUIFrame.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAoB,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGhE;;GAEG;AACH,KAAK,gBAAgB,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAEhE;;GAEG;AACH,KAAK,UAAU,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AAEpD,cAAc;AACd,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC3C;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IACnC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;OAEG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B;AAaD;;;;GAIG;AACH,eAAO,MAAM,YAAY,0IAYtB,YAAY,
|
|
1
|
+
{"version":3,"file":"GuestUIFrame.d.ts","sourceRoot":"","sources":["../../src/components/GuestUIFrame.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAoB,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGhE;;GAEG;AACH,KAAK,gBAAgB,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAEhE;;GAEG;AACH,KAAK,UAAU,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AAEpD,cAAc;AACd,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC3C;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IACnC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;OAEG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B;AAaD;;;;GAIG;AACH,eAAO,MAAM,YAAY,0IAYtB,YAAY,sBAwFd,CAAC;AACF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GuestUIFrame.test.d.ts","sourceRoot":"","sources":["../../src/components/GuestUIFrame.test.tsx"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -186,13 +186,10 @@ var GuestUIFrame = ({
|
|
|
186
186
|
}) => {
|
|
187
187
|
const ref = React.useRef();
|
|
188
188
|
const { host } = useHost();
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
const guest = host.guests.get(guestId);
|
|
193
|
-
const frameUrl = new URL(src, guest.url.href);
|
|
189
|
+
const guest = host ? host.guests.get(guestId) : void 0;
|
|
190
|
+
const guestId_ = guest == null ? void 0 : guest.id;
|
|
194
191
|
React.useEffect(() => {
|
|
195
|
-
if (ref.current) {
|
|
192
|
+
if (ref.current && guest) {
|
|
196
193
|
let mounted = true;
|
|
197
194
|
let connection;
|
|
198
195
|
const connectionFrame = ref.current;
|
|
@@ -229,9 +226,9 @@ var GuestUIFrame = ({
|
|
|
229
226
|
}
|
|
230
227
|
};
|
|
231
228
|
}
|
|
232
|
-
}, [
|
|
229
|
+
}, [guestId_]);
|
|
233
230
|
React.useEffect(() => {
|
|
234
|
-
if (ref.current && onResize) {
|
|
231
|
+
if (ref.current && guest && onResize) {
|
|
235
232
|
const currentFrame = ref.current;
|
|
236
233
|
return guest.addEventListener(
|
|
237
234
|
"guestresize",
|
|
@@ -242,7 +239,11 @@ var GuestUIFrame = ({
|
|
|
242
239
|
}
|
|
243
240
|
);
|
|
244
241
|
}
|
|
245
|
-
}, [ref.current,
|
|
242
|
+
}, [ref.current, guestId_, onResize]);
|
|
243
|
+
if (!host || !guest) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const frameUrl = new URL(src, guest.url.href);
|
|
246
247
|
return /* @__PURE__ */ React__default.default.createElement(
|
|
247
248
|
"iframe",
|
|
248
249
|
{
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/Extensible.tsx","../src/extension-context.ts","../src/components/GuestUIFrame.tsx","../src/hooks/useHost.ts","../src/components/ExtensibleComponentBoundary.tsx","../src/components/ExtensibleWrapper/ExtensibleWrapper.tsx","../src/components/ExtensibleWrapper/ExtensionManagerProvider.ts","../src/components/ExtensibleWrapper/UrlExtensionProvider.ts","../src/hooks/useExtensions.ts","../src/hooks/useExtensionListFetched.ts"],"names":["React","useEffect","useRef","Host","createContext","useMemo","useContext","useState"],"mappings":"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","sourcesContent":["/*\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\nexport * from \"@adobe/uix-host\";\nexport * from \"./components/index.js\";\nexport * from \"./hooks/index.js\";\nexport * from \"./extension-context\";\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 React, { useState, useEffect, useRef, useMemo } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport type {\n InstalledExtensions,\n ExtensionsProvider,\n HostConfig,\n PortOptions,\n SharedContextValues,\n} from \"@adobe/uix-host\";\nimport { Host } from \"@adobe/uix-host\";\nimport { ExtensionContext } from \"../extension-context.js\";\n\n/** @public */\nexport interface ExtensibleProps extends Omit<HostConfig, \"hostName\"> {\n /**\n * Unique name for identifying this extensible app. May be used as metadata in\n * extension registry in the future.\n */\n appName?: string;\n /**\n * Function which returns a promise for the full list of extensions.\n */\n extensionsProvider: ExtensionsProvider;\n /**\n * {@inheritDoc HostConfig.guestOptions}\n */\n guestOptions?: PortOptions;\n /**\n * {@inheritDoc HostConfig.sharedContext}\n */\n sharedContext?: SharedContextValues;\n extensionsListCallback?: (\n extensions: InstalledExtensions\n ) => InstalledExtensions;\n}\n\nfunction areExtensionsDifferent(\n set1: InstalledExtensions,\n set2: InstalledExtensions\n) {\n const ids1 = Object.keys(set1).sort();\n const ids2 = Object.keys(set2).sort();\n\n if (ids1.length !== ids2.length) {\n return true;\n }\n\n let isDifferent = false;\n\n ids1.forEach((id) => {\n if (isDifferent) {\n return;\n }\n\n const ext1 = set1[id];\n const ext2 = set2[id];\n\n if (typeof ext1 !== typeof ext2) {\n isDifferent = true;\n return;\n }\n\n if (typeof ext1 === \"string\" && typeof ext2 === \"string\") {\n if (ext1 !== ext2) {\n isDifferent = true;\n return;\n }\n }\n\n if (typeof ext1 === \"object\" && typeof ext2 === \"object\") {\n if (\n ext1.url !== ext2.url ||\n JSON.stringify(ext1.extensionPoints) !==\n JSON.stringify(ext2.extensionPoints) ||\n JSON.stringify(ext1.configuration) !==\n JSON.stringify(ext2.configuration)\n ) {\n isDifferent = true;\n return;\n }\n }\n });\n\n return isDifferent;\n}\n\n/**\n * Declares an extensible area in an app, and provides host and extension\n * objects to all descendents. The {@link useExtensions} hook can only be called\n * in a descendent of this component.\n *\n * @remarks\n * For many apps, there will be only one Extensible provider, fairly high in the\n * component tree. It is a context provider component that may be bundled with\n * other context providers in your app architecture.\n *\n * Each Extensible element creates one {@link @adobe/uix-host#Host} object and\n * one call to an extensions provider. If multiple Extensible elements are used,\n * this may cause redundant calls. Such a design should be carefully considered.\n *\n * @public\n */\nexport function Extensible({\n appName,\n children,\n extensionsProvider,\n guestOptions,\n runtimeContainer,\n debug,\n sharedContext,\n extensionsListCallback,\n}: PropsWithChildren<ExtensibleProps>) {\n const hostName = appName || window.location.host || \"mainframe\";\n\n const [extensions, setExtensions] = useState<InstalledExtensions>({});\n const [extensionListFetched, setExtensionListFetched] =\n useState<boolean>(false);\n const prevSharedContext = useRef(JSON.stringify(sharedContext));\n useEffect(() => {\n let cancelled = false;\n\n extensionsProvider()\n .then((loaded: InstalledExtensions) => {\n if (cancelled) {\n return;\n }\n setExtensions((prev) => {\n let newExtensions = loaded;\n\n if (extensionsListCallback && loaded) {\n newExtensions = extensionsListCallback(newExtensions);\n }\n\n const shouldUpdate = areExtensionsDifferent(prev, newExtensions);\n\n if (shouldUpdate) {\n return newExtensions;\n } else {\n return prev;\n }\n });\n })\n .catch((e: Error | unknown) => {\n if (!cancelled) {\n console.error(\"Fetching list of extensions failed!\", e);\n }\n })\n .finally(() => {\n if (!cancelled) {\n setExtensionListFetched(true);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [extensionsProvider, extensionsListCallback]);\n\n const [host, setHost] = useState<Host>();\n const hostRef = useRef<Host>();\n\n useEffect(() => {\n return () => {\n if (hostRef.current) {\n hostRef.current.unload().catch(() => {});\n hostRef.current = undefined;\n }\n };\n }, []);\n\n useEffect(() => {\n function logError(msg: string) {\n return (e: Error | unknown) => {\n const error = e instanceof Error ? e : new Error(String(e));\n console.error(msg, error, extensions, guestOptions);\n };\n }\n\n if (!extensions || !Object.keys(extensions).length) {\n return;\n }\n\n const loadExtensions = (hostInstance: Host) => {\n hostInstance\n .load(extensions, guestOptions)\n .catch(logError(\"Load of extensions failed!\"));\n };\n\n const sharedContextChanged =\n prevSharedContext.current !== JSON.stringify(sharedContext);\n\n if (sharedContextChanged) {\n prevSharedContext.current = JSON.stringify(sharedContext);\n }\n if (!host || sharedContextChanged) {\n if (hostRef.current) {\n hostRef.current.unload().catch(() => {});\n }\n const newHost = new Host({\n debug,\n hostName,\n runtimeContainer,\n sharedContext,\n });\n hostRef.current = newHost;\n setHost(newHost);\n loadExtensions(newHost);\n } else {\n loadExtensions(host);\n }\n }, [debug, hostName, runtimeContainer, extensions]);\n\n const contextValue = useMemo(\n () => ({ host, extensionListFetched }),\n [host, extensionListFetched]\n );\n\n return (\n <ExtensionContext.Provider value={contextValue}>\n {children}\n </ExtensionContext.Provider>\n );\n}\nexport default Extensible;\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 * @hidden\n */\nimport { createContext } from \"react\";\nimport { Host } from \"@adobe/uix-host\";\n\n/**\n * Context container with Host object and extensions load status.\n *\n * @internal\n */\nexport type ExtensibilityContext = {\n host: Host;\n extensionListFetched: boolean;\n};\n\n/**\n * @internal\n */\nexport const ExtensionContext = createContext<ExtensibilityContext>(\n {} as unknown as ExtensibilityContext\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 { CrossRealmObject, UIFrameRect, VirtualApi } from \"@adobe/uix-core\";\nimport React, { useEffect, useRef } from \"react\";\nimport type { IframeHTMLAttributes } from \"react\";\nimport { useHost } from \"../hooks/useHost.js\";\nimport type { AttrTokens, SandboxToken } from \"@adobe/uix-host\";\nimport { makeSandboxAttrs, requiredIframeProps } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\ntype ReactIframeProps = IframeHTMLAttributes<HTMLIFrameElement>;\n\n/**\n * @public\n */\ntype FrameProps = Omit<ReactIframeProps, \"sandbox\">;\n\n/** @public */\nexport interface GuestUIProps extends FrameProps {\n guestId: string;\n /**\n * Receives the Penpal context when the frame is mounted.\n */\n onConnect?: () => void;\n /**\n * Called when the frame disconnects and unmounts.\n */\n onDisconnect?: () => void;\n /**\n * Called when the connection process throws an exception\n */\n onConnectionError?: (error: Error) => void;\n /**\n * Called when the document in the iframe changes size.\n */\n onResize?: (dimensions: UIFrameRect) => void;\n /**\n * Additional sandbox attributes GuestUIFrame might need.\n */\n sandbox?: AttrTokens<SandboxToken>;\n /**\n * Optional custom URL or path.\n */\n src: string;\n /**\n * Host methods to provide only to the guest inside all iframes.\n */\n methods?: VirtualApi;\n /**\n * Host methods to provide only to the guest inside this iframe.\n */\n privateMethods?: VirtualApi;\n}\n\nconst defaultIFrameProps: FrameProps = {\n width: \"100%\",\n height: \"100%\",\n style: {\n display: \"block\",\n border: \"none\",\n },\n};\n\nconst defaultSandbox = \"allow-scripts allow-forms allow-same-origin\";\n\n/**\n * An iframe that attaches to a running GuestServer, to display visible UI pages\n * delivered by the Extension server.\n * @public\n */\nexport const GuestUIFrame = ({\n guestId,\n src = \"\",\n onConnect,\n onDisconnect,\n onConnectionError,\n onResize,\n methods,\n privateMethods,\n sandbox = \"\",\n style,\n ...customIFrameProps\n}: GuestUIProps) => {\n const ref = useRef<HTMLIFrameElement>();\n const { host } = useHost();\n if (!host) {\n return null;\n }\n const guest = host.guests.get(guestId);\n const frameUrl = new URL(src, guest.url.href);\n\n useEffect(() => {\n if (ref.current) {\n let mounted = true;\n let connection: CrossRealmObject<VirtualApi>;\n const connectionFrame = ref.current;\n if (methods) {\n guest.provide(methods);\n }\n const connecting = guest.attachUI(connectionFrame, privateMethods);\n connecting\n .then((c) => {\n connection = c;\n if (!mounted) {\n c.tunnel.destroy();\n } else if (onConnect) {\n onConnect();\n }\n })\n .catch((error: Error) => {\n if (mounted && !connection && connectionFrame === ref.current) {\n const frameError = new Error(\n `GuestUIFrame connection failed: ${\n (error && error.stack) || error\n }`\n );\n Object.assign(frameError, {\n original: error,\n ref,\n guest,\n host,\n });\n if (onConnectionError) onConnectionError(frameError);\n }\n });\n return () => {\n mounted = false;\n if (connection) {\n connection.tunnel.destroy();\n }\n };\n }\n }, [guest.id]);\n\n useEffect(() => {\n if (ref.current && onResize) {\n const currentFrame = ref.current;\n return guest.addEventListener(\n \"guestresize\",\n ({ detail: { guestPort, iframe, dimensions } }) => {\n if (guestPort.id === guest.id && iframe === currentFrame) {\n onResize(dimensions);\n }\n }\n );\n }\n }, [ref.current, guest.id, onResize]);\n\n return (\n <iframe\n {...defaultIFrameProps}\n ref={ref}\n src={frameUrl.href}\n name={`uix-guest-${guest.id}`}\n sandbox={\n sandbox\n ? makeSandboxAttrs(defaultSandbox, sandbox).join(\" \")\n : defaultSandbox\n }\n style={\n style\n ? { ...style, ...defaultIFrameProps.style }\n : defaultIFrameProps.style\n }\n {...customIFrameProps}\n {...requiredIframeProps}\n />\n );\n};\nexport default GuestUIFrame;\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 { useContext } from \"react\";\nimport { Host } from \"@adobe/uix-host\";\nimport { ExtensionContext, ExtensibilityContext } from \"../extension-context\";\n\n/**\n * @public\n */\nexport class OutsideOfExtensionContextError extends Error {\n outsideOfExtensionContext: boolean;\n constructor(msg: string) {\n super(msg);\n this.outsideOfExtensionContext = true;\n Object.setPrototypeOf(this, OutsideOfExtensionContextError.prototype);\n }\n}\n\n/** @public */\ntype UseHostResponse =\n | { host: undefined; error: Error }\n | { host: Host; error: undefined };\n\n/**\n * Retrieve the {@link @adobe/uix-host#Host} object hosting all extensions inside the current parent provider.\n *\n * @remarks Returns a `{ host, error }` tuple, not the host object directly.\n * @beta\n */\nexport function useHost(): UseHostResponse {\n const extensionsInfo = useContext<ExtensibilityContext>(ExtensionContext);\n\n if (!(extensionsInfo.host instanceof Host)) {\n const error = new OutsideOfExtensionContextError(\n \"Attempt to use extensions outside of ExtensionContext. Wrap extensible part of application with Extensible component.\"\n );\n return {\n host: undefined,\n error,\n };\n }\n return { error: undefined, host: extensionsInfo.host };\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 * @hidden\n */\nimport React, { createContext } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { ExtensionRegistryEndpointRegistration } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\nexport const ExtensibleComponentBoundaryContext = createContext<\n ExtensionRegistryEndpointRegistration[]\n>(null as ExtensionRegistryEndpointRegistration[]);\n\n/** @public */\nexport type ExtensibleComponentProps = PropsWithChildren<{\n extensionPoints: ExtensionRegistryEndpointRegistration[];\n}>;\n\n/**\n * Wrapper that adds an extension point context to subcomponent tree.\n *\n * @public\n */\nexport const ExtensibleComponentBoundary = ({\n extensionPoints,\n children,\n}: ExtensibleComponentProps) => {\n return (\n <ExtensibleComponentBoundaryContext.Provider value={extensionPoints}>\n {children}\n </ExtensibleComponentBoundaryContext.Provider>\n );\n};\n","/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nimport type { PropsWithChildren, ReactElement } from \"react\";\nimport React, { useMemo } from \"react\";\nimport { Extensible } from \"../Extensible\";\nimport {\n combineExtensionsFromProviders,\n InstalledExtensions,\n mutedProvider,\n type ExtensionsProvider,\n type HostConfig,\n type PortOptions,\n type SharedContextValues,\n} from \"@adobe/uix-host\";\nimport {\n ExtensionPointId,\n ExtensionProviderConfig,\n createExtensionManagerExtensionsProvider,\n} from \"./ExtensionManagerProvider\";\nimport { createUrlExtensionsProvider } from \"./UrlExtensionProvider\";\n\n/** @public */\nexport interface ExtensibleDefaultProps extends Omit<HostConfig, \"hostName\"> {\n /**\n * Unique name for identifying this extensible app. May be used as metadata in\n * extension registry in the future.\n */\n appName?: string;\n /**\n * {@inheritDoc HostConfig.guestOptions}\n */\n guestOptions?: PortOptions;\n /**\n * {@inheritDoc HostConfig.sharedContext}\n */\n sharedContext?: SharedContextValues;\n queryString?: string;\n service: string;\n extensionPoint: string;\n version: string;\n disableExtensionManager?: boolean;\n authConfig: {\n imsToken: string;\n imsOrg: string;\n apiKey: string;\n };\n scope?: Record<string, any>;\n experienceShellEnvironment?: \"prod\" | \"stage\";\n extensionsListCallback?: (\n extensions: InstalledExtensions\n ) => InstalledExtensions;\n}\n\n/**\n * ExtensibleWrapper component that provides extension support to React applications.\n * @public\n */\nexport const ExtensibleWrapper = ({\n appName,\n children,\n guestOptions,\n runtimeContainer,\n debug,\n sharedContext,\n experienceShellEnvironment,\n queryString,\n service,\n extensionPoint,\n version,\n disableExtensionManager,\n authConfig,\n scope,\n extensionsListCallback,\n}: PropsWithChildren<ExtensibleDefaultProps>): ReactElement => {\n const defaultExtensionsProvider = useMemo(() => {\n const extensionPointId: ExtensionPointId = {\n service,\n name: extensionPoint,\n version,\n };\n const params: URLSearchParams = new URLSearchParams(queryString ?? \"\");\n const extensionManagerUrlOverride = params.get(\"em\");\n const appRegistryUrlOverride = params.get(\"er\");\n const urlExtensionsProvider: ExtensionsProvider =\n createUrlExtensionsProvider(extensionPointId, queryString);\n const providerConfig: ExtensionProviderConfig = {\n disableExtensionManager,\n };\n\n if (extensionManagerUrlOverride) {\n providerConfig.extensionManagerUrl = extensionManagerUrlOverride;\n }\n\n if (appRegistryUrlOverride) {\n providerConfig.appRegistryUrl = appRegistryUrlOverride;\n }\n\n const extensionManagerExtensionsProvider: ExtensionsProvider =\n createExtensionManagerExtensionsProvider(\n {\n experienceShellEnvironment,\n scope,\n },\n authConfig,\n providerConfig,\n extensionPointId\n );\n\n const extenstions = combineExtensionsFromProviders(\n urlExtensionsProvider,\n mutedProvider(extensionManagerExtensionsProvider)\n );\n\n return extenstions;\n }, [\n experienceShellEnvironment,\n queryString,\n service,\n extensionPoint,\n version,\n disableExtensionManager,\n authConfig,\n scope,\n ]);\n return (\n <Extensible\n extensionsProvider={defaultExtensionsProvider}\n appName={appName}\n runtimeContainer={runtimeContainer}\n debug={debug}\n guestOptions={guestOptions}\n sharedContext={sharedContext}\n extensionsListCallback={extensionsListCallback}\n >\n {children}\n </Extensible>\n );\n};\n\nexport default ExtensibleWrapper;\n","/*************************************************************************\n * ADOBE CONFIDENTIAL\n * ___________________\n *\n * Copyright 2024 Adobe\n * All Rights Reserved.\n *\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n **************************************************************************/\n\nimport {\n createExtensionRegistryAsObjectsProvider,\n ExtensionsProvider,\n InstalledExtensions,\n} from \"@adobe/uix-host\";\n\nconst EXTENSION_MANAGER_URL_PROD = \"https://aemx-mngr.adobe.io\";\nconst EXTENSION_MANAGER_URL_STAGE = \"https://aemx-mngr-stage.adobe.io\";\n\nconst APP_REGISTRY_URL_PROD = \"https://appregistry.adobe.io\";\nconst APP_REGISTRY_URL_STAGE = \"https://appregistry-stage.adobe.io\";\n\n// Extension Manager stores information about extension points that a particular extension implements\n// in the \"extensionPoints\" array of objects of the following \"ExtensionPoint\" type\n// where \"extensionPoint\" is the name of the extension point, for example, \"aem/assets/details/1\"\n// \"url\" is the extension url for the specified extension point\n/** @internal */\ntype ExtensionPoint = {\n extensionPoint: string;\n url: string;\n};\n/** @public */\nexport type ExtensionManagerExtension = {\n id: string;\n name: string;\n title: string;\n description: string;\n status: string;\n supportEmail: string;\n extId: string;\n disabled: boolean;\n extensionPoints: ExtensionPoint[];\n scope: Record<string, unknown>;\n configuration?: Record<string, unknown>;\n};\n\n/** @internal */\ntype AuthEMConfig = {\n schema: \"Bearer\" | \"Basic\";\n imsToken: string;\n};\n/** @public */\nexport interface ExtensionManagerConfig {\n apiKey: string;\n auth: AuthEMConfig;\n service: string;\n extensionPoint: string;\n version: string;\n imsOrg: string;\n baseUrl: string;\n scope?: Record<string, string>;\n}\n\n/**\n * Authentication configuration, including IMS Org ID, access token, and API key\n * @public\n */\nexport interface AuthConfig {\n /** IMS Org ID */\n imsOrg: string;\n /** Access token for the user */\n imsToken: string;\n /** API key */\n apiKey: string;\n}\n\n/**\n * Discovery configuration, including environment and repo Id\n * @public\n */\nexport interface DiscoveryConfig {\n /** Environment level for backend Extension resolution services */\n experienceShellEnvironment?: \"prod\" | \"stage\";\n scope?: Record<string, string>;\n}\n\n/**\n * Extension point ID\n * @public\n */\nexport interface ExtensionPointId {\n /** Service name */\n service: string;\n /** Extension point name */\n name: string;\n /** Extension point version */\n version: string;\n}\n\n/**\n * Sets up new ExtensionsProvider with authentication and discovery information needed to fetch the list of\n * Extensions from AppRegistry and Extension Manager service, along with the query string portion of URL\n * to extract the information about development Extensions\n * @public\n */\nexport interface ExtensionsProviderConfig {\n /** Discovery configuration */\n discoveryConfig: DiscoveryConfig;\n /** Authentication configuration */\n authConfig: AuthConfig;\n /** Extension point ID */\n extensionPointId: ExtensionPointId;\n providerConfig: ExtensionProviderConfig;\n}\n\n/** @public */\nexport interface ExtensionProviderConfig {\n extensionManagerUrl?: string;\n appRegistryUrl?: string;\n disableExtensionManager?: boolean;\n}\n/** @internal */\nexport const getExtensionRegistryBaseUrl = (\n environment: \"prod\" | \"stage\" | undefined,\n registry: string | null\n): string =>\n environment === \"prod\"\n ? APP_REGISTRY_URL_PROD\n : registry ?? APP_REGISTRY_URL_STAGE;\n\n/** @internal */\nexport const getExtensionManagerBaseUrl = (\n environment: \"prod\" | \"stage\" | undefined,\n extensionManager: string | null\n): string =>\n environment === \"prod\"\n ? EXTENSION_MANAGER_URL_PROD\n : extensionManager ?? EXTENSION_MANAGER_URL_STAGE;\n\n/**\n * Extracts programId and envId from the repo value\n * @param repo - the repo value\n * @returns object with programId and envId\n * @internal\n */\nexport function extractProgramIdEnvId(repo: string): {\n programId: string;\n envId: string;\n} {\n const regex: RegExp = /p(\\d+)-e(\\d+)/;\n const match: RegExpMatchArray | null = regex.exec(repo);\n if (!match) {\n throw new Error(\"Error parsing a repo value\");\n }\n\n return {\n programId: match[1],\n envId: match[2],\n };\n}\n\n/**\n * Builds the URL for fetching extensions from the Extension Manager service\n * @param config - the Extension Manager configuration\n * @returns the URL for fetching extensions\n * @internal\n */\nexport function buildExtensionManagerUrl(\n config: ExtensionManagerConfig\n): string {\n const scope = config.scope\n ? Object.fromEntries(\n Object.entries(config.scope).map(([k, v]) => [`scope.${k}`, v])\n )\n : {};\n const extensionPoints: string = `${config.service}/${config.extensionPoint}/${config.version}`;\n const queryParams = new URLSearchParams({\n ...scope,\n extensionPoints,\n });\n\n return `${config.baseUrl}/v2/extensions?${queryParams.toString()}`;\n}\n\n/**\n * @internal\n */\nexport async function fetchExtensionsFromExtensionManager(\n config: ExtensionManagerConfig\n): Promise<ExtensionManagerExtension[]> {\n const resp: Response = await fetch(buildExtensionManagerUrl(config), {\n headers: {\n Authorization: `Bearer ${config.auth.imsToken}`,\n \"x-api-key\": config.apiKey,\n \"x-org-id\": config.imsOrg,\n },\n });\n\n if (resp.status !== 200) {\n throw new Error(\n `Extension Manager returned non-200 response (${\n resp.status\n }): ${await resp.text()}`\n );\n }\n\n return resp.json();\n}\n\n/**\n * Takes an array of extensions from the App Registry, an array of extensions from the Extension Manager, and\n * merges them into a list of Extensions. If an extension is disabled in the Extension Manager, it is removed from\n * the list.\n * Extension list from the App Registry is used as a base.\n * @internal\n */\nexport function mergeExtensions(\n appRegistryExtensions: InstalledExtensions,\n extensionManagerExtensions: ExtensionManagerExtension[],\n extensionPointId: ExtensionPointId\n): InstalledExtensions {\n const mergedExtensions: InstalledExtensions = Object.assign(\n appRegistryExtensions,\n {}\n );\n extensionManagerExtensions.forEach((extension: ExtensionManagerExtension) => {\n if (extension.disabled) {\n // remove disabled extensions\n delete mergedExtensions[extension.name];\n } else {\n const extPoint: ExtensionPoint | undefined =\n extension.extensionPoints.find(\n (_extensionPoint: ExtensionPoint) =>\n _extensionPoint.extensionPoint ===\n `${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`\n );\n if (extPoint) {\n // add a new extension record or replace the existing one by an extension record from Extension Manager\n // extension points are useful for filtering out extensions\n mergedExtensions[extension.name] = {\n id: extension.name,\n url: extPoint.url,\n configuration: extension.configuration,\n extensionPoints: extension.extensionPoints.map(\n (point) => point.extensionPoint\n ),\n };\n } else {\n //this should never happen because we query Extension Manager service for our specific extension point\n console.warn(\n `Extension point ${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version} not found for extension ${extension.name}`\n );\n }\n }\n });\n\n return mergedExtensions;\n}\n\nasync function getExtensionManagerExtensions(\n discoveryConfig: DiscoveryConfig,\n authConfig: AuthConfig,\n providerConfig: ExtensionProviderConfig,\n extensionPointId: ExtensionPointId\n): Promise<InstalledExtensions> {\n const config = {\n apiKey: authConfig.apiKey,\n auth: {\n schema: \"Bearer\",\n imsToken: authConfig.imsToken,\n },\n service: extensionPointId.service,\n extensionPoint: extensionPointId.name,\n version: extensionPointId.version,\n imsOrg: authConfig.imsOrg,\n scope: discoveryConfig.scope,\n };\n\n const appRegistryConfig = {\n ...config,\n baseUrl: getExtensionRegistryBaseUrl(\n discoveryConfig.experienceShellEnvironment,\n providerConfig.appRegistryUrl\n ),\n } as ExtensionManagerConfig;\n const appRegistryExtensionsProvider: ExtensionsProvider =\n createExtensionRegistryAsObjectsProvider(appRegistryConfig);\n\n const extensionManagerConfiguration = {\n ...config,\n baseUrl: getExtensionManagerBaseUrl(\n discoveryConfig.experienceShellEnvironment,\n providerConfig.extensionManagerUrl\n ),\n } as ExtensionManagerConfig;\n const [appRegistryExtensions, extensionManagerExtensions] = await Promise.all(\n [\n appRegistryExtensionsProvider(),\n providerConfig.disableExtensionManager\n ? []\n : fetchExtensionsFromExtensionManager(extensionManagerConfiguration),\n ]\n );\n\n if (providerConfig.disableExtensionManager) {\n return appRegistryExtensions;\n } else {\n return mergeExtensions(\n appRegistryExtensions,\n extensionManagerExtensions,\n extensionPointId\n );\n }\n}\n\n/**\n * Creates an extension manager extension provider\n * @internal\n */\nexport function createExtensionManagerExtensionsProvider(\n discoveryConfig: DiscoveryConfig,\n authConfig: AuthConfig,\n providerConfig: ExtensionProviderConfig,\n extensionPointId: ExtensionPointId\n): ExtensionsProvider {\n return () => {\n return getExtensionManagerExtensions(\n discoveryConfig,\n authConfig,\n providerConfig,\n extensionPointId\n );\n };\n}\n","/*************************************************************************\n * ADOBE CONFIDENTIAL\n * ___________________\n *\n * Copyright 2024 Adobe\n * All Rights Reserved.\n *\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n **************************************************************************/\nimport { ExtensionsProvider, InstalledExtensions } from \"@adobe/uix-host\";\nimport { Extension } from \"@adobe/uix-core\";\nimport { ExtensionPointId } from \"./ExtensionManagerProvider\";\nconst EXT_PARAM_PREFIX = \"ext\";\n\n/** @public */\nexport interface ExtUrlParams {\n [key: string]: string;\n}\n\n/**\n * Validates if a URL is safe and only allows HTTP/HTTPS protocols\n * @param url - The URL string to validate\n * @returns true if the URL is valid and uses HTTP/HTTPS protocol, false otherwise\n * @public\n */\nexport function isValidHttpUrl(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n\n return parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\n/**\n * Extracts extension URLs from the query string\n * @internal\n */\nexport function extractExtUrlParams(\n queryString: string | undefined\n): ExtUrlParams {\n if (!queryString) {\n return {};\n }\n const params: URLSearchParams = new URLSearchParams(queryString);\n return Array.from(params.entries()).reduce((extParams, [key, value]) => {\n if (key === EXT_PARAM_PREFIX || key.startsWith(`${EXT_PARAM_PREFIX}.`)) {\n extParams[key] = value;\n }\n return extParams;\n }, {} as ExtUrlParams);\n}\n\n/**\n * Generates an extension ID from the extension URL\n * @internal\n */\nexport function generateExtensionId(extensionUrl: string): string {\n return extensionUrl.replace(/\\W/g, \"_\");\n}\n\n/**\n * Creates an ExtensionsProvider that provides extensions from the URL\n * @internal\n */\nexport function createUrlExtensionsProvider(\n extensionPointId: ExtensionPointId,\n queryString: string | undefined\n): ExtensionsProvider {\n const extUrlParams: ExtUrlParams = extractExtUrlParams(queryString);\n\n const extensionUrls: string[] = Object.keys(extUrlParams)\n .filter(\n (extParam) =>\n extParam === EXT_PARAM_PREFIX ||\n extParam ===\n `${EXT_PARAM_PREFIX}.${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`\n )\n .flatMap((extParam) => {\n const paramValue = extUrlParams[extParam];\n // If it's a single value, return it in an array. If it's already an array, return it as is.\n if (Array.isArray(paramValue)) {\n return paramValue.filter((param) => isValidHttpUrl(param));\n } else {\n return isValidHttpUrl(paramValue) ? [paramValue] : [];\n }\n });\n\n const installedExtensions: InstalledExtensions = extensionUrls\n .map((extensionUrl: string) => {\n return {\n id: generateExtensionId(extensionUrl),\n url: extensionUrl,\n extensionPoints: [\n `${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`,\n ],\n } as Extension;\n })\n .reduce((acc: InstalledExtensions, extension: Extension) => {\n acc[extension.id] = extension;\n return acc;\n }, {} as InstalledExtensions);\n\n return async () => installedExtensions;\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 { useCallback, useContext, useEffect, useMemo, useState } from \"react\";\nimport type {\n GuestConnection,\n GuestApis,\n RemoteGuestApis,\n RemoteGuestApiNS,\n VirtualApi,\n} from \"@adobe/uix-core\";\n\nimport { Host, HostEvents } from \"@adobe/uix-host\";\nimport type { CapabilitySpec, Port } from \"@adobe/uix-host\";\nimport { useHost } from \"./useHost\";\nimport { ExtensibleComponentBoundaryContext } from \"../components/ExtensibleComponentBoundary\";\nimport { ExtensionRegistryEndpointRegistration } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\nexport interface TypedGuestConnection<T extends GuestApis>\n extends GuestConnection {\n id: GuestConnection[\"id\"];\n apis: RemoteGuestApis<T>;\n}\n\n/** @public */\nexport interface UseExtensionsConfig<\n Incoming extends GuestApis,\n Outgoing extends VirtualApi\n> {\n /**\n * A {@link @adobe/uix-host#CapabilitySpec} describing the namespaced methods\n * extensions must implement to be used by this component.\n *\n * @remarks\n * This declaration is used to filter the extensions that will be\n * returned; if they don't implement those methods, they will be filtered out.\n */\n requires?: CapabilitySpec<Required<Incoming>>;\n /**\n * A namespaced object of methods which extensions will be able to call.\n *\n * @remarks This is the counterpart of `requires`; in `requires`, the you\n * describes methods the extension must implement that your host code will\n * call, and in `provides`, you implement host methods that extensions will be\n * able to call.\n *\n * Most cases for host-side methods will use the state of the component. This\n * can cause unexpected bugs in React if the config callback is run on every\n * render. **useExtensions caches the config callback by default!**\n * So remember to pass a deps array, so that the config callback re-runs under\n * the right conditions.\n */\n provides?: Outgoing;\n /**\n * Sets when re-render is triggered on extension load.\n *\n * @remarks\n * Set to `each` to trigger a component re-render every time an individual\n * extension loads, which may result in multiple UI updates. Set to `all` to\n * wait until all extensions have loaded to re-render the component.\n * @defaultValue \"each\"\n */\n updateOn?: \"each\" | \"all\";\n}\n\n/** @public */\nexport interface UseExtensionsResult<T extends GuestApis> {\n /**\n * A list of loaded guests which implement the methods specified in\n * `requires`, represented as {@link @adobe/uix-host#Port} objects which\n * present methods to be called.\n */\n extensions: TypedGuestConnection<T>[];\n /**\n * This is `true` until all extensions are loaded. Use for rendering spinners\n * or other intermediate UI.\n */\n loading: boolean;\n /**\n * Populated with an Error if there were any problems during the load process.\n */\n error?: Error;\n}\n\nconst NO_EXTENSIONS: [] = [];\n\n/**\n * Fetch extensions which implement an API, provide them methods, and use them.\n *\n * @remarks `useExtensions` does three things at once:\n * - Gets all extensions which implement the APIs described in the `require` field\n * - Exposes any functions defined in the `provide` field to those extensions\n * - Returns an object whose `extensions` property is a list of `Port` objects representing those extensions\n *\n * useExtensions will trigger a re-render when extensions load. You can choose whether it triggers that rerender as each extension loads, or only after all extensions have loaded.\n * @public\n */\nexport function useExtensions<\n Incoming extends GuestApis,\n Outgoing extends VirtualApi\n>(\n configFactory: (host: Host) => UseExtensionsConfig<Incoming, Outgoing>,\n deps: unknown[] = []\n): UseExtensionsResult<Incoming> {\n const { host, error: contextError } = useHost();\n\n // All hooks must be called unconditionally before any early return.\n const [hostError, setHostError] = useState<Error>();\n const extensionPoints = useContext(ExtensibleComponentBoundaryContext);\n const boundryExtensionPointsAsString = extensionPoints?.map(\n ({\n service,\n extensionPoint,\n version,\n }: ExtensionRegistryEndpointRegistration) =>\n `${service}/${extensionPoint}/${version}`\n );\n const baseDeps = [host, ...deps];\n const {\n requires,\n provides,\n updateOn = \"each\",\n } = useMemo(\n () =>\n (host ? configFactory(host) : {}) as UseExtensionsConfig<\n Incoming,\n Outgoing\n >,\n baseDeps\n );\n\n const getExtensions = useCallback(() => {\n if (!host) return NO_EXTENSIONS;\n const newExtensions = [];\n const guests = host.getLoadedGuests(requires);\n\n // Extension filtering: If the boundary is provided, only return extensions which have extensionPoint\n // specified in a provided boundry. Otherwise no filtering is done.\n for (const guest of guests) {\n const allExtensionPoints: string[] =\n getAllExtensionPointsFromGuest(guest);\n\n if (\n !boundryExtensionPointsAsString ||\n !allExtensionPoints.length ||\n isGuestExtensionPointInBoundary(\n boundryExtensionPointsAsString,\n allExtensionPoints\n )\n ) {\n newExtensions.push(guest as unknown as TypedGuestConnection<Incoming>);\n }\n }\n return newExtensions.length === 0 ? NO_EXTENSIONS : newExtensions;\n }, [...baseDeps, requires]);\n\n const subscribe = useCallback(\n (handler: EventListener) => {\n if (!host) return () => {};\n const eventName = updateOn === \"all\" ? \"loadallguests\" : \"guestload\";\n host.addEventListener(eventName, handler);\n\n return () => {\n host.removeEventListener(eventName, handler);\n };\n },\n [...baseDeps, updateOn]\n );\n\n const subscribeToUnload = useCallback((handler: EventListener) => {\n if (!host) return () => {};\n host.addEventListener(\"guestunload\", handler);\n\n return () => {\n host.removeEventListener(\"guestunload\", handler);\n };\n }, baseDeps);\n\n const [extensions, setExtensions] =\n useState<TypedGuestConnection<Incoming>[]>(NO_EXTENSIONS);\n\n useEffect(() => {\n // Sync current guests immediately when host becomes available, then subscribe to future loads.\n setExtensions(getExtensions());\n return subscribe(() => setExtensions(getExtensions()));\n }, [subscribe]);\n\n const unloadExtentionCallback = (e: CustomEvent) => {\n const eventDetail = e.detail;\n const guest = eventDetail.guest as Port<GuestApis>;\n\n if (guest && guest.id) {\n setExtensions((prevExtensions) => {\n const filtered = prevExtensions.filter(\n (ext) => ext.id !== guest.id || ext.url !== guest.url\n );\n return filtered.length === 0 ? NO_EXTENSIONS : filtered;\n });\n }\n };\n\n useEffect(() => {\n return subscribeToUnload(unloadExtentionCallback);\n }, [subscribeToUnload]);\n\n useEffect(() => {\n for (const guest of extensions) {\n if (provides) {\n guest.provide(provides);\n }\n }\n }, [provides, extensions]);\n\n useEffect(() => {\n if (!host) return;\n return host.addEventListener(\n \"error\",\n (event: Extract<HostEvents, { detail: { error: Error } }>) =>\n setHostError(event.detail.error)\n );\n }, baseDeps);\n\n if (contextError) {\n return {\n extensions: NO_EXTENSIONS,\n loading: false,\n error: contextError,\n };\n }\n\n return {\n extensions,\n loading: extensions.length === 0 ? false : host.loading,\n error: hostError,\n };\n}\n\n/**\n * Each extension/guest can have\n * 1. `extensioPoints` field as an array of strings\n * 2. Metadata with array of extensionPoints. If the metadata is present, we need to use it for fitering the extensions.\n * Returns cumulative extension points.\n * @param guest\n * @returns array of extension points as strings\n */\nfunction getAllExtensionPointsFromGuest(guest: Port<GuestApis>): string[] {\n try {\n const guestExtensionPointsFromMetadata = guest.metadata?.extensions?.map(\n (extension: { extensionPoint: string }) => extension?.extensionPoint\n );\n const allExtensionPoints = [\n ...(guest.extensionPoints || []),\n ...(guestExtensionPointsFromMetadata || []),\n ];\n return allExtensionPoints;\n } catch {\n console.error(\n \"Error occurred while getting extension points from guest and metadata. Extension boundaries will not be effective.\"\n );\n return [];\n }\n}\n\nfunction isGuestExtensionPointInBoundary(\n boundryExtensionPointsAsString: string[],\n guestExtensionPoints: string[]\n) {\n return (\n boundryExtensionPointsAsString?.length &&\n guestExtensionPoints?.length &&\n guestExtensionPoints.some((extensionPoint) =>\n boundryExtensionPointsAsString.includes(extensionPoint)\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 { useContext } from \"react\";\nimport {\n ExtensionContext,\n ExtensibilityContext,\n} from \"../extension-context.js\";\n\n/**\n * Indicates if external extensions provider was processed. Returns true after passing extension list to the Host.\n *\n * @beta\n */\nexport function useExtensionListFetched(): boolean {\n const extensionsInfo = useContext<ExtensibilityContext>(ExtensionContext);\n\n return extensionsInfo.extensionListFetched;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/Extensible.tsx","../src/extension-context.ts","../src/components/GuestUIFrame.tsx","../src/hooks/useHost.ts","../src/components/ExtensibleComponentBoundary.tsx","../src/components/ExtensibleWrapper/ExtensibleWrapper.tsx","../src/components/ExtensibleWrapper/ExtensionManagerProvider.ts","../src/components/ExtensibleWrapper/UrlExtensionProvider.ts","../src/hooks/useExtensions.ts","../src/hooks/useExtensionListFetched.ts"],"names":["React","useEffect","useRef","Host","createContext","useMemo","useContext","useState"],"mappings":"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","sourcesContent":["/*\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\nexport * from \"@adobe/uix-host\";\nexport * from \"./components/index.js\";\nexport * from \"./hooks/index.js\";\nexport * from \"./extension-context\";\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 React, { useState, useEffect, useRef, useMemo } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport type {\n InstalledExtensions,\n ExtensionsProvider,\n HostConfig,\n PortOptions,\n SharedContextValues,\n} from \"@adobe/uix-host\";\nimport { Host } from \"@adobe/uix-host\";\nimport { ExtensionContext } from \"../extension-context.js\";\n\n/** @public */\nexport interface ExtensibleProps extends Omit<HostConfig, \"hostName\"> {\n /**\n * Unique name for identifying this extensible app. May be used as metadata in\n * extension registry in the future.\n */\n appName?: string;\n /**\n * Function which returns a promise for the full list of extensions.\n */\n extensionsProvider: ExtensionsProvider;\n /**\n * {@inheritDoc HostConfig.guestOptions}\n */\n guestOptions?: PortOptions;\n /**\n * {@inheritDoc HostConfig.sharedContext}\n */\n sharedContext?: SharedContextValues;\n extensionsListCallback?: (\n extensions: InstalledExtensions\n ) => InstalledExtensions;\n}\n\nfunction areExtensionsDifferent(\n set1: InstalledExtensions,\n set2: InstalledExtensions\n) {\n const ids1 = Object.keys(set1).sort();\n const ids2 = Object.keys(set2).sort();\n\n if (ids1.length !== ids2.length) {\n return true;\n }\n\n let isDifferent = false;\n\n ids1.forEach((id) => {\n if (isDifferent) {\n return;\n }\n\n const ext1 = set1[id];\n const ext2 = set2[id];\n\n if (typeof ext1 !== typeof ext2) {\n isDifferent = true;\n return;\n }\n\n if (typeof ext1 === \"string\" && typeof ext2 === \"string\") {\n if (ext1 !== ext2) {\n isDifferent = true;\n return;\n }\n }\n\n if (typeof ext1 === \"object\" && typeof ext2 === \"object\") {\n if (\n ext1.url !== ext2.url ||\n JSON.stringify(ext1.extensionPoints) !==\n JSON.stringify(ext2.extensionPoints) ||\n JSON.stringify(ext1.configuration) !==\n JSON.stringify(ext2.configuration)\n ) {\n isDifferent = true;\n return;\n }\n }\n });\n\n return isDifferent;\n}\n\n/**\n * Declares an extensible area in an app, and provides host and extension\n * objects to all descendents. The {@link useExtensions} hook can only be called\n * in a descendent of this component.\n *\n * @remarks\n * For many apps, there will be only one Extensible provider, fairly high in the\n * component tree. It is a context provider component that may be bundled with\n * other context providers in your app architecture.\n *\n * Each Extensible element creates one {@link @adobe/uix-host#Host} object and\n * one call to an extensions provider. If multiple Extensible elements are used,\n * this may cause redundant calls. Such a design should be carefully considered.\n *\n * @public\n */\nexport function Extensible({\n appName,\n children,\n extensionsProvider,\n guestOptions,\n runtimeContainer,\n debug,\n sharedContext,\n extensionsListCallback,\n}: PropsWithChildren<ExtensibleProps>) {\n const hostName = appName || window.location.host || \"mainframe\";\n\n const [extensions, setExtensions] = useState<InstalledExtensions>({});\n const [extensionListFetched, setExtensionListFetched] =\n useState<boolean>(false);\n const prevSharedContext = useRef(JSON.stringify(sharedContext));\n useEffect(() => {\n let cancelled = false;\n\n extensionsProvider()\n .then((loaded: InstalledExtensions) => {\n if (cancelled) {\n return;\n }\n setExtensions((prev) => {\n let newExtensions = loaded;\n\n if (extensionsListCallback && loaded) {\n newExtensions = extensionsListCallback(newExtensions);\n }\n\n const shouldUpdate = areExtensionsDifferent(prev, newExtensions);\n\n if (shouldUpdate) {\n return newExtensions;\n } else {\n return prev;\n }\n });\n })\n .catch((e: Error | unknown) => {\n if (!cancelled) {\n console.error(\"Fetching list of extensions failed!\", e);\n }\n })\n .finally(() => {\n if (!cancelled) {\n setExtensionListFetched(true);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [extensionsProvider, extensionsListCallback]);\n\n const [host, setHost] = useState<Host>();\n const hostRef = useRef<Host>();\n\n useEffect(() => {\n return () => {\n if (hostRef.current) {\n hostRef.current.unload().catch(() => {});\n hostRef.current = undefined;\n }\n };\n }, []);\n\n useEffect(() => {\n function logError(msg: string) {\n return (e: Error | unknown) => {\n const error = e instanceof Error ? e : new Error(String(e));\n console.error(msg, error, extensions, guestOptions);\n };\n }\n\n if (!extensions || !Object.keys(extensions).length) {\n return;\n }\n\n const loadExtensions = (hostInstance: Host) => {\n hostInstance\n .load(extensions, guestOptions)\n .catch(logError(\"Load of extensions failed!\"));\n };\n\n const sharedContextChanged =\n prevSharedContext.current !== JSON.stringify(sharedContext);\n\n if (sharedContextChanged) {\n prevSharedContext.current = JSON.stringify(sharedContext);\n }\n if (!host || sharedContextChanged) {\n if (hostRef.current) {\n hostRef.current.unload().catch(() => {});\n }\n const newHost = new Host({\n debug,\n hostName,\n runtimeContainer,\n sharedContext,\n });\n hostRef.current = newHost;\n setHost(newHost);\n loadExtensions(newHost);\n } else {\n loadExtensions(host);\n }\n }, [debug, hostName, runtimeContainer, extensions]);\n\n const contextValue = useMemo(\n () => ({ host, extensionListFetched }),\n [host, extensionListFetched]\n );\n\n return (\n <ExtensionContext.Provider value={contextValue}>\n {children}\n </ExtensionContext.Provider>\n );\n}\nexport default Extensible;\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 * @hidden\n */\nimport { createContext } from \"react\";\nimport { Host } from \"@adobe/uix-host\";\n\n/**\n * Context container with Host object and extensions load status.\n *\n * @internal\n */\nexport type ExtensibilityContext = {\n host: Host;\n extensionListFetched: boolean;\n};\n\n/**\n * @internal\n */\nexport const ExtensionContext = createContext<ExtensibilityContext>(\n {} as unknown as ExtensibilityContext\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 { CrossRealmObject, UIFrameRect, VirtualApi } from \"@adobe/uix-core\";\nimport React, { useEffect, useRef } from \"react\";\nimport type { IframeHTMLAttributes } from \"react\";\nimport { useHost } from \"../hooks/useHost.js\";\nimport type { AttrTokens, SandboxToken } from \"@adobe/uix-host\";\nimport { makeSandboxAttrs, requiredIframeProps } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\ntype ReactIframeProps = IframeHTMLAttributes<HTMLIFrameElement>;\n\n/**\n * @public\n */\ntype FrameProps = Omit<ReactIframeProps, \"sandbox\">;\n\n/** @public */\nexport interface GuestUIProps extends FrameProps {\n guestId: string;\n /**\n * Receives the Penpal context when the frame is mounted.\n */\n onConnect?: () => void;\n /**\n * Called when the frame disconnects and unmounts.\n */\n onDisconnect?: () => void;\n /**\n * Called when the connection process throws an exception\n */\n onConnectionError?: (error: Error) => void;\n /**\n * Called when the document in the iframe changes size.\n */\n onResize?: (dimensions: UIFrameRect) => void;\n /**\n * Additional sandbox attributes GuestUIFrame might need.\n */\n sandbox?: AttrTokens<SandboxToken>;\n /**\n * Optional custom URL or path.\n */\n src: string;\n /**\n * Host methods to provide only to the guest inside all iframes.\n */\n methods?: VirtualApi;\n /**\n * Host methods to provide only to the guest inside this iframe.\n */\n privateMethods?: VirtualApi;\n}\n\nconst defaultIFrameProps: FrameProps = {\n width: \"100%\",\n height: \"100%\",\n style: {\n display: \"block\",\n border: \"none\",\n },\n};\n\nconst defaultSandbox = \"allow-scripts allow-forms allow-same-origin\";\n\n/**\n * An iframe that attaches to a running GuestServer, to display visible UI pages\n * delivered by the Extension server.\n * @public\n */\nexport const GuestUIFrame = ({\n guestId,\n src = \"\",\n onConnect,\n onDisconnect,\n onConnectionError,\n onResize,\n methods,\n privateMethods,\n sandbox = \"\",\n style,\n ...customIFrameProps\n}: GuestUIProps) => {\n const ref = useRef<HTMLIFrameElement>();\n const { host } = useHost();\n const guest = host ? host.guests.get(guestId) : undefined;\n const guestId_ = guest?.id;\n\n useEffect(() => {\n if (ref.current && guest) {\n let mounted = true;\n let connection: CrossRealmObject<VirtualApi>;\n const connectionFrame = ref.current;\n if (methods) {\n guest.provide(methods);\n }\n const connecting = guest.attachUI(connectionFrame, privateMethods);\n connecting\n .then((c) => {\n connection = c;\n if (!mounted) {\n c.tunnel.destroy();\n } else if (onConnect) {\n onConnect();\n }\n })\n .catch((error: Error) => {\n if (mounted && !connection && connectionFrame === ref.current) {\n const frameError = new Error(\n `GuestUIFrame connection failed: ${\n (error && error.stack) || error\n }`\n );\n Object.assign(frameError, {\n original: error,\n ref,\n guest,\n host,\n });\n if (onConnectionError) onConnectionError(frameError);\n }\n });\n return () => {\n mounted = false;\n if (connection) {\n connection.tunnel.destroy();\n }\n };\n }\n }, [guestId_]);\n\n useEffect(() => {\n if (ref.current && guest && onResize) {\n const currentFrame = ref.current;\n return guest.addEventListener(\n \"guestresize\",\n ({ detail: { guestPort, iframe, dimensions } }) => {\n if (guestPort.id === guest.id && iframe === currentFrame) {\n onResize(dimensions);\n }\n }\n );\n }\n }, [ref.current, guestId_, onResize]);\n\n if (!host || !guest) {\n return null;\n }\n const frameUrl = new URL(src, guest.url.href);\n\n return (\n <iframe\n {...defaultIFrameProps}\n ref={ref}\n src={frameUrl.href}\n name={`uix-guest-${guest.id}`}\n sandbox={\n sandbox\n ? makeSandboxAttrs(defaultSandbox, sandbox).join(\" \")\n : defaultSandbox\n }\n style={\n style\n ? { ...style, ...defaultIFrameProps.style }\n : defaultIFrameProps.style\n }\n {...customIFrameProps}\n {...requiredIframeProps}\n />\n );\n};\nexport default GuestUIFrame;\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 { useContext } from \"react\";\nimport { Host } from \"@adobe/uix-host\";\nimport { ExtensionContext, ExtensibilityContext } from \"../extension-context\";\n\n/**\n * @public\n */\nexport class OutsideOfExtensionContextError extends Error {\n outsideOfExtensionContext: boolean;\n constructor(msg: string) {\n super(msg);\n this.outsideOfExtensionContext = true;\n Object.setPrototypeOf(this, OutsideOfExtensionContextError.prototype);\n }\n}\n\n/** @public */\ntype UseHostResponse =\n | { host: undefined; error: Error }\n | { host: Host; error: undefined };\n\n/**\n * Retrieve the {@link @adobe/uix-host#Host} object hosting all extensions inside the current parent provider.\n *\n * @remarks Returns a `{ host, error }` tuple, not the host object directly.\n * @beta\n */\nexport function useHost(): UseHostResponse {\n const extensionsInfo = useContext<ExtensibilityContext>(ExtensionContext);\n\n if (!(extensionsInfo.host instanceof Host)) {\n const error = new OutsideOfExtensionContextError(\n \"Attempt to use extensions outside of ExtensionContext. Wrap extensible part of application with Extensible component.\"\n );\n return {\n host: undefined,\n error,\n };\n }\n return { error: undefined, host: extensionsInfo.host };\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 * @hidden\n */\nimport React, { createContext } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { ExtensionRegistryEndpointRegistration } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\nexport const ExtensibleComponentBoundaryContext = createContext<\n ExtensionRegistryEndpointRegistration[]\n>(null as ExtensionRegistryEndpointRegistration[]);\n\n/** @public */\nexport type ExtensibleComponentProps = PropsWithChildren<{\n extensionPoints: ExtensionRegistryEndpointRegistration[];\n}>;\n\n/**\n * Wrapper that adds an extension point context to subcomponent tree.\n *\n * @public\n */\nexport const ExtensibleComponentBoundary = ({\n extensionPoints,\n children,\n}: ExtensibleComponentProps) => {\n return (\n <ExtensibleComponentBoundaryContext.Provider value={extensionPoints}>\n {children}\n </ExtensibleComponentBoundaryContext.Provider>\n );\n};\n","/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nimport type { PropsWithChildren, ReactElement } from \"react\";\nimport React, { useMemo } from \"react\";\nimport { Extensible } from \"../Extensible\";\nimport {\n combineExtensionsFromProviders,\n InstalledExtensions,\n mutedProvider,\n type ExtensionsProvider,\n type HostConfig,\n type PortOptions,\n type SharedContextValues,\n} from \"@adobe/uix-host\";\nimport {\n ExtensionPointId,\n ExtensionProviderConfig,\n createExtensionManagerExtensionsProvider,\n} from \"./ExtensionManagerProvider\";\nimport { createUrlExtensionsProvider } from \"./UrlExtensionProvider\";\n\n/** @public */\nexport interface ExtensibleDefaultProps extends Omit<HostConfig, \"hostName\"> {\n /**\n * Unique name for identifying this extensible app. May be used as metadata in\n * extension registry in the future.\n */\n appName?: string;\n /**\n * {@inheritDoc HostConfig.guestOptions}\n */\n guestOptions?: PortOptions;\n /**\n * {@inheritDoc HostConfig.sharedContext}\n */\n sharedContext?: SharedContextValues;\n queryString?: string;\n service: string;\n extensionPoint: string;\n version: string;\n disableExtensionManager?: boolean;\n authConfig: {\n imsToken: string;\n imsOrg: string;\n apiKey: string;\n };\n scope?: Record<string, any>;\n experienceShellEnvironment?: \"prod\" | \"stage\";\n extensionsListCallback?: (\n extensions: InstalledExtensions\n ) => InstalledExtensions;\n}\n\n/**\n * ExtensibleWrapper component that provides extension support to React applications.\n * @public\n */\nexport const ExtensibleWrapper = ({\n appName,\n children,\n guestOptions,\n runtimeContainer,\n debug,\n sharedContext,\n experienceShellEnvironment,\n queryString,\n service,\n extensionPoint,\n version,\n disableExtensionManager,\n authConfig,\n scope,\n extensionsListCallback,\n}: PropsWithChildren<ExtensibleDefaultProps>): ReactElement => {\n const defaultExtensionsProvider = useMemo(() => {\n const extensionPointId: ExtensionPointId = {\n service,\n name: extensionPoint,\n version,\n };\n const params: URLSearchParams = new URLSearchParams(queryString ?? \"\");\n const extensionManagerUrlOverride = params.get(\"em\");\n const appRegistryUrlOverride = params.get(\"er\");\n const urlExtensionsProvider: ExtensionsProvider =\n createUrlExtensionsProvider(extensionPointId, queryString);\n const providerConfig: ExtensionProviderConfig = {\n disableExtensionManager,\n };\n\n if (extensionManagerUrlOverride) {\n providerConfig.extensionManagerUrl = extensionManagerUrlOverride;\n }\n\n if (appRegistryUrlOverride) {\n providerConfig.appRegistryUrl = appRegistryUrlOverride;\n }\n\n const extensionManagerExtensionsProvider: ExtensionsProvider =\n createExtensionManagerExtensionsProvider(\n {\n experienceShellEnvironment,\n scope,\n },\n authConfig,\n providerConfig,\n extensionPointId\n );\n\n const extenstions = combineExtensionsFromProviders(\n urlExtensionsProvider,\n mutedProvider(extensionManagerExtensionsProvider)\n );\n\n return extenstions;\n }, [\n experienceShellEnvironment,\n queryString,\n service,\n extensionPoint,\n version,\n disableExtensionManager,\n authConfig,\n scope,\n ]);\n return (\n <Extensible\n extensionsProvider={defaultExtensionsProvider}\n appName={appName}\n runtimeContainer={runtimeContainer}\n debug={debug}\n guestOptions={guestOptions}\n sharedContext={sharedContext}\n extensionsListCallback={extensionsListCallback}\n >\n {children}\n </Extensible>\n );\n};\n\nexport default ExtensibleWrapper;\n","/*************************************************************************\n * ADOBE CONFIDENTIAL\n * ___________________\n *\n * Copyright 2024 Adobe\n * All Rights Reserved.\n *\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n **************************************************************************/\n\nimport {\n createExtensionRegistryAsObjectsProvider,\n ExtensionsProvider,\n InstalledExtensions,\n} from \"@adobe/uix-host\";\n\nconst EXTENSION_MANAGER_URL_PROD = \"https://aemx-mngr.adobe.io\";\nconst EXTENSION_MANAGER_URL_STAGE = \"https://aemx-mngr-stage.adobe.io\";\n\nconst APP_REGISTRY_URL_PROD = \"https://appregistry.adobe.io\";\nconst APP_REGISTRY_URL_STAGE = \"https://appregistry-stage.adobe.io\";\n\n// Extension Manager stores information about extension points that a particular extension implements\n// in the \"extensionPoints\" array of objects of the following \"ExtensionPoint\" type\n// where \"extensionPoint\" is the name of the extension point, for example, \"aem/assets/details/1\"\n// \"url\" is the extension url for the specified extension point\n/** @internal */\ntype ExtensionPoint = {\n extensionPoint: string;\n url: string;\n};\n/** @public */\nexport type ExtensionManagerExtension = {\n id: string;\n name: string;\n title: string;\n description: string;\n status: string;\n supportEmail: string;\n extId: string;\n disabled: boolean;\n extensionPoints: ExtensionPoint[];\n scope: Record<string, unknown>;\n configuration?: Record<string, unknown>;\n};\n\n/** @internal */\ntype AuthEMConfig = {\n schema: \"Bearer\" | \"Basic\";\n imsToken: string;\n};\n/** @public */\nexport interface ExtensionManagerConfig {\n apiKey: string;\n auth: AuthEMConfig;\n service: string;\n extensionPoint: string;\n version: string;\n imsOrg: string;\n baseUrl: string;\n scope?: Record<string, string>;\n}\n\n/**\n * Authentication configuration, including IMS Org ID, access token, and API key\n * @public\n */\nexport interface AuthConfig {\n /** IMS Org ID */\n imsOrg: string;\n /** Access token for the user */\n imsToken: string;\n /** API key */\n apiKey: string;\n}\n\n/**\n * Discovery configuration, including environment and repo Id\n * @public\n */\nexport interface DiscoveryConfig {\n /** Environment level for backend Extension resolution services */\n experienceShellEnvironment?: \"prod\" | \"stage\";\n scope?: Record<string, string>;\n}\n\n/**\n * Extension point ID\n * @public\n */\nexport interface ExtensionPointId {\n /** Service name */\n service: string;\n /** Extension point name */\n name: string;\n /** Extension point version */\n version: string;\n}\n\n/**\n * Sets up new ExtensionsProvider with authentication and discovery information needed to fetch the list of\n * Extensions from AppRegistry and Extension Manager service, along with the query string portion of URL\n * to extract the information about development Extensions\n * @public\n */\nexport interface ExtensionsProviderConfig {\n /** Discovery configuration */\n discoveryConfig: DiscoveryConfig;\n /** Authentication configuration */\n authConfig: AuthConfig;\n /** Extension point ID */\n extensionPointId: ExtensionPointId;\n providerConfig: ExtensionProviderConfig;\n}\n\n/** @public */\nexport interface ExtensionProviderConfig {\n extensionManagerUrl?: string;\n appRegistryUrl?: string;\n disableExtensionManager?: boolean;\n}\n/** @internal */\nexport const getExtensionRegistryBaseUrl = (\n environment: \"prod\" | \"stage\" | undefined,\n registry: string | null\n): string =>\n environment === \"prod\"\n ? APP_REGISTRY_URL_PROD\n : registry ?? APP_REGISTRY_URL_STAGE;\n\n/** @internal */\nexport const getExtensionManagerBaseUrl = (\n environment: \"prod\" | \"stage\" | undefined,\n extensionManager: string | null\n): string =>\n environment === \"prod\"\n ? EXTENSION_MANAGER_URL_PROD\n : extensionManager ?? EXTENSION_MANAGER_URL_STAGE;\n\n/**\n * Extracts programId and envId from the repo value\n * @param repo - the repo value\n * @returns object with programId and envId\n * @internal\n */\nexport function extractProgramIdEnvId(repo: string): {\n programId: string;\n envId: string;\n} {\n const regex: RegExp = /p(\\d+)-e(\\d+)/;\n const match: RegExpMatchArray | null = regex.exec(repo);\n if (!match) {\n throw new Error(\"Error parsing a repo value\");\n }\n\n return {\n programId: match[1],\n envId: match[2],\n };\n}\n\n/**\n * Builds the URL for fetching extensions from the Extension Manager service\n * @param config - the Extension Manager configuration\n * @returns the URL for fetching extensions\n * @internal\n */\nexport function buildExtensionManagerUrl(\n config: ExtensionManagerConfig\n): string {\n const scope = config.scope\n ? Object.fromEntries(\n Object.entries(config.scope).map(([k, v]) => [`scope.${k}`, v])\n )\n : {};\n const extensionPoints: string = `${config.service}/${config.extensionPoint}/${config.version}`;\n const queryParams = new URLSearchParams({\n ...scope,\n extensionPoints,\n });\n\n return `${config.baseUrl}/v2/extensions?${queryParams.toString()}`;\n}\n\n/**\n * @internal\n */\nexport async function fetchExtensionsFromExtensionManager(\n config: ExtensionManagerConfig\n): Promise<ExtensionManagerExtension[]> {\n const resp: Response = await fetch(buildExtensionManagerUrl(config), {\n headers: {\n Authorization: `Bearer ${config.auth.imsToken}`,\n \"x-api-key\": config.apiKey,\n \"x-org-id\": config.imsOrg,\n },\n });\n\n if (resp.status !== 200) {\n throw new Error(\n `Extension Manager returned non-200 response (${\n resp.status\n }): ${await resp.text()}`\n );\n }\n\n return resp.json();\n}\n\n/**\n * Takes an array of extensions from the App Registry, an array of extensions from the Extension Manager, and\n * merges them into a list of Extensions. If an extension is disabled in the Extension Manager, it is removed from\n * the list.\n * Extension list from the App Registry is used as a base.\n * @internal\n */\nexport function mergeExtensions(\n appRegistryExtensions: InstalledExtensions,\n extensionManagerExtensions: ExtensionManagerExtension[],\n extensionPointId: ExtensionPointId\n): InstalledExtensions {\n const mergedExtensions: InstalledExtensions = Object.assign(\n appRegistryExtensions,\n {}\n );\n extensionManagerExtensions.forEach((extension: ExtensionManagerExtension) => {\n if (extension.disabled) {\n // remove disabled extensions\n delete mergedExtensions[extension.name];\n } else {\n const extPoint: ExtensionPoint | undefined =\n extension.extensionPoints.find(\n (_extensionPoint: ExtensionPoint) =>\n _extensionPoint.extensionPoint ===\n `${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`\n );\n if (extPoint) {\n // add a new extension record or replace the existing one by an extension record from Extension Manager\n // extension points are useful for filtering out extensions\n mergedExtensions[extension.name] = {\n id: extension.name,\n url: extPoint.url,\n configuration: extension.configuration,\n extensionPoints: extension.extensionPoints.map(\n (point) => point.extensionPoint\n ),\n };\n } else {\n //this should never happen because we query Extension Manager service for our specific extension point\n console.warn(\n `Extension point ${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version} not found for extension ${extension.name}`\n );\n }\n }\n });\n\n return mergedExtensions;\n}\n\nasync function getExtensionManagerExtensions(\n discoveryConfig: DiscoveryConfig,\n authConfig: AuthConfig,\n providerConfig: ExtensionProviderConfig,\n extensionPointId: ExtensionPointId\n): Promise<InstalledExtensions> {\n const config = {\n apiKey: authConfig.apiKey,\n auth: {\n schema: \"Bearer\",\n imsToken: authConfig.imsToken,\n },\n service: extensionPointId.service,\n extensionPoint: extensionPointId.name,\n version: extensionPointId.version,\n imsOrg: authConfig.imsOrg,\n scope: discoveryConfig.scope,\n };\n\n const appRegistryConfig = {\n ...config,\n baseUrl: getExtensionRegistryBaseUrl(\n discoveryConfig.experienceShellEnvironment,\n providerConfig.appRegistryUrl\n ),\n } as ExtensionManagerConfig;\n const appRegistryExtensionsProvider: ExtensionsProvider =\n createExtensionRegistryAsObjectsProvider(appRegistryConfig);\n\n const extensionManagerConfiguration = {\n ...config,\n baseUrl: getExtensionManagerBaseUrl(\n discoveryConfig.experienceShellEnvironment,\n providerConfig.extensionManagerUrl\n ),\n } as ExtensionManagerConfig;\n const [appRegistryExtensions, extensionManagerExtensions] = await Promise.all(\n [\n appRegistryExtensionsProvider(),\n providerConfig.disableExtensionManager\n ? []\n : fetchExtensionsFromExtensionManager(extensionManagerConfiguration),\n ]\n );\n\n if (providerConfig.disableExtensionManager) {\n return appRegistryExtensions;\n } else {\n return mergeExtensions(\n appRegistryExtensions,\n extensionManagerExtensions,\n extensionPointId\n );\n }\n}\n\n/**\n * Creates an extension manager extension provider\n * @internal\n */\nexport function createExtensionManagerExtensionsProvider(\n discoveryConfig: DiscoveryConfig,\n authConfig: AuthConfig,\n providerConfig: ExtensionProviderConfig,\n extensionPointId: ExtensionPointId\n): ExtensionsProvider {\n return () => {\n return getExtensionManagerExtensions(\n discoveryConfig,\n authConfig,\n providerConfig,\n extensionPointId\n );\n };\n}\n","/*************************************************************************\n * ADOBE CONFIDENTIAL\n * ___________________\n *\n * Copyright 2024 Adobe\n * All Rights Reserved.\n *\n * NOTICE: All information contained herein is, and remains\n * the property of Adobe and its suppliers, if any. The intellectual\n * and technical concepts contained herein are proprietary to Adobe\n * and its suppliers and are protected by all applicable intellectual\n * property laws, including trade secret and copyright laws.\n * Dissemination of this information or reproduction of this material\n * is strictly forbidden unless prior written permission is obtained\n * from Adobe.\n **************************************************************************/\nimport { ExtensionsProvider, InstalledExtensions } from \"@adobe/uix-host\";\nimport { Extension } from \"@adobe/uix-core\";\nimport { ExtensionPointId } from \"./ExtensionManagerProvider\";\nconst EXT_PARAM_PREFIX = \"ext\";\n\n/** @public */\nexport interface ExtUrlParams {\n [key: string]: string;\n}\n\n/**\n * Validates if a URL is safe and only allows HTTP/HTTPS protocols\n * @param url - The URL string to validate\n * @returns true if the URL is valid and uses HTTP/HTTPS protocol, false otherwise\n * @public\n */\nexport function isValidHttpUrl(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n\n return parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\n/**\n * Extracts extension URLs from the query string\n * @internal\n */\nexport function extractExtUrlParams(\n queryString: string | undefined\n): ExtUrlParams {\n if (!queryString) {\n return {};\n }\n const params: URLSearchParams = new URLSearchParams(queryString);\n return Array.from(params.entries()).reduce((extParams, [key, value]) => {\n if (key === EXT_PARAM_PREFIX || key.startsWith(`${EXT_PARAM_PREFIX}.`)) {\n extParams[key] = value;\n }\n return extParams;\n }, {} as ExtUrlParams);\n}\n\n/**\n * Generates an extension ID from the extension URL\n * @internal\n */\nexport function generateExtensionId(extensionUrl: string): string {\n return extensionUrl.replace(/\\W/g, \"_\");\n}\n\n/**\n * Creates an ExtensionsProvider that provides extensions from the URL\n * @internal\n */\nexport function createUrlExtensionsProvider(\n extensionPointId: ExtensionPointId,\n queryString: string | undefined\n): ExtensionsProvider {\n const extUrlParams: ExtUrlParams = extractExtUrlParams(queryString);\n\n const extensionUrls: string[] = Object.keys(extUrlParams)\n .filter(\n (extParam) =>\n extParam === EXT_PARAM_PREFIX ||\n extParam ===\n `${EXT_PARAM_PREFIX}.${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`\n )\n .flatMap((extParam) => {\n const paramValue = extUrlParams[extParam];\n // If it's a single value, return it in an array. If it's already an array, return it as is.\n if (Array.isArray(paramValue)) {\n return paramValue.filter((param) => isValidHttpUrl(param));\n } else {\n return isValidHttpUrl(paramValue) ? [paramValue] : [];\n }\n });\n\n const installedExtensions: InstalledExtensions = extensionUrls\n .map((extensionUrl: string) => {\n return {\n id: generateExtensionId(extensionUrl),\n url: extensionUrl,\n extensionPoints: [\n `${extensionPointId.service}/${extensionPointId.name}/${extensionPointId.version}`,\n ],\n } as Extension;\n })\n .reduce((acc: InstalledExtensions, extension: Extension) => {\n acc[extension.id] = extension;\n return acc;\n }, {} as InstalledExtensions);\n\n return async () => installedExtensions;\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 { useCallback, useContext, useEffect, useMemo, useState } from \"react\";\nimport type {\n GuestConnection,\n GuestApis,\n RemoteGuestApis,\n RemoteGuestApiNS,\n VirtualApi,\n} from \"@adobe/uix-core\";\n\nimport { Host, HostEvents } from \"@adobe/uix-host\";\nimport type { CapabilitySpec, Port } from \"@adobe/uix-host\";\nimport { useHost } from \"./useHost\";\nimport { ExtensibleComponentBoundaryContext } from \"../components/ExtensibleComponentBoundary\";\nimport { ExtensionRegistryEndpointRegistration } from \"@adobe/uix-host\";\n\n/**\n * @internal\n */\nexport interface TypedGuestConnection<T extends GuestApis>\n extends GuestConnection {\n id: GuestConnection[\"id\"];\n apis: RemoteGuestApis<T>;\n}\n\n/** @public */\nexport interface UseExtensionsConfig<\n Incoming extends GuestApis,\n Outgoing extends VirtualApi\n> {\n /**\n * A {@link @adobe/uix-host#CapabilitySpec} describing the namespaced methods\n * extensions must implement to be used by this component.\n *\n * @remarks\n * This declaration is used to filter the extensions that will be\n * returned; if they don't implement those methods, they will be filtered out.\n */\n requires?: CapabilitySpec<Required<Incoming>>;\n /**\n * A namespaced object of methods which extensions will be able to call.\n *\n * @remarks This is the counterpart of `requires`; in `requires`, the you\n * describes methods the extension must implement that your host code will\n * call, and in `provides`, you implement host methods that extensions will be\n * able to call.\n *\n * Most cases for host-side methods will use the state of the component. This\n * can cause unexpected bugs in React if the config callback is run on every\n * render. **useExtensions caches the config callback by default!**\n * So remember to pass a deps array, so that the config callback re-runs under\n * the right conditions.\n */\n provides?: Outgoing;\n /**\n * Sets when re-render is triggered on extension load.\n *\n * @remarks\n * Set to `each` to trigger a component re-render every time an individual\n * extension loads, which may result in multiple UI updates. Set to `all` to\n * wait until all extensions have loaded to re-render the component.\n * @defaultValue \"each\"\n */\n updateOn?: \"each\" | \"all\";\n}\n\n/** @public */\nexport interface UseExtensionsResult<T extends GuestApis> {\n /**\n * A list of loaded guests which implement the methods specified in\n * `requires`, represented as {@link @adobe/uix-host#Port} objects which\n * present methods to be called.\n */\n extensions: TypedGuestConnection<T>[];\n /**\n * This is `true` until all extensions are loaded. Use for rendering spinners\n * or other intermediate UI.\n */\n loading: boolean;\n /**\n * Populated with an Error if there were any problems during the load process.\n */\n error?: Error;\n}\n\nconst NO_EXTENSIONS: [] = [];\n\n/**\n * Fetch extensions which implement an API, provide them methods, and use them.\n *\n * @remarks `useExtensions` does three things at once:\n * - Gets all extensions which implement the APIs described in the `require` field\n * - Exposes any functions defined in the `provide` field to those extensions\n * - Returns an object whose `extensions` property is a list of `Port` objects representing those extensions\n *\n * useExtensions will trigger a re-render when extensions load. You can choose whether it triggers that rerender as each extension loads, or only after all extensions have loaded.\n * @public\n */\nexport function useExtensions<\n Incoming extends GuestApis,\n Outgoing extends VirtualApi\n>(\n configFactory: (host: Host) => UseExtensionsConfig<Incoming, Outgoing>,\n deps: unknown[] = []\n): UseExtensionsResult<Incoming> {\n const { host, error: contextError } = useHost();\n\n // All hooks must be called unconditionally before any early return.\n const [hostError, setHostError] = useState<Error>();\n const extensionPoints = useContext(ExtensibleComponentBoundaryContext);\n const boundryExtensionPointsAsString = extensionPoints?.map(\n ({\n service,\n extensionPoint,\n version,\n }: ExtensionRegistryEndpointRegistration) =>\n `${service}/${extensionPoint}/${version}`\n );\n const baseDeps = [host, ...deps];\n const {\n requires,\n provides,\n updateOn = \"each\",\n } = useMemo(\n () =>\n (host ? configFactory(host) : {}) as UseExtensionsConfig<\n Incoming,\n Outgoing\n >,\n baseDeps\n );\n\n const getExtensions = useCallback(() => {\n if (!host) return NO_EXTENSIONS;\n const newExtensions = [];\n const guests = host.getLoadedGuests(requires);\n\n // Extension filtering: If the boundary is provided, only return extensions which have extensionPoint\n // specified in a provided boundry. Otherwise no filtering is done.\n for (const guest of guests) {\n const allExtensionPoints: string[] =\n getAllExtensionPointsFromGuest(guest);\n\n if (\n !boundryExtensionPointsAsString ||\n !allExtensionPoints.length ||\n isGuestExtensionPointInBoundary(\n boundryExtensionPointsAsString,\n allExtensionPoints\n )\n ) {\n newExtensions.push(guest as unknown as TypedGuestConnection<Incoming>);\n }\n }\n return newExtensions.length === 0 ? NO_EXTENSIONS : newExtensions;\n }, [...baseDeps, requires]);\n\n const subscribe = useCallback(\n (handler: EventListener) => {\n if (!host) return () => {};\n const eventName = updateOn === \"all\" ? \"loadallguests\" : \"guestload\";\n host.addEventListener(eventName, handler);\n\n return () => {\n host.removeEventListener(eventName, handler);\n };\n },\n [...baseDeps, updateOn]\n );\n\n const subscribeToUnload = useCallback((handler: EventListener) => {\n if (!host) return () => {};\n host.addEventListener(\"guestunload\", handler);\n\n return () => {\n host.removeEventListener(\"guestunload\", handler);\n };\n }, baseDeps);\n\n const [extensions, setExtensions] =\n useState<TypedGuestConnection<Incoming>[]>(NO_EXTENSIONS);\n\n useEffect(() => {\n // Sync current guests immediately when host becomes available, then subscribe to future loads.\n setExtensions(getExtensions());\n return subscribe(() => setExtensions(getExtensions()));\n }, [subscribe]);\n\n const unloadExtentionCallback = (e: CustomEvent) => {\n const eventDetail = e.detail;\n const guest = eventDetail.guest as Port<GuestApis>;\n\n if (guest && guest.id) {\n setExtensions((prevExtensions) => {\n const filtered = prevExtensions.filter(\n (ext) => ext.id !== guest.id || ext.url !== guest.url\n );\n return filtered.length === 0 ? NO_EXTENSIONS : filtered;\n });\n }\n };\n\n useEffect(() => {\n return subscribeToUnload(unloadExtentionCallback);\n }, [subscribeToUnload]);\n\n useEffect(() => {\n for (const guest of extensions) {\n if (provides) {\n guest.provide(provides);\n }\n }\n }, [provides, extensions]);\n\n useEffect(() => {\n if (!host) return;\n return host.addEventListener(\n \"error\",\n (event: Extract<HostEvents, { detail: { error: Error } }>) =>\n setHostError(event.detail.error)\n );\n }, baseDeps);\n\n if (contextError) {\n return {\n extensions: NO_EXTENSIONS,\n loading: false,\n error: contextError,\n };\n }\n\n return {\n extensions,\n loading: extensions.length === 0 ? false : host.loading,\n error: hostError,\n };\n}\n\n/**\n * Each extension/guest can have\n * 1. `extensioPoints` field as an array of strings\n * 2. Metadata with array of extensionPoints. If the metadata is present, we need to use it for fitering the extensions.\n * Returns cumulative extension points.\n * @param guest\n * @returns array of extension points as strings\n */\nfunction getAllExtensionPointsFromGuest(guest: Port<GuestApis>): string[] {\n try {\n const guestExtensionPointsFromMetadata = guest.metadata?.extensions?.map(\n (extension: { extensionPoint: string }) => extension?.extensionPoint\n );\n const allExtensionPoints = [\n ...(guest.extensionPoints || []),\n ...(guestExtensionPointsFromMetadata || []),\n ];\n return allExtensionPoints;\n } catch {\n console.error(\n \"Error occurred while getting extension points from guest and metadata. Extension boundaries will not be effective.\"\n );\n return [];\n }\n}\n\nfunction isGuestExtensionPointInBoundary(\n boundryExtensionPointsAsString: string[],\n guestExtensionPoints: string[]\n) {\n return (\n boundryExtensionPointsAsString?.length &&\n guestExtensionPoints?.length &&\n guestExtensionPoints.some((extensionPoint) =>\n boundryExtensionPointsAsString.includes(extensionPoint)\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 { useContext } from \"react\";\nimport {\n ExtensionContext,\n ExtensibilityContext,\n} from \"../extension-context.js\";\n\n/**\n * Indicates if external extensions provider was processed. Returns true after passing extension list to the Host.\n *\n * @beta\n */\nexport function useExtensionListFetched(): boolean {\n const extensionsInfo = useContext<ExtensibilityContext>(ExtensionContext);\n\n return extensionsInfo.extensionListFetched;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/uix-host-react",
|
|
3
|
-
"version": "1.1.10
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
],
|
|
21
21
|
"bugs": "https://github.com/adobe/uix-sdk/issues",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@adobe/uix-core": "^1.1.10
|
|
24
|
-
"@adobe/uix-host": "^1.1.10
|
|
23
|
+
"@adobe/uix-core": "^1.1.10",
|
|
24
|
+
"@adobe/uix-host": "^1.1.10"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@swc/jest": "^0.2.29",
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 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 React from "react";
|
|
14
|
+
import { render, waitFor, cleanup } from "@testing-library/react";
|
|
15
|
+
import { Host } from "@adobe/uix-host";
|
|
16
|
+
import { GuestUIFrame } from "./GuestUIFrame";
|
|
17
|
+
import { useHost } from "../hooks/useHost";
|
|
18
|
+
|
|
19
|
+
jest.mock("@adobe/uix-host", () => ({
|
|
20
|
+
...jest.requireActual("@adobe/uix-host"),
|
|
21
|
+
Host: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
jest.mock("../hooks/useHost");
|
|
24
|
+
|
|
25
|
+
const mockedUseHost = jest.mocked(useHost);
|
|
26
|
+
|
|
27
|
+
interface MockGuest {
|
|
28
|
+
id: string;
|
|
29
|
+
url: URL;
|
|
30
|
+
provide: jest.Mock;
|
|
31
|
+
attachUI: jest.Mock;
|
|
32
|
+
addEventListener: jest.Mock;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const createGuest = (id = "guest-1"): MockGuest => ({
|
|
36
|
+
id,
|
|
37
|
+
url: new URL("https://example.com/guest/"),
|
|
38
|
+
provide: jest.fn().mockName("guest.provide"),
|
|
39
|
+
attachUI: jest
|
|
40
|
+
.fn()
|
|
41
|
+
.mockName("guest.attachUI")
|
|
42
|
+
.mockResolvedValue({
|
|
43
|
+
tunnel: { destroy: jest.fn() },
|
|
44
|
+
}),
|
|
45
|
+
addEventListener: jest
|
|
46
|
+
.fn()
|
|
47
|
+
.mockName("guest.addEventListener")
|
|
48
|
+
.mockReturnValue(jest.fn()),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const mockHostWithGuest = (guest?: MockGuest) =>
|
|
52
|
+
({
|
|
53
|
+
guests: {
|
|
54
|
+
get: jest.fn().mockReturnValue(guest),
|
|
55
|
+
},
|
|
56
|
+
} as unknown as Host);
|
|
57
|
+
|
|
58
|
+
describe("GuestUIFrame", () => {
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
cleanup();
|
|
61
|
+
jest.clearAllMocks();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renders null when no host is available", () => {
|
|
65
|
+
mockedUseHost.mockReturnValue({ host: undefined, error: undefined });
|
|
66
|
+
|
|
67
|
+
const { container } = render(
|
|
68
|
+
<GuestUIFrame guestId="guest-1" src="index.html" />
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(container.querySelector("iframe")).toBeNull();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("renders null without crashing when the guest is not found", () => {
|
|
75
|
+
mockedUseHost.mockReturnValue({
|
|
76
|
+
host: mockHostWithGuest(undefined),
|
|
77
|
+
error: undefined,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(() =>
|
|
81
|
+
render(<GuestUIFrame guestId="missing-guest" src="index.html" />)
|
|
82
|
+
).not.toThrow();
|
|
83
|
+
|
|
84
|
+
const { container } = render(
|
|
85
|
+
<GuestUIFrame guestId="missing-guest" src="index.html" />
|
|
86
|
+
);
|
|
87
|
+
expect(container.querySelector("iframe")).toBeNull();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("renders an iframe with a resolved src and name when the guest exists", () => {
|
|
91
|
+
const guest = createGuest("guest-1");
|
|
92
|
+
mockedUseHost.mockReturnValue({
|
|
93
|
+
host: mockHostWithGuest(guest),
|
|
94
|
+
error: undefined,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const { container } = render(
|
|
98
|
+
<GuestUIFrame guestId="guest-1" src="page.html" />
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const iframe = container.querySelector("iframe");
|
|
102
|
+
expect(iframe).not.toBeNull();
|
|
103
|
+
expect(iframe?.getAttribute("src")).toBe(
|
|
104
|
+
"https://example.com/guest/page.html"
|
|
105
|
+
);
|
|
106
|
+
expect(iframe?.getAttribute("name")).toBe("uix-guest-guest-1");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("attaches the UI and invokes onConnect once connected", async () => {
|
|
110
|
+
const guest = createGuest("guest-1");
|
|
111
|
+
mockedUseHost.mockReturnValue({
|
|
112
|
+
host: mockHostWithGuest(guest),
|
|
113
|
+
error: undefined,
|
|
114
|
+
});
|
|
115
|
+
const onConnect = jest.fn();
|
|
116
|
+
|
|
117
|
+
render(
|
|
118
|
+
<GuestUIFrame guestId="guest-1" src="page.html" onConnect={onConnect} />
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
await waitFor(() => {
|
|
122
|
+
expect(guest.attachUI).toHaveBeenCalled();
|
|
123
|
+
expect(onConnect).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("provides host methods to the guest when methods are passed", async () => {
|
|
128
|
+
const guest = createGuest("guest-1");
|
|
129
|
+
mockedUseHost.mockReturnValue({
|
|
130
|
+
host: mockHostWithGuest(guest),
|
|
131
|
+
error: undefined,
|
|
132
|
+
});
|
|
133
|
+
const methods = { ns: { doThing: jest.fn() } };
|
|
134
|
+
|
|
135
|
+
render(
|
|
136
|
+
<GuestUIFrame guestId="guest-1" src="page.html" methods={methods} />
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
await waitFor(() => {
|
|
140
|
+
expect(guest.provide).toHaveBeenCalledWith(methods);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("registers a guestresize listener when onResize is provided", () => {
|
|
145
|
+
const guest = createGuest("guest-1");
|
|
146
|
+
mockedUseHost.mockReturnValue({
|
|
147
|
+
host: mockHostWithGuest(guest),
|
|
148
|
+
error: undefined,
|
|
149
|
+
});
|
|
150
|
+
const onResize = jest.fn();
|
|
151
|
+
|
|
152
|
+
render(
|
|
153
|
+
<GuestUIFrame guestId="guest-1" src="page.html" onResize={onResize} />
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(guest.addEventListener).toHaveBeenCalledWith(
|
|
157
|
+
"guestresize",
|
|
158
|
+
expect.any(Function)
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("calls onConnectionError when the connection fails", async () => {
|
|
163
|
+
const guest = createGuest("guest-1");
|
|
164
|
+
guest.attachUI.mockRejectedValue(new Error("boom"));
|
|
165
|
+
mockedUseHost.mockReturnValue({
|
|
166
|
+
host: mockHostWithGuest(guest),
|
|
167
|
+
error: undefined,
|
|
168
|
+
});
|
|
169
|
+
const onConnectionError = jest.fn();
|
|
170
|
+
|
|
171
|
+
render(
|
|
172
|
+
<GuestUIFrame
|
|
173
|
+
guestId="guest-1"
|
|
174
|
+
src="page.html"
|
|
175
|
+
onConnectionError={onConnectionError}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
expect(onConnectionError).toHaveBeenCalledWith(expect.any(Error));
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -95,14 +95,11 @@ export const GuestUIFrame = ({
|
|
|
95
95
|
}: GuestUIProps) => {
|
|
96
96
|
const ref = useRef<HTMLIFrameElement>();
|
|
97
97
|
const { host } = useHost();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
const guest = host.guests.get(guestId);
|
|
102
|
-
const frameUrl = new URL(src, guest.url.href);
|
|
98
|
+
const guest = host ? host.guests.get(guestId) : undefined;
|
|
99
|
+
const guestId_ = guest?.id;
|
|
103
100
|
|
|
104
101
|
useEffect(() => {
|
|
105
|
-
if (ref.current) {
|
|
102
|
+
if (ref.current && guest) {
|
|
106
103
|
let mounted = true;
|
|
107
104
|
let connection: CrossRealmObject<VirtualApi>;
|
|
108
105
|
const connectionFrame = ref.current;
|
|
@@ -142,10 +139,10 @@ export const GuestUIFrame = ({
|
|
|
142
139
|
}
|
|
143
140
|
};
|
|
144
141
|
}
|
|
145
|
-
}, [
|
|
142
|
+
}, [guestId_]);
|
|
146
143
|
|
|
147
144
|
useEffect(() => {
|
|
148
|
-
if (ref.current && onResize) {
|
|
145
|
+
if (ref.current && guest && onResize) {
|
|
149
146
|
const currentFrame = ref.current;
|
|
150
147
|
return guest.addEventListener(
|
|
151
148
|
"guestresize",
|
|
@@ -156,7 +153,12 @@ export const GuestUIFrame = ({
|
|
|
156
153
|
}
|
|
157
154
|
);
|
|
158
155
|
}
|
|
159
|
-
}, [ref.current,
|
|
156
|
+
}, [ref.current, guestId_, onResize]);
|
|
157
|
+
|
|
158
|
+
if (!host || !guest) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const frameUrl = new URL(src, guest.url.href);
|
|
160
162
|
|
|
161
163
|
return (
|
|
162
164
|
<iframe
|