Skip to content

Commit

Permalink
fix: issue 4907 RELEASE (#334)
Browse files Browse the repository at this point in the history
  • Loading branch information
nirgur authored Dec 13, 2023
1 parent 486e6f9 commit e81d572
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 67 deletions.
15 changes: 15 additions & 0 deletions packages/web-component/src/lib/constants/content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IS_LOCAL_STORAGE } from './general';

const BASE_CONTENT_URL_KEY = 'base.content.url';

// eslint-disable-next-line import/prefer-default-export
export const BASE_CONTENT_URL =
(IS_LOCAL_STORAGE && localStorage.getItem(BASE_CONTENT_URL_KEY)) ||
'https://static.descope.com/pages';

export const ASSETS_FOLDER = 'v2-beta';
export const PREV_VER_ASSETS_FOLDER = 'v2-alpha';

// Those files are saved on a new folder to prevent breaking changes
export const THEME_FILENAME = 'theme.json';
export const CONFIG_FILENAME = 'config.json';
2 changes: 2 additions & 0 deletions packages/web-component/src/lib/constants/general.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* eslint-disable import/prefer-default-export */
export const IS_LOCAL_STORAGE = typeof localStorage !== 'undefined';
21 changes: 4 additions & 17 deletions packages/web-component/src/lib/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
const BASE_CONTENT_URL_KEY = 'base.content.url';
export const UI_COMPONENTS_URL_KEY = 'base.ui.components.url';
export const UI_COMPONENTS_URL_VERSION_PLACEHOLDER = '<version>';
export const IS_LOCAL_STORAGE = typeof localStorage !== 'undefined';
export const BASE_CONTENT_URL =
(IS_LOCAL_STORAGE && localStorage.getItem(BASE_CONTENT_URL_KEY)) ||
'https://static.descope.com/pages';
export const UI_COMPONENTS_URL =
(IS_LOCAL_STORAGE && localStorage.getItem(UI_COMPONENTS_URL_KEY)) ||
'https://static.descope.com/npm/@descope/web-components-ui@<version>/dist/umd/index.js';
export * from './general';
export * from './content';
export * from './uiComponents';

export const URL_RUN_IDS_PARAM_NAME = 'descope-login-flow';
export const URL_TOKEN_PARAM_NAME = 't';
export const URL_CODE_PARAM_NAME = 'code';
Expand All @@ -34,13 +28,6 @@ export const RESPONSE_ACTIONS = {
loadForm: 'loadForm',
};

export const ASSETS_FOLDER = 'v2-beta';
export const PREV_VER_ASSETS_FOLDER = 'v2-alpha';

// Those files are saved on a new folder to prevent breaking changes
export const THEME_FILENAME = 'theme.json';
export const CONFIG_FILENAME = 'config.json';

export const CUSTOM_INTERACTIONS = {
submit: 'submit',
polling: 'polling',
Expand Down
13 changes: 13 additions & 0 deletions packages/web-component/src/lib/constants/uiComponents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IS_LOCAL_STORAGE } from './general';

export const UI_COMPONENTS_URL_KEY = 'base.ui.components.url';

export const UI_COMPONENTS_URL =
(IS_LOCAL_STORAGE && localStorage.getItem(UI_COMPONENTS_URL_KEY)) ||
'https://static.descope.com/npm/@descope/web-components-ui@<version>/dist/umd/index.js';

export const UI_COMPONENTS_FALLBACK_URL =
(IS_LOCAL_STORAGE && localStorage.getItem(UI_COMPONENTS_URL_KEY)) ||
'https://cdn.jsdelivr.net/npm/@descope/web-components-ui@<version>/dist/umd/index.js';

