installPlugin(pluginId, installerPluginName) {
		return new Promise((resolve, reject) => {
			confirm(
				strings.install,
				`Do you want to install plugin '${pluginId}'${installerPluginName ? ` requested by ${installerPluginName}` : ""}?`,
			)
				.then((confirmation) => {
					if (!confirmation) {
						reject(new Error("User cancelled installation"));
						return;
					}

					fsOperation(Url.join(PLUGIN_DIR, pluginId))
						.exists()
						.then((isPluginExists) => {
							if (isPluginExists) {
								reject(new Error("Plugin already installed"));
								return;
							}

							let purchaseToken;
							let product;
							const pluginUrl = Url.join(
								constants.API_BASE,
								`plugin/${pluginId}`,
							);
							fsOperation(pluginUrl)
								.readFile("json")
								.catch(() => {
									reject(new Error("Failed to fetch plugin details"));
									return null;
								})
								.then((remotePlugin) => {
									if (remotePlugin) {
										const isPaid = remotePlugin.price > 0;
										helpers
											.promisify(iap.getProducts, [remotePlugin.sku])
											.then((products) => {
												[product] = products;
												if (product) {
													return getPurchase(product.productId);
												}
												return null;
											})
											.then((purchase) => {
												purchaseToken = purchase?.purchaseToken;

												if (isPaid && !purchaseToken) {
													if (!product) throw new Error("Product not found");
													return helpers.checkAPIStatus().then((apiStatus) => {
														if (!apiStatus) {
															alert(strings.error, strings.api_error);
															return;
														}

														iap.setPurchaseUpdatedListener(
															...purchaseListener(onpurchase, onerror),
														);
														return helpers.promisify(
															iap.purchase,
															product.json,
														);
													});
												}
											})
											.then(() => {
												import("lib/installPlugin").then(
													({ default: installPlugin }) => {
														installPlugin(
															pluginId,
															remotePlugin.name,
															purchaseToken,
														).then(() => {
															resolve();
														});
													},
												);
											});

										async function onpurchase(e) {
											const purchase = await getPurchase(product.productId);
											await ajax.post(
												Url.join(constants.API_BASE, "plugin/order"),
												{
													data: {
														id: remotePlugin.id,
														token: purchase?.purchaseToken,
														package: BuildInfo.packageName,
													},
												},
											);
											purchaseToken = purchase?.purchaseToken;
										}

										async function onerror(error) {
											throw error;
										}
									}
								});

							async function getPurchase(sku) {
								const purchases = await helpers.promisify(iap.getPurchases);
								const purchase = purchases.find((p) =>
									p.productIds.includes(sku),
								);
								return purchase;
							}
						});
				})
				.catch((error) => {
					reject(error);
				});
		});
	}
Installs an Acode plugin from registry
@param {string} pluginId id of the plugin to install
@param {string} installerPluginName Name of plugin attempting to install
@returns {Promise<void>}