@adobe/uix-host-react 1.1.12-nightly.20260920 → 1.1.12-nightly.20260922
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Extensible.d.ts","sourceRoot":"","sources":["../../src/components/Extensible.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA+C,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAIzB,cAAc;AACd,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;IACnE;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,kBAAkB,EAAE,kBAAkB,CAAC;IACvC;;OAEG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B;;OAEG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,sBAAsB,CAAC,EAAE,CACvB,UAAU,EAAE,mBAAmB,KAC5B,mBAAmB,CAAC;CAC1B;AAoDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,aAAa,EACb,sBAAsB,GACvB,EAAE,iBAAiB,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"Extensible.d.ts","sourceRoot":"","sources":["../../src/components/Extensible.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA+C,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAIzB,cAAc;AACd,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;IACnE;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,kBAAkB,EAAE,kBAAkB,CAAC;IACvC;;OAEG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B;;OAEG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,sBAAsB,CAAC,EAAE,CACvB,UAAU,EAAE,mBAAmB,KAC5B,mBAAmB,CAAC;CAC1B;AAoDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,aAAa,EACb,sBAAsB,GACvB,EAAE,iBAAiB,CAAC,eAAe,CAAC,qBAoHpC;AACD,eAAe,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -108,10 +108,14 @@ function Extensible({
|
|
|
108
108
|
console.error(msg, error, extensions, guestOptions);
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
|
-
if (!
|
|
111
|
+
if (!extensionListFetched) {
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
+
const hasExtensions = !!extensions && !!Object.keys(extensions).length;
|
|
114
115
|
const loadExtensions = (hostInstance) => {
|
|
116
|
+
if (!hasExtensions) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
115
119
|
hostInstance.load(extensions, guestOptions).catch(logError("Load of extensions failed!"));
|
|
116
120
|
};
|
|
117
121
|
const sharedContextChanged = prevSharedContext.current !== JSON.stringify(sharedContext);
|
|
@@ -135,7 +139,7 @@ function Extensible({
|
|
|
135
139
|
} else {
|
|
136
140
|
loadExtensions(host);
|
|
137
141
|
}
|
|
138
|
-
}, [debug, hostName, runtimeContainer, extensions]);
|
|
142
|
+
}, [debug, hostName, runtimeContainer, extensions, extensionListFetched]);
|
|
139
143
|
const contextValue = React.useMemo(
|
|
140
144
|
() => ({ host, extensionListFetched }),
|
|
141
145
|
[host, extensionListFetched]
|
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 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"]}
|
|
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":";AAYA,cAAc;;;ACAd,OAAO,SAAS,UAAU,WAAW,QAAQ,eAAe;AAS5D,SAAS,YAAY;;;ACNrB,SAAS,qBAAqB;AAgBvB,IAAM,mBAAmB;AAAA,EAC9B,CAAC;AACH;;;ADeA,SAAS,uBACP,MACA,MACA;AACA,QAAM,OAAO,OAAO,KAAK,IAAI,EAAE,KAAK;AACpC,QAAM,OAAO,OAAO,KAAK,IAAI,EAAE,KAAK;AAEpC,MAAI,KAAK,WAAW,KAAK,QAAQ;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,cAAc;AAElB,OAAK,QAAQ,CAAC,OAAO;AACnB,QAAI,aAAa;AACf;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,EAAE;AACpB,UAAM,OAAO,KAAK,EAAE;AAEpB,QAAI,OAAO,SAAS,OAAO,MAAM;AAC/B,oBAAc;AACd;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AACxD,UAAI,SAAS,MAAM;AACjB,sBAAc;AACd;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AACxD,UACE,KAAK,QAAQ,KAAK,OAClB,KAAK,UAAU,KAAK,eAAe,MACjC,KAAK,UAAU,KAAK,eAAe,KACrC,KAAK,UAAU,KAAK,aAAa,MAC/B,KAAK,UAAU,KAAK,aAAa,GACnC;AACA,sBAAc;AACd;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAkBO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,QAAM,WAAW,WAAW,OAAO,SAAS,QAAQ;AAEpD,QAAM,CAAC,YAAY,aAAa,IAAI,SAA8B,CAAC,CAAC;AACpE,QAAM,CAAC,sBAAsB,uBAAuB,IAClD,SAAkB,KAAK;AACzB,QAAM,oBAAoB,OAAO,KAAK,UAAU,aAAa,CAAC;AAC9D,YAAU,MAAM;AACd,QAAI,YAAY;AAEhB,uBAAmB,EAChB,KAAK,CAAC,WAAgC;AACrC,UAAI,WAAW;AACb;AAAA,MACF;AACA,oBAAc,CAAC,SAAS;AACtB,YAAI,gBAAgB;AAEpB,YAAI,0BAA0B,QAAQ;AACpC,0BAAgB,uBAAuB,aAAa;AAAA,QACtD;AAEA,cAAM,eAAe,uBAAuB,MAAM,aAAa;AAE/D,YAAI,cAAc;AAChB,iBAAO;AAAA,QACT,OAAO;AACL,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH,CAAC,EACA,MAAM,CAAC,MAAuB;AAC7B,UAAI,CAAC,WAAW;AACd,gBAAQ,MAAM,uCAAuC,CAAC;AAAA,MACxD;AAAA,IACF,CAAC,EACA,QAAQ,MAAM;AACb,UAAI,CAAC,WAAW;AACd,gCAAwB,IAAI;AAAA,MAC9B;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,oBAAoB,sBAAsB,CAAC;AAE/C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAe;AACvC,QAAM,UAAU,OAAa;AAE7B,YAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,QAAQ,SAAS;AACnB,gBAAQ,QAAQ,OAAO,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACvC,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,aAAS,SAAS,KAAa;AAC7B,aAAO,CAAC,MAAuB;AAC7B,cAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,gBAAQ,MAAM,KAAK,OAAO,YAAY,YAAY;AAAA,MACpD;AAAA,IACF;AAEA,QAAI,CAAC,sBAAsB;AACzB;AAAA,IACF;AAEA,UAAM,gBAAgB,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,KAAK,UAAU,EAAE;AAEhE,UAAM,iBAAiB,CAAC,iBAAuB;AAC7C,UAAI,CAAC,eAAe;AAClB;AAAA,MACF;AACA,mBACG,KAAK,YAAY,YAAY,EAC7B,MAAM,SAAS,4BAA4B,CAAC;AAAA,IACjD;AAEA,UAAM,uBACJ,kBAAkB,YAAY,KAAK,UAAU,aAAa;AAE5D,QAAI,sBAAsB;AACxB,wBAAkB,UAAU,KAAK,UAAU,aAAa;AAAA,IAC1D;AACA,QAAI,CAAC,QAAQ,sBAAsB;AACjC,UAAI,QAAQ,SAAS;AACnB,gBAAQ,QAAQ,OAAO,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACzC;AACA,YAAM,UAAU,IAAI,KAAK;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,cAAQ,UAAU;AAClB,cAAQ,OAAO;AACf,qBAAe,OAAO;AAAA,IACxB,OAAO;AACL,qBAAe,IAAI;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,OAAO,UAAU,kBAAkB,YAAY,oBAAoB,CAAC;AAExE,QAAM,eAAe;AAAA,IACnB,OAAO,EAAE,MAAM,qBAAqB;AAAA,IACpC,CAAC,MAAM,oBAAoB;AAAA,EAC7B;AAEA,SACE,oCAAC,iBAAiB,UAAjB,EAA0B,OAAO,gBAC/B,QACH;AAEJ;;;AElOA,OAAOA,UAAS,aAAAC,YAAW,UAAAC,eAAc;;;ACDzC,SAAS,kBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAMd,IAAM,iCAAN,cAA6C,MAAM;AAAA,EAExD,YAAY,KAAa;AACvB,UAAM,GAAG;AACT,SAAK,4BAA4B;AACjC,WAAO,eAAe,MAAM,+BAA+B,SAAS;AAAA,EACtE;AACF;AAaO,SAAS,UAA2B;AACzC,QAAM,iBAAiB,WAAiC,gBAAgB;AAExE,MAAI,EAAE,eAAe,gBAAgBA,QAAO;AAC1C,UAAM,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,QAAW,MAAM,eAAe,KAAK;AACvD;;;ADnCA,SAAS,kBAAkB,2BAA2B;AAiDtD,IAAM,qBAAiC;AAAA,EACrC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;AAEA,IAAM,iBAAiB;AAOhB,IAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,MAAoB;AAClB,QAAM,MAAMD,QAA0B;AACtC,QAAM,EAAE,KAAK,IAAI,QAAQ;AACzB,QAAM,QAAQ,OAAO,KAAK,OAAO,IAAI,OAAO,IAAI;AAChD,QAAM,WAAW,+BAAO;AAExB,EAAAD,WAAU,MAAM;AACd,QAAI,IAAI,WAAW,OAAO;AACxB,UAAI,UAAU;AACd,UAAI;AACJ,YAAM,kBAAkB,IAAI;AAC5B,UAAI,SAAS;AACX,cAAM,QAAQ,OAAO;AAAA,MACvB;AACA,YAAM,aAAa,MAAM,SAAS,iBAAiB,cAAc;AACjE,iBACG,KAAK,CAAC,MAAM;AACX,qBAAa;AACb,YAAI,CAAC,SAAS;AACZ,YAAE,OAAO,QAAQ;AAAA,QACnB,WAAW,WAAW;AACpB,oBAAU;AAAA,QACZ;AAAA,MACF,CAAC,EACA,MAAM,CAAC,UAAiB;AACvB,YAAI,WAAW,CAAC,cAAc,oBAAoB,IAAI,SAAS;AAC7D,gBAAM,aAAa,IAAI;AAAA,YACrB,mCACG,SAAS,MAAM,SAAU;AAAA,UAE9B;AACA,iBAAO,OAAO,YAAY;AAAA,YACxB,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,UACF,CAAC;AACD,cAAI;AAAmB,8BAAkB,UAAU;AAAA,QACrD;AAAA,MACF,CAAC;AACH,aAAO,MAAM;AACX,kBAAU;AACV,YAAI,YAAY;AACd,qBAAW,OAAO,QAAQ;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,EAAAA,WAAU,MAAM;AACd,QAAI,IAAI,WAAW,SAAS,UAAU;AACpC,YAAM,eAAe,IAAI;AACzB,aAAO,MAAM;AAAA,QACX;AAAA,QACA,CAAC,EAAE,QAAQ,EAAE,WAAW,QAAQ,WAAW,EAAE,MAAM;AACjD,cAAI,UAAU,OAAO,MAAM,MAAM,WAAW,cAAc;AACxD,qBAAS,UAAU;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAI,SAAS,UAAU,QAAQ,CAAC;AAEpC,MAAI,CAAC,QAAQ,CAAC,OAAO;AACnB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI;AAE5C,SACE,gBAAAD,OAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,KAAK,SAAS;AAAA,MACd,MAAM,aAAa,MAAM;AAAA,MACzB,SACE,UACI,iBAAiB,gBAAgB,OAAO,EAAE,KAAK,GAAG,IAClD;AAAA,MAEN,OACE,QACI,EAAE,GAAG,OAAO,GAAG,mBAAmB,MAAM,IACxC,mBAAmB;AAAA,MAExB,GAAG;AAAA,MACH,GAAG;AAAA;AAAA,EACN;AAEJ;;;AEvKA,OAAOA,UAAS,iBAAAI,sBAAqB;AAO9B,IAAM,qCAAqCA,eAEhD,IAA+C;AAY1C,IAAM,8BAA8B,CAAC;AAAA,EAC1C;AAAA,EACA;AACF,MAAgC;AAC9B,SACE,gBAAAJ,OAAA,cAAC,mCAAmC,UAAnC,EAA4C,OAAO,mBACjD,QACH;AAEJ;;;ACjCA,OAAOA,UAAS,WAAAK,gBAAe;AAE/B;AAAA,EACE;AAAA,EAEA;AAAA,OAKK;;;ACLP;AAAA,EACE;AAAA,OAGK;AAEP,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AAEpC,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAsGxB,IAAM,8BAA8B,CACzC,aACA,aAEA,gBAAgB,SACZ,wBACA,8BAAY;AAGX,IAAM,6BAA6B,CACxC,aACA,qBAEA,gBAAgB,SACZ,6BACA,8CAAoB;AAQnB,SAAS,sBAAsB,MAGpC;AACA,QAAM,QAAgB;AACtB,QAAM,QAAiC,MAAM,KAAK,IAAI;AACtD,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,WAAW,MAAM,CAAC;AAAA,IAClB,OAAO,MAAM,CAAC;AAAA,EAChB;AACF;AAQO,SAAS,yBACd,QACQ;AACR,QAAM,QAAQ,OAAO,QACjB,OAAO;AAAA,IACL,OAAO,QAAQ,OAAO,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,CAAC;AAAA,EAChE,IACA,CAAC;AACL,QAAM,kBAA0B,GAAG,OAAO,WAAW,OAAO,kBAAkB,OAAO;AACrF,QAAM,cAAc,IAAI,gBAAgB;AAAA,IACtC,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO,GAAG,OAAO,yBAAyB,YAAY,SAAS;AACjE;AAKA,eAAsB,oCACpB,QACsC;AACtC,QAAM,OAAiB,MAAM,MAAM,yBAAyB,MAAM,GAAG;AAAA,IACnE,SAAS;AAAA,MACP,eAAe,UAAU,OAAO,KAAK;AAAA,MACrC,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,IACrB;AAAA,EACF,CAAC;AAED,MAAI,KAAK,WAAW,KAAK;AACvB,UAAM,IAAI;AAAA,MACR,gDACE,KAAK,YACD,MAAM,KAAK,KAAK;AAAA,IACxB;AAAA,EACF;AAEA,SAAO,KAAK,KAAK;AACnB;AASO,SAAS,gBACd,uBACA,4BACA,kBACqB;AACrB,QAAM,mBAAwC,OAAO;AAAA,IACnD;AAAA,IACA,CAAC;AAAA,EACH;AACA,6BAA2B,QAAQ,CAAC,cAAyC;AAC3E,QAAI,UAAU,UAAU;AAEtB,aAAO,iBAAiB,UAAU,IAAI;AAAA,IACxC,OAAO;AACL,YAAM,WACJ,UAAU,gBAAgB;AAAA,QACxB,CAAC,oBACC,gBAAgB,mBAChB,GAAG,iBAAiB,WAAW,iBAAiB,QAAQ,iBAAiB;AAAA,MAC7E;AACF,UAAI,UAAU;AAGZ,yBAAiB,UAAU,IAAI,IAAI;AAAA,UACjC,IAAI,UAAU;AAAA,UACd,KAAK,SAAS;AAAA,UACd,eAAe,UAAU;AAAA,UACzB,iBAAiB,UAAU,gBAAgB;AAAA,YACzC,CAAC,UAAU,MAAM;AAAA,UACnB;AAAA,QACF;AAAA,MACF,OAAO;AAEL,gBAAQ;AAAA,UACN,mBAAmB,iBAAiB,WAAW,iBAAiB,QAAQ,iBAAiB,mCAAmC,UAAU;AAAA,QACxI;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,eAAe,8BACb,iBACA,YACA,gBACA,kBAC8B;AAC9B,QAAM,SAAS;AAAA,IACb,QAAQ,WAAW;AAAA,IACnB,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,UAAU,WAAW;AAAA,IACvB;AAAA,IACA,SAAS,iBAAiB;AAAA,IAC1B,gBAAgB,iBAAiB;AAAA,IACjC,SAAS,iBAAiB;AAAA,IAC1B,QAAQ,WAAW;AAAA,IACnB,OAAO,gBAAgB;AAAA,EACzB;AAEA,QAAM,oBAAoB;AAAA,IACxB,GAAG;AAAA,IACH,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,EACF;AACA,QAAM,gCACJ,yCAAyC,iBAAiB;AAE5D,QAAM,gCAAgC;AAAA,IACpC,GAAG;AAAA,IACH,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,EACF;AACA,QAAM,CAAC,uBAAuB,0BAA0B,IAAI,MAAM,QAAQ;AAAA,IACxE;AAAA,MACE,8BAA8B;AAAA,MAC9B,eAAe,0BACX,CAAC,IACD,oCAAoC,6BAA6B;AAAA,IACvE;AAAA,EACF;AAEA,MAAI,eAAe,yBAAyB;AAC1C,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,yCACd,iBACA,YACA,gBACA,kBACoB;AACpB,SAAO,MAAM;AACX,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACjUA,IAAM,mBAAmB;AAalB,SAAS,eAAe,KAAsB;AACnD,MAAI;AACF,UAAM,YAAY,IAAI,IAAI,GAAG;AAE7B,WAAO,UAAU,aAAa,WAAW,UAAU,aAAa;AAAA,EAClE,QAAE;AACA,WAAO;AAAA,EACT;AACF;AAMO,SAAS,oBACd,aACc;AACd,MAAI,CAAC,aAAa;AAChB,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAA0B,IAAI,gBAAgB,WAAW;AAC/D,SAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,KAAK,MAAM;AACtE,QAAI,QAAQ,oBAAoB,IAAI,WAAW,GAAG,mBAAmB,GAAG;AACtE,gBAAU,GAAG,IAAI;AAAA,IACnB;AACA,WAAO;AAAA,EACT,GAAG,CAAC,CAAiB;AACvB;AAMO,SAAS,oBAAoB,cAA8B;AAChE,SAAO,aAAa,QAAQ,OAAO,GAAG;AACxC;AAMO,SAAS,4BACd,kBACA,aACoB;AACpB,QAAM,eAA6B,oBAAoB,WAAW;AAElE,QAAM,gBAA0B,OAAO,KAAK,YAAY,EACrD;AAAA,IACC,CAAC,aACC,aAAa,oBACb,aACE,GAAG,oBAAoB,iBAAiB,WAAW,iBAAiB,QAAQ,iBAAiB;AAAA,EACnG,EACC,QAAQ,CAAC,aAAa;AACrB,UAAM,aAAa,aAAa,QAAQ;AAExC,QAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,aAAO,WAAW,OAAO,CAAC,UAAU,eAAe,KAAK,CAAC;AAAA,IAC3D,OAAO;AACL,aAAO,eAAe,UAAU,IAAI,CAAC,UAAU,IAAI,CAAC;AAAA,IACtD;AAAA,EACF,CAAC;AAEH,QAAM,sBAA2C,cAC9C,IAAI,CAAC,iBAAyB;AAC7B,WAAO;AAAA,MACL,IAAI,oBAAoB,YAAY;AAAA,MACpC,KAAK;AAAA,MACL,iBAAiB;AAAA,QACf,GAAG,iBAAiB,WAAW,iBAAiB,QAAQ,iBAAiB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF,CAAC,EACA,OAAO,CAAC,KAA0B,cAAyB;AAC1D,QAAI,UAAU,EAAE,IAAI;AACpB,WAAO;AAAA,EACT,GAAG,CAAC,CAAwB;AAE9B,SAAO,YAAY;AACrB;;;AF9CO,IAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA+D;AAC7D,QAAM,4BAA4BA,SAAQ,MAAM;AAC9C,UAAM,mBAAqC;AAAA,MACzC;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AACA,UAAM,SAA0B,IAAI,gBAAgB,oCAAe,EAAE;AACrE,UAAM,8BAA8B,OAAO,IAAI,IAAI;AACnD,UAAM,yBAAyB,OAAO,IAAI,IAAI;AAC9C,UAAM,wBACJ,4BAA4B,kBAAkB,WAAW;AAC3D,UAAM,iBAA0C;AAAA,MAC9C;AAAA,IACF;AAEA,QAAI,6BAA6B;AAC/B,qBAAe,sBAAsB;AAAA,IACvC;AAEA,QAAI,wBAAwB;AAC1B,qBAAe,iBAAiB;AAAA,IAClC;AAEA,UAAM,qCACJ;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEF,UAAM,cAAc;AAAA,MAClB;AAAA,MACA,cAAc,kCAAkC;AAAA,IAClD;AAEA,WAAO;AAAA,EACT,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,SACE,gBAAAL,OAAA;AAAA,IAAC;AAAA;AAAA,MACC,oBAAoB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,IAEC;AAAA,EACH;AAEJ;;;AGtIA,SAAS,aAAa,cAAAM,aAAY,aAAAL,YAAW,WAAAI,UAAS,YAAAE,iBAAgB;AAoFtE,IAAM,gBAAoB,CAAC;AAapB,SAAS,cAId,eACA,OAAkB,CAAC,GACY;AAC/B,QAAM,EAAE,MAAM,OAAO,aAAa,IAAI,QAAQ;AAG9C,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAgB;AAClD,QAAM,kBAAkBD,YAAW,kCAAkC;AACrE,QAAM,iCAAiC,mDAAiB;AAAA,IACtD,CAAC;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,IACF,MACE,GAAG,WAAW,kBAAkB;AAAA;AAEpC,QAAM,WAAW,CAAC,MAAM,GAAG,IAAI;AAC/B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,IAAID;AAAA,IACF,MACG,OAAO,cAAc,IAAI,IAAI,CAAC;AAAA,IAIjC;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,MAAM;AACtC,QAAI,CAAC;AAAM,aAAO;AAClB,UAAM,gBAAgB,CAAC;AACvB,UAAM,SAAS,KAAK,gBAAgB,QAAQ;AAI5C,eAAW,SAAS,QAAQ;AAC1B,YAAM,qBACJ,+BAA+B,KAAK;AAEtC,UACE,CAAC,kCACD,CAAC,mBAAmB,UACpB;AAAA,QACE;AAAA,QACA;AAAA,MACF,GACA;AACA,sBAAc,KAAK,KAAkD;AAAA,MACvE;AAAA,IACF;AACA,WAAO,cAAc,WAAW,IAAI,gBAAgB;AAAA,EACtD,GAAG,CAAC,GAAG,UAAU,QAAQ,CAAC;AAE1B,QAAM,YAAY;AAAA,IAChB,CAAC,YAA2B;AAC1B,UAAI,CAAC;AAAM,eAAO,MAAM;AAAA,QAAC;AACzB,YAAM,YAAY,aAAa,QAAQ,kBAAkB;AACzD,WAAK,iBAAiB,WAAW,OAAO;AAExC,aAAO,MAAM;AACX,aAAK,oBAAoB,WAAW,OAAO;AAAA,MAC7C;AAAA,IACF;AAAA,IACA,CAAC,GAAG,UAAU,QAAQ;AAAA,EACxB;AAEA,QAAM,oBAAoB,YAAY,CAAC,YAA2B;AAChE,QAAI,CAAC;AAAM,aAAO,MAAM;AAAA,MAAC;AACzB,SAAK,iBAAiB,eAAe,OAAO;AAE5C,WAAO,MAAM;AACX,WAAK,oBAAoB,eAAe,OAAO;AAAA,IACjD;AAAA,EACF,GAAG,QAAQ;AAEX,QAAM,CAAC,YAAY,aAAa,IAC9BE,UAA2C,aAAa;AAE1D,EAAAN,WAAU,MAAM;AAEd,kBAAc,cAAc,CAAC;AAC7B,WAAO,UAAU,MAAM,cAAc,cAAc,CAAC,CAAC;AAAA,EACvD,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,0BAA0B,CAAC,MAAmB;AAClD,UAAM,cAAc,EAAE;AACtB,UAAM,QAAQ,YAAY;AAE1B,QAAI,SAAS,MAAM,IAAI;AACrB,oBAAc,CAAC,mBAAmB;AAChC,cAAM,WAAW,eAAe;AAAA,UAC9B,CAAC,QAAQ,IAAI,OAAO,MAAM,MAAM,IAAI,QAAQ,MAAM;AAAA,QACpD;AACA,eAAO,SAAS,WAAW,IAAI,gBAAgB;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,EAAAA,WAAU,MAAM;AACd,WAAO,kBAAkB,uBAAuB;AAAA,EAClD,GAAG,CAAC,iBAAiB,CAAC;AAEtB,EAAAA,WAAU,MAAM;AACd,eAAW,SAAS,YAAY;AAC9B,UAAI,UAAU;AACZ,cAAM,QAAQ,QAAQ;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,UAAU,CAAC;AAEzB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC;AAAM;AACX,WAAO,KAAK;AAAA,MACV;AAAA,MACA,CAAC,UACC,aAAa,MAAM,OAAO,KAAK;AAAA,IACnC;AAAA,EACF,GAAG,QAAQ;AAEX,MAAI,cAAc;AAChB,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,WAAW,WAAW,IAAI,QAAQ,KAAK;AAAA,IAChD,OAAO;AAAA,EACT;AACF;AAUA,SAAS,+BAA+B,OAAkC;AAjQ1E;AAkQE,MAAI;AACF,UAAM,oCAAmC,iBAAM,aAAN,mBAAgB,eAAhB,mBAA4B;AAAA,MACnE,CAAC,cAA0C,uCAAW;AAAA;AAExD,UAAM,qBAAqB;AAAA,MACzB,GAAI,MAAM,mBAAmB,CAAC;AAAA,MAC9B,GAAI,oCAAoC,CAAC;AAAA,IAC3C;AACA,WAAO;AAAA,EACT,QAAE;AACA,YAAQ;AAAA,MACN;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,gCACP,gCACA,sBACA;AACA,UACE,iFAAgC,YAChC,6DAAsB,WACtB,qBAAqB;AAAA,IAAK,CAAC,mBACzB,+BAA+B,SAAS,cAAc;AAAA,EACxD;AAEJ;;;AClRA,SAAS,cAAAK,mBAAkB;AAWpB,SAAS,0BAAmC;AACjD,QAAM,iBAAiBA,YAAiC,gBAAgB;AAExE,SAAO,eAAe;AACxB","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 (!extensionListFetched) {\n return;\n }\n\n const hasExtensions = !!extensions && !!Object.keys(extensions).length;\n\n const loadExtensions = (hostInstance: Host) => {\n if (!hasExtensions) {\n return;\n }\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, extensionListFetched]);\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.12-nightly.
|
|
3
|
+
"version": "1.1.12-nightly.20260922",
|
|
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.12-nightly.
|
|
24
|
-
"@adobe/uix-host": "^1.1.12-nightly.
|
|
23
|
+
"@adobe/uix-core": "^1.1.12-nightly.20260922",
|
|
24
|
+
"@adobe/uix-host": "^1.1.12-nightly.20260922"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@swc/jest": "^0.2.29",
|
|
@@ -104,7 +104,7 @@ describe("Extensible", () => {
|
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
it("should
|
|
107
|
+
it("should still create a host when extensions resolve empty, and unload it on unmount", async () => {
|
|
108
108
|
const extensionsProvider = jest.fn().mockResolvedValue({});
|
|
109
109
|
|
|
110
110
|
const { unmount } = render(
|
|
@@ -113,11 +113,74 @@ describe("Extensible", () => {
|
|
|
113
113
|
</Extensible>
|
|
114
114
|
);
|
|
115
115
|
|
|
116
|
+
// The host must exist even with zero extensions, so consumers relying on
|
|
117
|
+
// host readiness (e.g. useHost/loading state) aren't stuck waiting forever.
|
|
118
|
+
await waitFor(() => {
|
|
119
|
+
expect(MockedHost).toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// load() must not be called since there is nothing to load
|
|
123
|
+
expect(mockLoad).not.toHaveBeenCalled();
|
|
124
|
+
|
|
125
|
+
unmount();
|
|
126
|
+
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(mockUnload).toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should not call unload if the extensions fetch never resolved before unmount", () => {
|
|
133
|
+
const extensionsProvider = jest
|
|
134
|
+
.fn()
|
|
135
|
+
.mockReturnValue(new Promise(() => {}));
|
|
136
|
+
|
|
137
|
+
const { unmount } = render(
|
|
138
|
+
<Extensible appName="test-app" extensionsProvider={extensionsProvider}>
|
|
139
|
+
<div>Test Child</div>
|
|
140
|
+
</Extensible>
|
|
141
|
+
);
|
|
142
|
+
|
|
116
143
|
unmount();
|
|
117
144
|
|
|
118
145
|
// Unload should not be called if host was never created
|
|
119
146
|
expect(mockUnload).not.toHaveBeenCalled();
|
|
120
147
|
});
|
|
148
|
+
|
|
149
|
+
it("reuses the host (does not recreate) once extensions arrive after an initial empty resolve", async () => {
|
|
150
|
+
const emptyProvider = jest.fn().mockResolvedValue({});
|
|
151
|
+
const nonEmptyExtensions: InstalledExtensions = {
|
|
152
|
+
"ext-1": { id: "ext-1", url: "https://example.com/ext1" },
|
|
153
|
+
};
|
|
154
|
+
const nonEmptyProvider = jest.fn().mockResolvedValue(nonEmptyExtensions);
|
|
155
|
+
|
|
156
|
+
const { rerender } = render(
|
|
157
|
+
<Extensible appName="test-app" extensionsProvider={emptyProvider}>
|
|
158
|
+
<div>Test Child</div>
|
|
159
|
+
</Extensible>
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Host is created immediately even though there is nothing to load yet.
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(MockedHost).toHaveBeenCalledTimes(1);
|
|
165
|
+
});
|
|
166
|
+
expect(mockLoad).not.toHaveBeenCalled();
|
|
167
|
+
|
|
168
|
+
// Extensions arrive later (e.g. a slower registry response, or a
|
|
169
|
+
// subsequent provider swap). The existing host must be reused, not
|
|
170
|
+
// torn down and recreated, and load() should now be called.
|
|
171
|
+
rerender(
|
|
172
|
+
<Extensible appName="test-app" extensionsProvider={nonEmptyProvider}>
|
|
173
|
+
<div>Test Child</div>
|
|
174
|
+
</Extensible>
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
await waitFor(() => {
|
|
178
|
+
expect(mockLoad).toHaveBeenCalledWith(nonEmptyExtensions, undefined);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
expect(MockedHost).toHaveBeenCalledTimes(1);
|
|
182
|
+
expect(mockUnload).not.toHaveBeenCalled();
|
|
183
|
+
});
|
|
121
184
|
});
|
|
122
185
|
|
|
123
186
|
describe("Old host unloading when creating new host", () => {
|
|
@@ -188,11 +188,16 @@ export function Extensible({
|
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
if (!
|
|
191
|
+
if (!extensionListFetched) {
|
|
192
192
|
return;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
const hasExtensions = !!extensions && !!Object.keys(extensions).length;
|
|
196
|
+
|
|
195
197
|
const loadExtensions = (hostInstance: Host) => {
|
|
198
|
+
if (!hasExtensions) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
196
201
|
hostInstance
|
|
197
202
|
.load(extensions, guestOptions)
|
|
198
203
|
.catch(logError("Load of extensions failed!"));
|
|
@@ -220,7 +225,7 @@ export function Extensible({
|
|
|
220
225
|
} else {
|
|
221
226
|
loadExtensions(host);
|
|
222
227
|
}
|
|
223
|
-
}, [debug, hostName, runtimeContainer, extensions]);
|
|
228
|
+
}, [debug, hostName, runtimeContainer, extensions, extensionListFetched]);
|
|
224
229
|
|
|
225
230
|
const contextValue = useMemo(
|
|
226
231
|
() => ({ host, extensionListFetched }),
|
|
@@ -106,6 +106,23 @@ describe("GuestUIFrame", () => {
|
|
|
106
106
|
expect(iframe?.getAttribute("name")).toBe("uix-guest-guest-1");
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
it('always sets allow="local-network-access", even if a custom allow prop is passed', () => {
|
|
110
|
+
const guest = createGuest("guest-1");
|
|
111
|
+
mockedUseHost.mockReturnValue({
|
|
112
|
+
host: mockHostWithGuest(guest),
|
|
113
|
+
error: undefined,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const { container } = render(
|
|
117
|
+
<GuestUIFrame guestId="guest-1" src="page.html" allow="fullscreen" />
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const iframe = container.querySelector("iframe");
|
|
121
|
+
// required props win over any custom `allow`, same as the other
|
|
122
|
+
// required iframe props (data-uix-guest, role, referrerPolicy)
|
|
123
|
+
expect(iframe?.getAttribute("allow")).toBe("local-network-access");
|
|
124
|
+
});
|
|
125
|
+
|
|
109
126
|
it("attaches the UI and invokes onConnect once connected", async () => {
|
|
110
127
|
const guest = createGuest("guest-1");
|
|
111
128
|
mockedUseHost.mockReturnValue({
|