loadAndSaveNewPlugin = async (
  plugin,
  force,
  noSignalOrDB,
  __ = (str) => str,
  allowUnsafeOnTenantsWithoutConfigSetting
) => {
  const tenants_unsafe_plugins = getRootState().getConfig(
    "tenants_unsafe_plugins",
    false
  );
  if (!isRoot() && !tenants_unsafe_plugins) {
    if (plugin.source !== "npm") {
      console.error("\nWARNING: Skipping unsafe plugin ", plugin.name);
      return;
    }
    //get allowed plugins

    //refresh root store
    await db.runWithTenant(
      db.connectObj.default_schema,
      async () => await Plugin.store_plugins_available()
    );

    const instore = getRootState().getConfig("available_plugins", []);
    const safes = instore.filter((p) => !p.unsafe).map((p) => p.location);
    if (
      !safes.includes(plugin.location) &&
      !allowUnsafeOnTenantsWithoutConfigSetting
    ) {
      console.error("\nWARNING: Skipping unsafe plugin ", plugin.name);
      return;
    }
  }
  if (plugin.source === "npm") await ensurePluginSupport(plugin);
  const loadMsgs = [];
  const loader = new PluginInstaller(plugin, {
    scVersion: packagejson.version,
    envVars: { PUPPETEER_SKIP_DOWNLOAD: true },
  });
  const { version, plugin_module, location, loadedWithReload, msgs } =
    await loader.install(force);
  if (msgs) loadMsgs.push(...msgs);
  // install dependecies
  for (const loc of plugin_module.dependencies || []) {
    const existing = await Plugin.findOne({ location: loc });
    if (!existing && loc !== plugin.location) {
      await loadAndSaveNewPlugin(
        new Plugin({
          name: loc.replace("@saltcorn/", ""),
          location: loc,
          source: "npm",
        }),
        force,
        noSignalOrDB
      );
    }
  }
  let registeredWithReload = false;
  try {
    getState().registerPlugin(
      plugin_module.plugin_name || plugin.name,
      plugin_module,
      plugin.configuration,
      location,
      plugin.name
    );
  } catch (error) {
    if (force) {
      getState().log(
        2,
        `Error registering plugin ${plugin.name}. Removing and trying again.`
      );
      await loader.remove();
      await loader.install(force);
      getState().registerPlugin(
        plugin_module.plugin_name || plugin.name,
        plugin_module,
        plugin.configuration,
        location,
        plugin.name
      );
      registeredWithReload = true;
    } else {
      throw error;
    }
  }
  if (loadedWithReload || registeredWithReload) {
    loadMsgs.push(
      __(
        "The plugin was corrupted and had to be repaired. We recommend restarting your server.",
        plugin.name
      )
    );
  }
  if (plugin_module.onLoad) {
    try {
      await plugin_module.onLoad(plugin.configuration);
    } catch (error) {
      console.error(error);
    }
  }
  if (version) plugin.version = version;

  if (isRoot() && plugin_module.authentication)
    await eachTenant(reloadAuthFromRoot);

  if (!noSignalOrDB) {
    await plugin.upsert();
    getState().processSend({
      installPlugin: plugin,
      tenant: db.getTenantSchema(),
      force: false, // okay ??
    });
  }
  return loadMsgs;
}
Load Plugin and its dependencies and save into local installation
@param plugin
@param force
@param noSignalOrDB
@param __ translation function
@returns {Promise<void>}