 function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { navigateDisklet } from 'disklet'













import { makeLog } from '../log/log'









const allPlugins = {}
let allPluginsLocked = false
const onPluginsAdded = []
const onPluginsLocked = []

/**
 * Adds plugins to the core.
 */
export function addEdgeCorePlugins(plugins) {
  if (allPluginsLocked) {
    throw new Error('The Edge core plugin list has already been locked')
  }

  // Save the new plugins:
  for (const pluginId of Object.keys(plugins)) {
    allPlugins[pluginId] = plugins[pluginId]
  }

  // Update already-booted contexts:
  for (const f of onPluginsAdded) f(plugins)
}

/**
 * Finalizes the core plugin list, so no further plugins are expected.
 */
export function lockEdgeCorePlugins() {
  allPluginsLocked = true
  for (const f of onPluginsLocked) f()
}

/**
 * Subscribes a context object to the core plugin list.
 */
export function watchPlugins(
  ios,
  infoCache,
  logBackend,
  pluginsInit,
  dispatch
) {
  const { io, nativeIo } = ios
  const legacyIo = { ...io, console }

  function pluginsAdded(plugins) {
    const out = {}

    for (const pluginId of Object.keys(plugins)) {
      const plugin = plugins[pluginId]
      const log = makeLog(logBackend, pluginId)
      const initOptions = pluginsInit[pluginId]
      if (initOptions === false || initOptions == null) continue

      // Figure out what kind of object this is:
      try {
        if (typeof plugin === 'function') {
          const opts = {
            infoPayload: _nullishCoalesce(_optionalChain([infoCache, 'access', _ => _.corePlugins, 'optionalAccess', _2 => _2[pluginId]]), () => ( {})),
            initOptions: typeof initOptions === 'object' ? initOptions : {},
            io: legacyIo,
            log,
            nativeIo,
            pluginDisklet: navigateDisklet(io.disklet, 'plugins/' + pluginId)
          }
          out[pluginId] = plugin(opts)
        } else if (typeof plugin === 'object' && plugin != null) {
          out[pluginId] = plugin
        } else {
          throw new TypeError(
            `Plugins must be functions or objects, got ${typeof plugin}`
          )
        }
      } catch (error) {
        // Show the error but keep going:
        log.error(error)
      }
    }

    dispatch({ type: 'CORE_PLUGINS_ADDED', payload: out })
  }

  function pluginsLocked() {
    dispatch({ type: 'CORE_PLUGINS_LOCKED', payload: pluginsInit })
  }

  // Add any plugins currently available:
  pluginsAdded(allPlugins)
  if (allPluginsLocked) pluginsLocked()

  // Save the callbacks:
  onPluginsAdded.push(pluginsAdded)
  onPluginsLocked.push(pluginsLocked)

  return () => {
    onPluginsAdded.filter(f => f !== pluginsAdded)
    onPluginsLocked.filter(f => f !== pluginsLocked)
  }
}
