import { onDebug } from '@atlassian/clientside-extensions-debug'; /* eslint-disable import-x/no-unresolved, node/no-missing-import */ import wrmRequire from 'wrm/require'; import contextPath from 'wrm/context-path'; /* eslint-enable import-x/no-unresolved, node/no-missing-import */ import type { ExtensionDescriptor } from './types'; const getClientExtensionsRestURL = (location: string) => { const baseURL = `${contextPath()}/rest/client-plugins/1.0/client-plugins`; return `${baseURL}/items?location=${location}`; }; const deferBy = async (timeout: number) => { return new Promise((resolve) => setTimeout(() => resolve(), timeout)); }; export async function getLocationExtensions(location: string): Promise { onDebug(({ debug }) => ({ level: debug, message: `Loading legacy web-items for "${location}" extension location...`, components: 'Registry', meta: { location, }, })); let webItems: ExtensionDescriptor[] = []; try { const request = await fetch(getClientExtensionsRestURL(location), { method: 'get', credentials: 'include', headers: { 'Content-Type': 'application/json', }, }); const response = await request.json(); webItems = (response.webItems as ExtensionDescriptor[]) || []; onDebug(({ debug }) => ({ level: debug, message: `Loaded legacy web-components for "${location}" extension location`, components: 'Registry', meta: { location, webItems, }, })); // eslint-disable-next-line no-empty } catch (e) { onDebug(({ error }) => ({ level: error, message: `Couldn't load the legacy web-components for "${location}" extension location`, components: 'Registry', meta: { location, webItems, error: (e as Error).message, }, })); } return webItems; } function getEnvDeferTime(isAtlassianDevModeEnabled: boolean = false): number { // In the local refapp with watch mode and webpack-dev-server (WDS), we can not assume we actually loaded the resources // by calling "WRM.require". The loaded web-resource includes only a proxy code that will load actual assets from the WDS. // However, we can just artificially try to force it by deferring the call by some milliseconds. // // Once we create the CSE P2 runtime Java plugin, we have a similar issue. Inside the product runtime, the resources can be // loaded with or without WDS. When we run this code in product runtime we can't determine if the product is using WDS. // What we can do instead is to leverage the "atlassian.dev.mode" flag and assume that if the mode is enabled we are running WDS. // This is not perfect, but it gives us a good enough solution to simulate more or less deterministic behaviour of "WRM.require". const isLocalWatchModeEnabled = typeof module !== 'undefined' && (module as unknown as { hot: boolean }).hot; return isLocalWatchModeEnabled || isAtlassianDevModeEnabled ? 1500 : 0; } export async function getLocationResources(location: string, isAtlassianDevModeEnabled?: boolean): Promise { onDebug(({ debug }) => ({ level: debug, message: `Loading web-resources for "${location}" extension location...`, components: 'Registry', meta: { location, }, })); // We need to use Promise wrapper since different WRM versions can return a jQuery-based thenable object. await new Promise((resolve, reject) => wrmRequire(`wrc!${location}`).then( () => resolve(), () => reject(), ), ); /** We can not assume we actually loaded the extension's resources yet. Check the {@see getEnvDeferTime} for more details. We need to defer the initialization of the extension point depending on the runtime environment: - product in production mode - product in dev mode (with or without webpack-dev-server) - local refapp with webpack-dev-server */ await deferBy(getEnvDeferTime(isAtlassianDevModeEnabled)); onDebug(({ debug }) => ({ level: debug, message: `Loaded web-resources for "${location}" extension location`, components: 'Registry', meta: { location, }, })); }