export const UI_COMPONENTS_URL_VERSION_PLACEHOLDER = '<version>';
123 changes: 77 additions & 46 deletions packages/web-component/src/lib/descope-wc/BaseDescopeWc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CONFIG_FILENAME,
PREV_VER_ASSETS_FOLDER,
THEME_FILENAME,
UI_COMPONENTS_FALLBACK_URL,
UI_COMPONENTS_URL,
UI_COMPONENTS_URL_VERSION_PLACEHOLDER,
} from '../constants';
Expand Down Expand Up @@ -370,7 +371,7 @@ class BaseDescopeWc extends HTMLElement {
styleEle.innerText =
(theme?.light?.globals || '') + (theme?.dark?.globals || '');

const descopeUi = await this.descopeUI;
const descopeUi = await BaseDescopeWc.descopeUI;
if (descopeUi?.componentsThemeManager) {
descopeUi.componentsThemeManager.themes = {
light: theme?.light?.components,
Expand All @@ -392,7 +393,7 @@ class BaseDescopeWc extends HTMLElement {

async #applyTheme() {
this.rootElement.setAttribute('data-theme', this.theme);
const descopeUi = await this.descopeUI;
const descopeUi = await BaseDescopeWc.descopeUI;
if (descopeUi?.componentsThemeManager) {
descopeUi.componentsThemeManager.currentThemeName = this.theme;
}
Expand Down Expand Up @@ -488,66 +489,96 @@ class BaseDescopeWc extends HTMLElement {
};
}

async #loadDescopeUI() {
const SCRIPT_ID = 'load-descope-ui';
async #getComponentsVersion() {
const version = (await this.#getConfig())?.projectConfig?.componentsVersion;

// if DescopeUI is already loaded, use it
if (globalThis.DescopeUI) {
this.descopeUI = Promise.resolve(globalThis.DescopeUI);
return;
}
if (version) return version;

const existingScript = document.getElementById(
SCRIPT_ID,
) as HTMLScriptElement;
const scriptEle: HTMLScriptElement =
existingScript || document.createElement('script');
this.logger.error('Did not get components version, using latest version');

if (existingScript) {
return 'latest';
}

static descopeUI: any;

async #loadDescopeUI() {
if (BaseDescopeWc.descopeUI) {
this.loggerWrapper.info(
'DescopeUI loading script is already exist, probably multiple flows are running on the same page',
'DescopeUI is already loading, probably multiple flows are running on the same page',
);
} else {
scriptEle.id = SCRIPT_ID;

let version = (await this.#getConfig())?.projectConfig?.componentsVersion;
return;
}

if (!version) {
this.logger.error(
'Did not get components version, using latest version',
);
version = 'latest';
BaseDescopeWc.descopeUI = new Promise((resolve) => {
if (globalThis.DescopeUI) {
resolve(globalThis.DescopeUI);
return;
}

scriptEle.src = UI_COMPONENTS_URL.replace(
UI_COMPONENTS_URL_VERSION_PLACEHOLDER,
version,
);
const setupScript = (url: string) => {
const scriptEle = document.createElement('script');
scriptEle.id = 'load-descope-ui';
scriptEle.src = url;

document.body.append(scriptEle);
}
return scriptEle;
};

this.descopeUI = new Promise((res) => {
const onError = () => {
this.loggerWrapper.error(
'Cannot load DescopeUI',
`Make sure this URL is valid and return the correct script: "${scriptEle.src}"`,
const generateScriptUrl = (
urlTemplate: string,
componentsVersion: string,
) =>
urlTemplate.replace(
UI_COMPONENTS_URL_VERSION_PLACEHOLDER,
componentsVersion,
);

res(undefined);
const attachEvents = (
scriptEle: HTMLScriptElement,
onError: () => void,
) => {
const onErrorInternal = () => {
this.loggerWrapper.error(
'Cannot load DescopeUI',
`Make sure this URL is valid and return the correct script: "${scriptEle.src}"`,
);

onError();
};

scriptEle.addEventListener('load', () => {
if (!globalThis.DescopeUI) onErrorInternal();
resolve(globalThis.DescopeUI);
});

scriptEle.addEventListener('error', onErrorInternal);
};

scriptEle.addEventListener('load', () => {
if (!globalThis.DescopeUI) onError();
res(globalThis.DescopeUI);
});
(async () => {
const componentsVersion = await this.#getComponentsVersion();
const scriptEle = setupScript(
generateScriptUrl(UI_COMPONENTS_URL, componentsVersion),
);

scriptEle.addEventListener('error', onError);
// if we cannot load descope UI, we want to try from a fallback url
const onError = () => {
scriptEle.remove();

this.loggerWrapper.info(
'Trying to load DescopeUI from a fallback URL',
);

const fallbackScriptEle = setupScript(
generateScriptUrl(UI_COMPONENTS_FALLBACK_URL, componentsVersion),
);
attachEvents(fallbackScriptEle, () => {
resolve(undefined);
});
document.body.append(fallbackScriptEle);
};

// in case the load event was dispatched before we registered, we have a fallback
if (globalThis.DescopeUI) {
res(globalThis.DescopeUI);
}
attachEvents(scriptEle, onError);
document.body.append(scriptEle);
})();
});
}

Expand Down
3 changes: 2 additions & 1 deletion packages/web-component/src/lib/descope-wc/DescopeWc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ class DescopeWc extends BaseDescopeWc {
}

async loadDescopeUiComponents(clone: DocumentFragment) {
const descopeUI = await this.descopeUI;
const descopeUI = await BaseDescopeWc.descopeUI;
if (!descopeUI) return;

const descopeUiComponentsList = getDescopeUiComponentsList(clone);
Expand All @@ -673,6 +673,7 @@ class DescopeWc extends BaseDescopeWc {
return undefined;
}
try {
// eslint-disable-next-line @typescript-eslint/return-await
return await descopeUI[tag]();
} catch (e) {
// this error is thrown when trying to register a component which is already registered
Expand Down
10 changes: 7 additions & 3 deletions packages/web-component/test/descope-wc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import * as helpers from '../src/lib/helpers/helpers';
// eslint-disable-next-line import/no-namespace
import { generateSdkResponse, invokeScriptOnload } from './testUtils';
import { getABTestingKey } from '../src/lib/helpers/abTestingKey';
import BaseDescopeWc from '../src/lib/descope-wc/BaseDescopeWc';

jest.mock('@descope/web-js-sdk', () => ({
__esModule: true,
Expand Down Expand Up @@ -3199,6 +3200,9 @@ describe('web-component', () => {
});

describe('Descope UI', () => {
beforeEach(() => {
BaseDescopeWc.descopeUI = undefined;
});
it('should log error if Descope UI cannot be loaded', async () => {
startMock.mockReturnValue(generateSdkResponse());

Expand All @@ -3221,14 +3225,14 @@ describe('web-component', () => {
it('should try to load all descope component on the page', async () => {
startMock.mockReturnValue(generateSdkResponse());

pageContent =
'<descope-input16 id="email"></descope-input16><descope-button16>It works!</descope-button16>';

globalThis.DescopeUI = {
'descope-button16': jest.fn(),
'descope-input16': jest.fn(),
};

pageContent =
'<descope-input16 id="email"></descope-input16><descope-button16>It works!</descope-button16>';

document.body.innerHTML = `<h1>Custom element test</h1> <descope-wc flow-id="otpSignInEmail" project-id="1"></descope-wc>`;

await waitFor(
Expand Down

0 comments on commit e81d572

Please sign in to comment.