@itwin/core-frontend
Version:
iTwin.js frontend components
116 lines • 4.79 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Extensions
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtensionAdmin = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const FrontendLoggerCategory_1 = require("../common/FrontendLoggerCategory");
/** The Extension Admin controls the list of currently loaded Extensions.
*
* @alpha
*/
class ExtensionAdmin {
/** Defines the set of extensions that are currently known and can be invoked during activation events. */
_extensions = new Map();
_hosts;
/** Fired when an Extension has been added or removed.
* @internal
*/
onStartup = async () => {
await this.activateExtensionEvents("onStartup");
};
constructor() {
this._hosts = [];
}
/**
* Adds an extension.
* The manifest will be fetched and the extension will be activated on an activation event.
* @param provider
* @alpha
*/
async addExtension(provider) {
if (provider.hostname) {
const hostName = provider.hostname;
if (this._hosts.length > 0 && this._hosts.indexOf(hostName) < 0) {
throw new Error(`Error loading extension: ${hostName} was not registered.`);
}
}
try {
const manifest = await provider.getManifest();
this._extensions.set(manifest.name, {
manifest,
provider,
});
// TODO - temporary fix to execute the missed startup event
if (manifest.activationEvents.includes("onStartup"))
provider.execute(); // eslint-disable-line @typescript-eslint/no-floating-promises
}
catch (e) {
throw new Error(`Failed to get extension manifest ${provider.hostname ? `at ${provider.hostname}` : ""}: ${e}`);
}
}
/**
* Adds a list of extensions
* @param providers
* @alpha
*/
async addExtensions(providers) {
return Promise.all(providers.map(async (provider) => this.addExtension(provider)));
}
/**
* Registers a hostname for an extension.
* Once a hostname has been registered, only remote extensions from registered hosts are permitted to be added.
* @param hostUrl (string) Accepts both URLs and hostnames (e.g., http://localhost:3000, yourdomain.com, https://www.yourdomain.com, etc.).
*/
registerHost(hostUrl) {
const hostname = this.getHostName(hostUrl);
if (this._hosts.indexOf(hostname) < 0) {
this._hosts.push(hostname);
}
}
/** Returns the hostname of an input string. Throws an error if input is not a valid hostname (or URL). */
getHostName(inputUrl) {
// inputs without a protocol (e.g., http://) will throw an error in URL constructor
const inputWithProtocol = /(http|https):\/\//.test(inputUrl) ?
inputUrl :
`https://${inputUrl}`;
try {
const hostname = new URL(inputWithProtocol).hostname.replace("www.", "");
return hostname;
}
catch (e) {
if (e instanceof TypeError) {
throw new Error("Argument hostUrl should be a valid URL or hostname (i.e. http://localhost:3000, yourdomain.com, etc.).");
}
throw e;
}
}
/** Loops over all enabled Extensions and triggers each one if the provided event is defined. */
async activateExtensionEvents(event) {
for (const extension of this._extensions.values()) {
if (!extension.manifest.activationEvents)
continue;
for (const activationEvent of extension.manifest.activationEvents) {
if (activationEvent === event) {
this._execute(extension); // eslint-disable-line @typescript-eslint/no-floating-promises
}
}
}
}
/** Executes the extension. Catches and logs any errors (so that an extension will not crash the main application). */
async _execute(extension) {
try {
await extension.provider.execute();
}
catch (e) {
core_bentley_1.Logger.logError(FrontendLoggerCategory_1.FrontendLoggerCategory.Extensions, `Error executing extension ${extension.manifest.name}: ${e}`);
}
}
}
exports.ExtensionAdmin = ExtensionAdmin;
//# sourceMappingURL=ExtensionAdmin.js.map
;