class AssertionError extends Error {
  constructor(message) {
    super(message);
    this.name = 'AssertionError';
  }
}
const Object$1 = 1;
const Number = 2;
const Array$1 = 3;
const String$1 = 4;
const Boolean$1 = 5;
const Function = 6;
const Null = 7;
const Unknown = 8;
const getType = value => {
  switch (typeof value) {
    case 'number':
      return Number;
    case 'function':
      return Function;
    case 'string':
      return String$1;
    case 'object':
      if (value === null) {
        return Null;
      }
      if (Array.isArray(value)) {
        return Array$1;
      }
      return Object$1;
    case 'boolean':
      return Boolean$1;
    default:
      return Unknown;
  }
};
const object = value => {
  const type = getType(value);
  if (type !== Object$1) {
    throw new AssertionError('expected value to be of type object');
  }
};
const number = value => {
  const type = getType(value);
  if (type !== Number) {
    throw new AssertionError('expected value to be of type number');
  }
};
const string = value => {
  const type = getType(value);
  if (type !== String$1) {
    throw new AssertionError('expected value to be of type string');
  }
};

const normalizeLine = line => {
  if (line.startsWith('Error: ')) {
    return line.slice('Error: '.length);
  }
  if (line.startsWith('VError: ')) {
    return line.slice('VError: '.length);
  }
  return line;
};
const getCombinedMessage = (error, message) => {
  const stringifiedError = normalizeLine(`${error}`);
  if (message) {
    return `${message}: ${stringifiedError}`;
  }
  return stringifiedError;
};
const NewLine$3 = '\n';
const getNewLineIndex$1 = (string, startIndex = undefined) => {
  return string.indexOf(NewLine$3, startIndex);
};
const mergeStacks = (parent, child) => {
  if (!child) {
    return parent;
  }
  const parentNewLineIndex = getNewLineIndex$1(parent);
  const childNewLineIndex = getNewLineIndex$1(child);
  if (childNewLineIndex === -1) {
    return parent;
  }
  const parentFirstLine = parent.slice(0, parentNewLineIndex);
  const childRest = child.slice(childNewLineIndex);
  const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
  if (parentFirstLine.includes(childFirstLine)) {
    return parentFirstLine + childRest;
  }
  return child;
};
class VError extends Error {
  constructor(error, message) {
    const combinedMessage = getCombinedMessage(error, message);
    super(combinedMessage);
    this.name = 'VError';
    if (error instanceof Error) {
      this.stack = mergeStacks(this.stack, error.stack);
    }
    if (error.codeFrame) {
      // @ts-ignore
      this.codeFrame = error.codeFrame;
    }
    if (error.code) {
      // @ts-ignore
      this.code = error.code;
    }
  }
}

const isMessagePort = value => {
  return value && value instanceof MessagePort;
};
const isMessagePortMain = value => {
  return value && value.constructor && value.constructor.name === 'MessagePortMain';
};
const isOffscreenCanvas = value => {
  return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
};
const isInstanceOf = (value, constructorName) => {
  return value?.constructor?.name === constructorName;
};
const isSocket = value => {
  return isInstanceOf(value, 'Socket');
};
const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
const isTransferrable = value => {
  for (const fn of transferrables) {
    if (fn(value)) {
      return true;
    }
  }
  return false;
};
const walkValue = (value, transferrables, isTransferrable) => {
  if (!value) {
    return;
  }
  if (isTransferrable(value)) {
    transferrables.push(value);
    return;
  }
  if (Array.isArray(value)) {
    for (const item of value) {
      walkValue(item, transferrables, isTransferrable);
    }
    return;
  }
  if (typeof value === 'object') {
    for (const property of Object.values(value)) {
      walkValue(property, transferrables, isTransferrable);
    }
    return;
  }
};
const getTransferrables = value => {
  const transferrables = [];
  walkValue(value, transferrables, isTransferrable);
  return transferrables;
};
const attachEvents = that => {
  const handleMessage = (...args) => {
    const data = that.getData(...args);
    that.dispatchEvent(new MessageEvent('message', {
      data
    }));
  };
  that.onMessage(handleMessage);
  const handleClose = event => {
    that.dispatchEvent(new Event('close'));
  };
  that.onClose(handleClose);
};
class Ipc extends EventTarget {
  constructor(rawIpc) {
    super();
    this._rawIpc = rawIpc;
    attachEvents(this);
  }
}
const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
const NewLine$2 = '\n';
const joinLines$1 = lines => {
  return lines.join(NewLine$2);
};
const RE_AT = /^\s+at/;
const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
const isNormalStackLine = line => {
  return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
};
const getDetails = lines => {
  const index = lines.findIndex(isNormalStackLine);
  if (index === -1) {
    return {
      actualMessage: joinLines$1(lines),
      rest: []
    };
  }
  let lastIndex = index - 1;
  while (++lastIndex < lines.length) {
    if (!isNormalStackLine(lines[lastIndex])) {
      break;
    }
  }
  return {
    actualMessage: lines[index - 1],
    rest: lines.slice(index, lastIndex)
  };
};
const splitLines$1 = lines => {
  return lines.split(NewLine$2);
};
const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/;
const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/;
const isMessageCodeBlockStartIndex = line => {
  return RE_MESSAGE_CODE_BLOCK_START.test(line);
};
const isMessageCodeBlockEndIndex = line => {
  return RE_MESSAGE_CODE_BLOCK_END.test(line);
};
const getMessageCodeBlock = stderr => {
  const lines = splitLines$1(stderr);
  const startIndex = lines.findIndex(isMessageCodeBlockStartIndex);
  const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex);
  const relevantLines = lines.slice(startIndex, endIndex);
  const relevantMessage = relevantLines.join(' ').slice('Error: '.length);
  return relevantMessage;
};
const isModuleNotFoundMessage = line => {
  return line.includes('[ERR_MODULE_NOT_FOUND]');
};
const getModuleNotFoundError = stderr => {
  const lines = splitLines$1(stderr);
  const messageIndex = lines.findIndex(isModuleNotFoundMessage);
  const message = lines[messageIndex];
  return {
    code: ERR_MODULE_NOT_FOUND,
    message
  };
};
const isModuleNotFoundError = stderr => {
  if (!stderr) {
    return false;
  }
  return stderr.includes('ERR_MODULE_NOT_FOUND');
};
const isModulesSyntaxError = stderr => {
  if (!stderr) {
    return false;
  }
  return stderr.includes('SyntaxError: Cannot use import statement outside a module');
};
const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/;
const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/;
const isUnhelpfulNativeModuleError = stderr => {
  return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr);
};
const getNativeModuleErrorMessage = stderr => {
  const message = getMessageCodeBlock(stderr);
  return {
    code: E_INCOMPATIBLE_NATIVE_MODULE,
    message: `Incompatible native node module: ${message}`
  };
};
const getModuleSyntaxError = () => {
  return {
    code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON,
    message: `ES Modules are not supported in electron`
  };
};
const getHelpfulChildProcessError = (stdout, stderr) => {
  if (isUnhelpfulNativeModuleError(stderr)) {
    return getNativeModuleErrorMessage(stderr);
  }
  if (isModulesSyntaxError(stderr)) {
    return getModuleSyntaxError();
  }
  if (isModuleNotFoundError(stderr)) {
    return getModuleNotFoundError(stderr);
  }
  const lines = splitLines$1(stderr);
  const {
    actualMessage,
    rest
  } = getDetails(lines);
  return {
    code: '',
    message: actualMessage,
    stack: rest
  };
};
class IpcError extends VError {
  // @ts-ignore
  constructor(betterMessage, stdout = '', stderr = '') {
    if (stdout || stderr) {
      // @ts-ignore
      const {
        code,
        message,
        stack
      } = getHelpfulChildProcessError(stdout, stderr);
      const cause = new Error(message);
      // @ts-ignore
      cause.code = code;
      cause.stack = stack;
      super(cause, betterMessage);
    } else {
      super(betterMessage);
    }
    // @ts-ignore
    this.name = 'IpcError';
    // @ts-ignore
    this.stdout = stdout;
    // @ts-ignore
    this.stderr = stderr;
  }
}
const readyMessage = 'ready';
const getData$2 = event => {
  return event.data;
};
const listen$7 = () => {
  // @ts-ignore
  if (typeof WorkerGlobalScope === 'undefined') {
    throw new TypeError('module is not in web worker scope');
  }
  return globalThis;
};
const signal$8 = global => {
  global.postMessage(readyMessage);
};
class IpcChildWithModuleWorker extends Ipc {
  getData(event) {
    return getData$2(event);
  }
  send(message) {
    // @ts-ignore
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    // @ts-ignore
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    // ignore
  }
  onClose(callback) {
    // ignore
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
  }
}
const wrap$f = global => {
  return new IpcChildWithModuleWorker(global);
};
const waitForFirstMessage = async port => {
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  port.addEventListener('message', resolve, {
    once: true
  });
  const event = await promise;
  // @ts-ignore
  return event.data;
};
const listen$6 = async () => {
  const parentIpcRaw = listen$7();
  signal$8(parentIpcRaw);
  const parentIpc = wrap$f(parentIpcRaw);
  const firstMessage = await waitForFirstMessage(parentIpc);
  if (firstMessage.method !== 'initialize') {
    throw new IpcError('unexpected first message');
  }
  const type = firstMessage.params[0];
  if (type === 'message-port') {
    parentIpc.send({
      id: firstMessage.id,
      jsonrpc: '2.0',
      result: null
    });
    parentIpc.dispose();
    const port = firstMessage.params[1];
    return port;
  }
  return globalThis;
};
class IpcChildWithModuleWorkerAndMessagePort extends Ipc {
  getData(event) {
    return getData$2(event);
  }
  send(message) {
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    if (this._rawIpc.close) {
      this._rawIpc.close();
    }
  }
  onClose(callback) {
    // ignore
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
    this._rawIpc.start();
  }
}
const wrap$e = port => {
  return new IpcChildWithModuleWorkerAndMessagePort(port);
};
const IpcChildWithModuleWorkerAndMessagePort$1 = {
  __proto__: null,
  listen: listen$6,
  wrap: wrap$e
};
const Error$3 = 1;
const Open = 2;
const Close = 3;
const addListener = (emitter, type, callback) => {
  if ('addEventListener' in emitter) {
    emitter.addEventListener(type, callback);
  } else {
    emitter.on(type, callback);
  }
};
const removeListener = (emitter, type, callback) => {
  if ('removeEventListener' in emitter) {
    emitter.removeEventListener(type, callback);
  } else {
    emitter.off(type, callback);
  }
};
const getFirstEvent = (eventEmitter, eventMap) => {
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  const listenerMap = Object.create(null);
  const cleanup = value => {
    for (const event of Object.keys(eventMap)) {
      removeListener(eventEmitter, event, listenerMap[event]);
    }
    resolve(value);
  };
  for (const [event, type] of Object.entries(eventMap)) {
    const listener = event => {
      cleanup({
        event,
        type
      });
    };
    addListener(eventEmitter, event, listener);
    listenerMap[event] = listener;
  }
  return promise;
};
const Message$1 = 3;
const create$5$1 = async ({
  isMessagePortOpen,
  messagePort
}) => {
  if (!isMessagePort(messagePort)) {
    throw new IpcError('port must be of type MessagePort');
  }
  if (isMessagePortOpen) {
    return messagePort;
  }
  const eventPromise = getFirstEvent(messagePort, {
    message: Message$1
  });
  messagePort.start();
  const {
    event,
    type
  } = await eventPromise;
  if (type !== Message$1) {
    throw new IpcError('Failed to wait for ipc message');
  }
  if (event.data !== readyMessage) {
    throw new IpcError('unexpected first message');
  }
  return messagePort;
};
const signal$1 = messagePort => {
  messagePort.start();
};
class IpcParentWithMessagePort extends Ipc {
  getData = getData$2;
  send(message) {
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    this._rawIpc.close();
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
  }
  onClose(callback) {}
}
const wrap$5 = messagePort => {
  return new IpcParentWithMessagePort(messagePort);
};
const IpcParentWithMessagePort$1 = {
  __proto__: null,
  create: create$5$1,
  signal: signal$1,
  wrap: wrap$5
};
const stringifyCompact = value => {
  return JSON.stringify(value);
};
const parse = content => {
  if (content === 'undefined') {
    return null;
  }
  try {
    return JSON.parse(content);
  } catch (error) {
    throw new VError(error, 'failed to parse json');
  }
};
const waitForWebSocketToBeOpen = webSocket => {
  return getFirstEvent(webSocket, {
    close: Close,
    error: Error$3,
    open: Open
  });
};
const create$d = async ({
  webSocket
}) => {
  const firstWebSocketEvent = await waitForWebSocketToBeOpen(webSocket);
  if (firstWebSocketEvent.type === Error$3) {
    throw new IpcError(`WebSocket connection error`);
  }
  if (firstWebSocketEvent.type === Close) {
    throw new IpcError('Websocket connection was immediately closed');
  }
  return webSocket;
};
class IpcParentWithWebSocket extends Ipc {
  getData(event) {
    return parse(event.data);
  }
  send(message) {
    this._rawIpc.send(stringifyCompact(message));
  }
  sendAndTransfer(message) {
    throw new Error('sendAndTransfer not supported');
  }
  dispose() {
    this._rawIpc.close();
  }
  onClose(callback) {
    this._rawIpc.addEventListener('close', callback);
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
  }
}
const wrap = webSocket => {
  return new IpcParentWithWebSocket(webSocket);
};
const IpcParentWithWebSocket$1 = {
  __proto__: null,
  create: create$d,
  wrap
};

class CommandNotFoundError extends Error {
  constructor(command) {
    super(`Command not found ${command}`);
    this.name = 'CommandNotFoundError';
  }
}
const commands = Object.create(null);
const register = commandMap => {
  Object.assign(commands, commandMap);
};
const getCommand = key => {
  return commands[key];
};
const execute = (command, ...args) => {
  const fn = getCommand(command);
  if (!fn) {
    throw new CommandNotFoundError(command);
  }
  return fn(...args);
};

const Two$1 = '2.0';
const callbacks = Object.create(null);
const get$6 = id => {
  return callbacks[id];
};
const remove$2 = id => {
  delete callbacks[id];
};
class JsonRpcError extends Error {
  constructor(message) {
    super(message);
    this.name = 'JsonRpcError';
  }
}
const NewLine$1 = '\n';
const DomException = 'DOMException';
const ReferenceError$1 = 'ReferenceError';
const SyntaxError$1 = 'SyntaxError';
const TypeError$1 = 'TypeError';
const getErrorConstructor = (message, type) => {
  if (type) {
    switch (type) {
      case DomException:
        return DOMException;
      case ReferenceError$1:
        return ReferenceError;
      case SyntaxError$1:
        return SyntaxError;
      case TypeError$1:
        return TypeError;
      default:
        return Error;
    }
  }
  if (message.startsWith('TypeError: ')) {
    return TypeError;
  }
  if (message.startsWith('SyntaxError: ')) {
    return SyntaxError;
  }
  if (message.startsWith('ReferenceError: ')) {
    return ReferenceError;
  }
  return Error;
};
const constructError = (message, type, name) => {
  const ErrorConstructor = getErrorConstructor(message, type);
  if (ErrorConstructor === DOMException && name) {
    return new ErrorConstructor(message, name);
  }
  if (ErrorConstructor === Error) {
    const error = new Error(message);
    if (name && name !== 'VError') {
      error.name = name;
    }
    return error;
  }
  return new ErrorConstructor(message);
};
const joinLines = lines => {
  return lines.join(NewLine$1);
};
const splitLines = lines => {
  return lines.split(NewLine$1);
};
const getCurrentStack = () => {
  const stackLinesToSkip = 3;
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
  return currentStack;
};
const getNewLineIndex = (string, startIndex = undefined) => {
  return string.indexOf(NewLine$1, startIndex);
};
const getParentStack = error => {
  let parentStack = error.stack || error.data || error.message || '';
  if (parentStack.startsWith('    at')) {
    parentStack = error.message + NewLine$1 + parentStack;
  }
  return parentStack;
};
const MethodNotFound = -32601;
const Custom = -32001;
const restoreJsonRpcError = error => {
  const currentStack = getCurrentStack();
  if (error && error instanceof Error) {
    if (typeof error.stack === 'string') {
      error.stack = error.stack + NewLine$1 + currentStack;
    }
    return error;
  }
  if (error && error.code && error.code === MethodNotFound) {
    const restoredError = new JsonRpcError(error.message);
    const parentStack = getParentStack(error);
    restoredError.stack = parentStack + NewLine$1 + currentStack;
    return restoredError;
  }
  if (error && error.message) {
    const restoredError = constructError(error.message, error.type, error.name);
    if (error.data) {
      if (error.data.stack && error.data.type && error.message) {
        restoredError.stack = error.data.type + ': ' + error.message + NewLine$1 + error.data.stack + NewLine$1 + currentStack;
      } else if (error.data.stack) {
        restoredError.stack = error.data.stack;
      }
      if (error.data.codeFrame) {
        // @ts-ignore
        restoredError.codeFrame = error.data.codeFrame;
      }
      if (error.data.code) {
        // @ts-ignore
        restoredError.code = error.data.code;
      }
      if (error.data.type) {
        // @ts-ignore
        restoredError.name = error.data.type;
      }
    } else {
      if (error.stack) {
        const lowerStack = restoredError.stack || '';
        // @ts-ignore
        const indexNewLine = getNewLineIndex(lowerStack);
        const parentStack = getParentStack(error);
        // @ts-ignore
        restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
      }
      if (error.codeFrame) {
        // @ts-ignore
        restoredError.codeFrame = error.codeFrame;
      }
    }
    return restoredError;
  }
  if (typeof error === 'string') {
    return new Error(`JsonRpc Error: ${error}`);
  }
  return new Error(`JsonRpc Error: ${error}`);
};
const unwrapJsonRpcResult = responseMessage => {
  if ('error' in responseMessage) {
    const restoredError = restoreJsonRpcError(responseMessage.error);
    throw restoredError;
  }
  if ('result' in responseMessage) {
    return responseMessage.result;
  }
  throw new JsonRpcError('unexpected response message');
};
const warn$1 = (...args) => {
  console.warn(...args);
};
const resolve = (id, response) => {
  const fn = get$6(id);
  if (!fn) {
    console.log(response);
    warn$1(`callback ${id} may already be disposed`);
    return;
  }
  fn(response);
  remove$2(id);
};
const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
const getErrorType = prettyError => {
  if (prettyError && prettyError.type) {
    return prettyError.type;
  }
  if (prettyError && prettyError.constructor && prettyError.constructor.name) {
    return prettyError.constructor.name;
  }
  return undefined;
};
const isAlreadyStack = line => {
  return line.trim().startsWith('at ');
};
const getStack = prettyError => {
  const stackString = prettyError.stack || '';
  const newLineIndex = stackString.indexOf('\n');
  if (newLineIndex !== -1 && !isAlreadyStack(stackString.slice(0, newLineIndex))) {
    return stackString.slice(newLineIndex + 1);
  }
  return stackString;
};
const getErrorProperty = (error, prettyError) => {
  if (error && error.code === E_COMMAND_NOT_FOUND) {
    return {
      code: MethodNotFound,
      data: error.stack,
      message: error.message
    };
  }
  return {
    code: Custom,
    data: {
      code: prettyError.code,
      codeFrame: prettyError.codeFrame,
      name: prettyError.name,
      stack: getStack(prettyError),
      type: getErrorType(prettyError)
    },
    message: prettyError.message
  };
};
const create$1$1 = (id, error) => {
  return {
    error,
    id,
    jsonrpc: Two$1
  };
};
const getErrorResponse = (id, error, preparePrettyError, logError) => {
  const prettyError = preparePrettyError(error);
  logError(error, prettyError);
  const errorProperty = getErrorProperty(error, prettyError);
  return create$1$1(id, errorProperty);
};
const create$c = (message, result) => {
  return {
    id: message.id,
    jsonrpc: Two$1,
    result: result ?? null
  };
};
const getSuccessResponse = (message, result) => {
  const resultProperty = result ?? null;
  return create$c(message, resultProperty);
};
const getErrorResponseSimple = (id, error) => {
  return {
    error: {
      code: Custom,
      data: error,
      // @ts-ignore
      message: error.message
    },
    id,
    jsonrpc: Two$1
  };
};
const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
  try {
    const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
    return getSuccessResponse(message, result);
  } catch (error) {
    if (ipc.canUseSimpleErrorResponse) {
      return getErrorResponseSimple(message.id, error);
    }
    return getErrorResponse(message.id, error, preparePrettyError, logError);
  }
};
const defaultPreparePrettyError = error => {
  return error;
};
const defaultLogError = () => {
  // ignore
};
const defaultRequiresSocket = () => {
  return false;
};
const defaultResolve = resolve;

// TODO maybe remove this in v6 or v7, only accept options object to simplify the code
const normalizeParams = args => {
  if (args.length === 1) {
    const options = args[0];
    return {
      execute: options.execute,
      ipc: options.ipc,
      logError: options.logError || defaultLogError,
      message: options.message,
      preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
      requiresSocket: options.requiresSocket || defaultRequiresSocket,
      resolve: options.resolve || defaultResolve
    };
  }
  return {
    execute: args[2],
    ipc: args[0],
    logError: args[5],
    message: args[1],
    preparePrettyError: args[4],
    requiresSocket: args[6],
    resolve: args[3]
  };
};
const handleJsonRpcMessage = async (...args) => {
  const options = normalizeParams(args);
  const {
    execute,
    ipc,
    logError,
    message,
    preparePrettyError,
    requiresSocket,
    resolve
  } = options;
  if ('id' in message) {
    if ('method' in message) {
      const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
      try {
        ipc.send(response);
      } catch (error) {
        const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError);
        ipc.send(errorResponse);
      }
      return;
    }
    resolve(message.id, message);
    return;
  }
  if ('method' in message) {
    await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
    return;
  }
  throw new JsonRpcError('unexpected message');
};

const Two = '2.0';

const create$b = (method, params) => {
  return {
    jsonrpc: Two,
    method,
    params
  };
};

const create$a = (id, method, params) => {
  const message = {
    id,
    jsonrpc: Two,
    method,
    params
  };
  return message;
};

let id = 0;
const create$9 = () => {
  return ++id;
};

const registerPromise = map => {
  const id = create$9();
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  map[id] = resolve;
  return {
    id,
    promise
  };
};

const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer) => {
  const {
    id,
    promise
  } = registerPromise(callbacks);
  const message = create$a(id, method, params);
  if (useSendAndTransfer && ipc.sendAndTransfer) {
    ipc.sendAndTransfer(message);
  } else {
    ipc.send(message);
  }
  const responseMessage = await promise;
  return unwrapJsonRpcResult(responseMessage);
};
const createRpc = ipc => {
  const callbacks = Object.create(null);
  ipc._resolve = (id, response) => {
    const fn = callbacks[id];
    if (!fn) {
      console.warn(`callback ${id} may already be disposed`);
      return;
    }
    fn(response);
    delete callbacks[id];
  };
  const rpc = {
    async dispose() {
      await ipc?.dispose();
    },
    invoke(method, ...params) {
      return invokeHelper(callbacks, ipc, method, params, false);
    },
    invokeAndTransfer(method, ...params) {
      return invokeHelper(callbacks, ipc, method, params, true);
    },
    // @ts-ignore
    ipc,
    /**
     * @deprecated
     */
    send(method, ...params) {
      const message = create$b(method, params);
      ipc.send(message);
    }
  };
  return rpc;
};

const requiresSocket = () => {
  return false;
};
const preparePrettyError = error => {
  return error;
};
const logError = () => {
  // handled by renderer worker
};
const handleMessage = event => {
  const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
  const actualExecute = event?.target?.execute || execute;
  return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket);
};

const handleIpc = ipc => {
  if ('addEventListener' in ipc) {
    ipc.addEventListener('message', handleMessage);
  } else if ('on' in ipc) {
    // deprecated
    ipc.on('message', handleMessage);
  }
};

const listen$1 = async (module, options) => {
  const rawIpc = await module.listen(options);
  if (module.signal) {
    module.signal(rawIpc);
  }
  const ipc = module.wrap(rawIpc);
  return ipc;
};

const create$8 = async ({
  commandMap,
  isMessagePortOpen = true,
  messagePort
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const rawIpc = await IpcParentWithMessagePort$1.create({
    isMessagePortOpen,
    messagePort
  });
  const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  messagePort.start();
  return rpc;
};

const create$7 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  const {
    port1,
    port2
  } = new MessageChannel();
  await send(port1);
  return create$8({
    commandMap,
    isMessagePortOpen,
    messagePort: port2
  });
};

const createSharedLazyRpc = factory => {
  let rpcPromise;
  const getOrCreate = () => {
    if (!rpcPromise) {
      rpcPromise = factory();
    }
    return rpcPromise;
  };
  return {
    async dispose() {
      const rpc = await getOrCreate();
      await rpc.dispose();
    },
    async invoke(method, ...params) {
      const rpc = await getOrCreate();
      return rpc.invoke(method, ...params);
    },
    async invokeAndTransfer(method, ...params) {
      const rpc = await getOrCreate();
      return rpc.invokeAndTransfer(method, ...params);
    },
    async send(method, ...params) {
      const rpc = await getOrCreate();
      rpc.send(method, ...params);
    }
  };
};

const create$6 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  return createSharedLazyRpc(() => {
    return create$7({
      commandMap,
      isMessagePortOpen,
      send
    });
  });
};

const Https = 'https:';
const Ws = 'ws:';
const Wss = 'wss:';

const getWebSocketProtocol = locationProtocol => {
  return locationProtocol === Https ? Wss : Ws;
};

const getWebSocketUrl = (type, host, locationProtocol) => {
  const wsProtocol = getWebSocketProtocol(locationProtocol);
  return `${wsProtocol}//${host}/websocket/${type}`;
};

const getHost = () => {
  return location.host;
};
const getProtocol = () => {
  return location.protocol;
};

const create$5 = async ({
  commandMap,
  webSocket
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const rawIpc = await IpcParentWithWebSocket$1.create({
    webSocket
  });
  const ipc = IpcParentWithWebSocket$1.wrap(rawIpc);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  return rpc;
};

const create$4 = async ({
  commandMap,
  type
}) => {
  const host = getHost();
  const protocol = getProtocol();
  const wsUrl = getWebSocketUrl(type, host, protocol);
  const webSocket = new WebSocket(wsUrl);
  const rpc = await create$5({
    commandMap,
    webSocket
  });
  return rpc;
};

const create$3 = async ({
  commandMap,
  isMessagePortOpen,
  messagePort
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const rawIpc = await IpcParentWithMessagePort$1.create({
    isMessagePortOpen,
    messagePort
  });
  const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  return rpc;
};

const create$2 = async ({
  commandMap
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  return rpc;
};

const createMockRpc = ({
  commandMap
}) => {
  const invocations = [];
  const invoke = (method, ...params) => {
    invocations.push([method, ...params]);
    const command = commandMap[method];
    if (!command) {
      throw new Error(`command ${method} not found`);
    }
    return command(...params);
  };
  const mockRpc = {
    invocations,
    invoke,
    invokeAndTransfer: invoke
  };
  return mockRpc;
};

const rpcs$2 = Object.create(null);
const set$9 = (id, rpc) => {
  rpcs$2[id] = rpc;
};
const get$5 = id => {
  return rpcs$2[id];
};
const remove$1 = id => {
  delete rpcs$2[id];
};

/* eslint-disable  @typescript-eslint/explicit-function-return-type */
const create$1 = rpcId => {
  return {
    async dispose() {
      const rpc = get$5(rpcId);
      await rpc.dispose();
    },
    // @ts-ignore
    invoke(method, ...params) {
      const rpc = get$5(rpcId);
      // @ts-ignore
      return rpc.invoke(method, ...params);
    },
    // @ts-ignore
    invokeAndTransfer(method, ...params) {
      const rpc = get$5(rpcId);
      // @ts-ignore
      return rpc.invokeAndTransfer(method, ...params);
    },
    registerMockRpc(commandMap) {
      const mockRpc = createMockRpc({
        commandMap
      });
      set$9(rpcId, mockRpc);
      // @ts-ignore
      mockRpc[Symbol.dispose] = () => {
        remove$1(rpcId);
      };
      // @ts-ignore
      return mockRpc;
    },
    set(rpc) {
      set$9(rpcId, rpc);
    }
  };
};

const Web = 1;
const Electron = 2;
const Remote = 3;
const Test = 4;

const ExtensionHostWorker = 44;
const FileSystemWorker = 209;
const RendererWorker = 1;
const SharedProcess = 1492;

const {
  dispose,
  invoke: invoke$5,
  invokeAndTransfer: invokeAndTransfer$2,
  registerMockRpc,
  set: set$8
} = create$1(ExtensionHostWorker);
const executeReferenceProvider = async (id, offset) => {
  // @ts-ignore
  return invoke$5('ExtensionHostReference.executeReferenceProvider', id, offset);
};
const executeFileReferenceProvider = async id => {
  // @ts-ignore
  return invoke$5('ExtensionHostReference.executeFileReferenceProvider', id);
};
const getRuntimeStatus$2 = async extensionId => {
  // @ts-ignore
  return invoke$5('ExtensionHost.getRuntimeStatus', extensionId);
};
const getEnabledOutputProviderIds = async () => {
  const channels = await invoke$5('Output.getEnabledProviders');
  return channels;
};

const ExtensionHost = {
  __proto__: null,
  dispose,
  executeFileReferenceProvider,
  executeReferenceProvider,
  getEnabledOutputProviderIds,
  getRuntimeStatus: getRuntimeStatus$2,
  invoke: invoke$5,
  invokeAndTransfer: invokeAndTransfer$2,
  registerMockRpc,
  set: set$8
};

const {
  invoke: invoke$4,
  set: set$7
} = create$1(FileSystemWorker);
const readFile$1 = async uri => {
  return invoke$4('FileSystem.readFile', uri);
};
const writeFile = async (uri, content) => {
  return invoke$4('FileSystem.writeFile', uri, content);
};
const mkdir = async uri => {
  return invoke$4('FileSystem.mkdir', uri);
};
const exists = async uri => {
  return invoke$4('FileSystem.exists', uri);
};

const {
  invoke: invoke$3,
  invokeAndTransfer: invokeAndTransfer$1,
  set: set$6
} = create$1(RendererWorker);
const sendMessagePortToIconThemeWorker = async (port, rpcId) => {
  const command = 'IconTheme.handleMessagePort';
  await invokeAndTransfer$1('SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port, command, rpcId);
};
const sendMessagePortToFileSystemWorker$1 = async (port, rpcId) => {
  const command = 'FileSystem.handleMessagePort';
  await invokeAndTransfer$1('SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port, command, rpcId);
};
const sendMessagePortToExtensionHostWorker = async (port, rpcId = 0) => {
  const command = 'HandleMessagePort.handleMessagePort2';
  await invokeAndTransfer$1('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
};
const sendMessagePortToSharedProcess = async port => {
  const command = 'HandleElectronMessagePort.handleElectronMessagePort';
  await invokeAndTransfer$1('SendMessagePortToExtensionHostWorker.sendMessagePortToSharedProcess', port, command, 0);
};

const {
  invoke: invoke$2,
  set: set$5
} = create$1(SharedProcess);

const create = () => {
  return {
    finished: false
  };
};
const cancel = token => {
  token.finished = true;
};
const isCanceled = token => {
  return token.finished;
};

const None = 0;
const Importing = 1;
const Activating = 2;
const Activated = 3;
const Error$1 = 4;

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const createInitialState = () => {
  return {
    activatedExtensions: Object.create(null),
    cachedActivationEvents: Object.create(null),
    cachedExtensions: undefined,
    disabledIds: [],
    platform: 0,
    runtimeStatuses: Object.create(null),
    webExtensions: []
  };
};
const createEmptyRuntimeStatus = id => {
  return {
    activationEndTime: 0,
    activationEvent: '',
    activationStartTime: 0,
    activationTime: 0,
    id,
    importEndTime: 0,
    importStartTime: 0,
    importTime: 0,
    status: None
  };
};
const state$1 = {
  extensionsState: createInitialState()
};
const get$4 = () => {
  return state$1.extensionsState;
};
const set$4 = newState => {
  state$1.extensionsState = newState;
};
const update = newState => {
  set$4({
    ...state$1.extensionsState,
    ...newState
  });
};
const setPlatform = platform => {
  update({
    platform
  });
};
const hasWebExtensionUri = uri => {
  return state$1.extensionsState.webExtensions.some(extension => extension.uri === uri);
};
const addWebExtension$1 = extension => {
  update({
    webExtensions: [...state$1.extensionsState.webExtensions, extension]
  });
};
const clearCachedExtensions = () => {
  update({
    cachedExtensions: undefined
  });
};
const setRuntimeStatus = status => {
  update({
    runtimeStatuses: {
      ...state$1.extensionsState.runtimeStatuses,
      [status.id]: {
        ...status
      }
    }
  });
};
const updateRuntimeStatus = (id, statusUpdate) => {
  const previousStatus = state$1.extensionsState.runtimeStatuses[id] || createEmptyRuntimeStatus(id);
  setRuntimeStatus({
    ...previousStatus,
    ...statusUpdate,
    id
  });
};
const getRuntimeStatus$1 = extensionId => {
  return state$1.extensionsState.runtimeStatuses[extensionId];
};

const baseName = path => {
  const slashIndex = path.lastIndexOf('/');
  return path.slice(slashIndex + 1);
};
const getExtensionId$4 = extension => {
  if (extension && extension.id) {
    return extension.id;
  }
  if (extension && extension.path) {
    return baseName(extension.path);
  }
  return '<unknown>';
};

const isImportErrorChrome = error => {
  return Boolean(error && error instanceof Error && error.message.startsWith('Failed to fetch dynamically imported module'));
};

const isImportErrorFirefox = error => {
  return Boolean(error && error instanceof TypeError && error.message === 'error loading dynamically imported module');
};

const isSyntaxError = error => {
  return error instanceof SyntaxError;
};

const isImportError = error => {
  return isImportErrorChrome(error) || isImportErrorFirefox(error) || isSyntaxError(error);
};

const sleep = duration => {
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  setTimeout(resolve, duration);
  return promise;
};

const NotFound = 404;

const tryToGetActualImportErrorMessage = async (url, error) => {
  let response;
  try {
    response = await fetch(url);
  } catch (error) {
    return `Failed to import ${url}: ${error}`;
  }
  if (response.ok) {
    throw new Error(`Failed to import ${url}: Unknown Error`);
  }
  switch (response.status) {
    case NotFound:
      throw new Error(`Failed to import ${url}: Not found (404)`);
    default:
      return `Failed to import ${url}: ${error}`;
  }
};

// TODO make activation timeout configurable or remove it.
// some extension might do workspace indexing which could take some time
const activationTimeout = 10_000;
const rejectAfterTimeout = async (timeout, token) => {
  await sleep(timeout);
  if (isCanceled(token)) {
    return;
  }
  throw new Error(`Activation timeout of ${timeout}ms exceeded`);
};
const activate = async (extensionId, extension, extensionHost) => {
  await extensionHost.invoke('ExtensionHost.activateExtension3', extensionId, extension);
};
const activateExtension2 = async (extensionId, extension, absolutePath, extensionHost = ExtensionHost) => {
  string(extensionId);
  object(extension);
  string(absolutePath);
  const token = create();
  try {
    const startTime = performance.now();
    updateRuntimeStatus(extensionId, {
      activationStartTime: startTime,
      status: Activating
    });
    await Promise.race([activate(extensionId, extension, extensionHost), rejectAfterTimeout(activationTimeout, token)]);
    const endTime = performance.now();
    const time = endTime - startTime;
    updateRuntimeStatus(extensionId, {
      activationEndTime: endTime,
      activationTime: time,
      status: Activated
    });
  } catch (error) {
    const id = getExtensionId$4(extension);
    if (isImportError(error)) {
      const actualErrorMessage = await tryToGetActualImportErrorMessage(absolutePath, error);
      throw new Error(`Failed to activate extension ${id}: ${actualErrorMessage}`, {
        cause: error
      });
    }
    updateRuntimeStatus(extensionId, {
      status: Error$1 // TODO maybe store error also in runtime status state
    });
    throw new VError(error, `Failed to activate extension ${id}`);
  } finally {
    cancel(token);
  }
};

const commandMapRef = {};

const rpcs$1 = Object.create(null);
const get$3 = extensionId => {
  return rpcs$1[extensionId];
};
const getAll = () => {
  return Object.values(rpcs$1);
};
const set$3 = (extensionId, rpc) => {
  rpcs$1[extensionId] = rpc;
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
const invoke$1 = (method, ...params) => {
  return invoke$3(method, ...params);
};
const invokeAndTransfer = (method, ...params) => {
  return invokeAndTransfer$1(method, ...params);
};

const createIsolatedExtensionHostWorker = async (extensionId, absolutePath, workerName, createRpc, invokeAndTransfer) => {
  return createRpc({
    commandMap: commandMapRef,
    isMessagePortOpen: true,
    send(port) {
      return invokeAndTransfer('LaunchIsolatedExtensionHostWorker.launchIsolatedExtensionHostWorker', port, extensionId, absolutePath, workerName);
    }
  });
};
const getOrCreateIsolatedExtensionHostWorker = async (extensionId, absolutePath, workerName = '') => {
  const existingRpc = get$3(extensionId);
  if (existingRpc) {
    return existingRpc;
  }
  const rpc = await createIsolatedExtensionHostWorker(extensionId, absolutePath, workerName, create$7, invokeAndTransfer);
  set$3(extensionId, rpc);
  return rpc;
};

const rpcs = Object.create(null);
const add = (id, rpc) => {
  rpcs[id] = rpc;
};
const get$2 = id => {
  return rpcs[id];
};

const getUrlPrefix = (platform, extensionPath) => {
  if (extensionPath.startsWith('http://') || extensionPath.startsWith('https://')) {
    return extensionPath;
  }
  if (platform === Web) {
    return extensionPath;
  }
  if (extensionPath.startsWith('/')) {
    return `/remote${extensionPath}`;
  }
  return `/remote/${extensionPath}`;
};

const handleRpcInfos = (extension, platform) => {
  try {
    if (!extension) {
      return;
    }
    const rpcs = extension.rpc;
    if (!rpcs) {
      return;
    }
    if (!Array.isArray(rpcs)) {
      return;
    }
    const urlPrefix = getUrlPrefix(platform, extension.path);
    for (const rpc of rpcs) {
      rpc.url = `${urlPrefix}/${rpc.url}`;
      add(rpc.id, rpc);
    }
  } catch (error) {
    console.warn(`Failed to handle extension rpcs: ${error}`);
  }
};

const importExtension = async (extensionId, absolutePath, activationEvent, extensionHost = ExtensionHost) => {
  try {
    string(absolutePath);
    const startTime = performance.now();
    setRuntimeStatus({
      activationEndTime: 0,
      activationEvent: activationEvent,
      activationStartTime: performance.now(),
      activationTime: 0,
      id: extensionId,
      importEndTime: 0,
      importStartTime: startTime,
      importTime: 0,
      status: Importing
    });
    try {
      await extensionHost.invoke('ExtensionHost.importExtension2', extensionId, absolutePath);
      const endTime = performance.now();
      const time = endTime - startTime;
      updateRuntimeStatus(extensionId, {
        importEndTime: endTime,
        importTime: time
      });
    } catch (error) {
      updateRuntimeStatus(extensionId, {
        status: Error$1 // TODO maybe store error also in runtime status state
      });
      if (isImportError(error)) {
        const actualErrorMessage = await tryToGetActualImportErrorMessage(absolutePath, error);
        throw new Error(actualErrorMessage, {
          cause: error
        });
      }
      throw error;
    }
  } catch (error) {
    throw new VError(error, `Failed to import extension ${extensionId}`);
  }
};

const NewLine = '\n';
const Slash = '/';

const interExtensionId = path => {
  const slashIndex = path.lastIndexOf(Slash);
  return path.slice(slashIndex + 1);
};

const isExtensionIsolated = extension => {
  return extension?.isolated === true;
};

const activateExtension3 = async (extension, absolutePath, activationEvent, platform) => {
  handleRpcInfos(extension, platform);
  const extensionId = extension.id || interExtensionId(extension.uri);
  if (isExtensionIsolated(extension)) {
    await getOrCreateIsolatedExtensionHostWorker(extensionId, absolutePath, extension.workerName || '');
    return;
  }
  await importExtension(extensionId, absolutePath, activationEvent);
  await activateExtension2(extensionId, extension, absolutePath);
};

const getExtensionAbsolutePath = (id, isWeb, isBuiltin, path, relativePath, origin, platform, assetDir) => {
  if (path.startsWith('http')) {
    if (path.endsWith('/')) {
      return new URL(relativePath, path).href;
    }
    return new URL(relativePath, path + '/').href;
  }
  if (!path.startsWith('/')) {
    path = '/' + path;
  }
  if (isWeb) {
    return path + '/' + relativePath;
  }
  if (platform === Web) {
    return path + '/' + relativePath;
  }
  if (isBuiltin) {
    return `${assetDir}/extensions/${id}/${relativePath}`;
  }
  return new URL('/remote' + path + '/' + relativePath, origin).href;
};

const isMissingAssetDir = assetDir => {
  return typeof assetDir !== 'string' || assetDir.length === 0;
};
const isMissingPlatform = platform => {
  return typeof platform !== 'number' || platform === 0;
};
const isStaticHttpAssetDir = assetDir => {
  return assetDir.startsWith('/') || assetDir.startsWith('http');
};
const isHttpLocation = () => {
  return Reflect.has(globalThis, 'location') && globalThis.location.protocol.startsWith('http');
};
const getRuntimeContext = async (assetDir, platform) => {
  const shouldInferPlatform = isMissingPlatform(platform);
  const resolvedAssetDir = isMissingAssetDir(assetDir) ? await invoke$3('Layout.getAssetDir') : assetDir;
  const resolvedPlatform = shouldInferPlatform ? await invoke$3('Layout.getPlatform') : platform;
  if (shouldInferPlatform && isHttpLocation() && isStaticHttpAssetDir(resolvedAssetDir)) {
    return {
      assetDir: resolvedAssetDir,
      platform: Web
    };
  }
  return {
    assetDir: resolvedAssetDir,
    platform: resolvedPlatform
  };
};

const getResponseErrorMessage = response => {
  return response.statusText || String(response.status) || 'Request failed';
};
const getJson$1 = async url => {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(getResponseErrorMessage(response));
    }
    const json = await response.json();
    return json;
  } catch (error) {
    throw new VError(error, `Failed to get json`);
  }
};

const getWebExtensionsUrl = assetDir => {
  return `${assetDir}/config/extensions.json`;
};

const getWebExtensions = async assetDir => {
  try {
    return await getJson$1(getWebExtensionsUrl(assetDir));
  } catch {
    return [];
  }
};

const isExtensionCompatible = (extension, platform) => {
  return platform !== Web || extension?.compatibility?.web !== false;
};

const WorkspaceConfigFolderName = '.lvce';
const DisabledExtensionsFileName = 'disabled-extensions.json';
const UriSchemeRegex = /^[a-zA-Z][a-zA-Z\d+.-]*:/;
const WindowsDrivePathRegex = /^[a-zA-Z]:[\\/]/;
const WindowsDriveSegmentRegex = /^[a-zA-Z]:$/;
const encodePathSegment = (segment, index) => {
  if (index === 0 && WindowsDriveSegmentRegex.test(segment)) {
    return segment;
  }
  return encodeURIComponent(segment);
};
const encodeFilePath = path => {
  return path.split('/').map(encodePathSegment).join('/');
};
const toWorkspaceUri = workspacePath => {
  if (WindowsDrivePathRegex.test(workspacePath)) {
    return `file:///${encodeFilePath(workspacePath.replaceAll('\\', '/'))}`;
  }
  if (UriSchemeRegex.test(workspacePath)) {
    return workspacePath;
  }
  if (workspacePath.startsWith('/')) {
    return `file://${encodeFilePath(workspacePath)}`;
  }
  return workspacePath;
};
const joinUri = (base, ...parts) => {
  const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
  return [normalizedBase, ...parts].join('/');
};
const stringifyJson = data => {
  return JSON.stringify(data, null, 2) + '\n';
};
const getWorkspaceUri = async () => {
  const workspacePath = await invoke$3('Workspace.getPath');
  return toWorkspaceUri(workspacePath);
};
const getWorkspaceConfigDirUri = async () => {
  const workspaceUri = await getWorkspaceUri();
  return joinUri(workspaceUri, WorkspaceConfigFolderName);
};
const getWorkspaceDisabledExtensionsJsonUri = async () => {
  const configDirUri = await getWorkspaceConfigDirUri();
  return joinUri(configDirUri, DisabledExtensionsFileName);
};
const parseDisabledExtensions = content => {
  const parsed = JSON.parse(content);
  if (!Array.isArray(parsed.disabledExtensions)) {
    return [];
  }
  return parsed.disabledExtensions.filter(item => typeof item === 'string');
};
const readDisabledExtensionIdsFromUri = async uri => {
  const exists$1 = await exists(uri);
  if (!exists$1) {
    return [];
  }
  const content = await readFile$1(uri);
  return parseDisabledExtensions(content);
};
const readDisabledExtensionIds = async () => {
  const uri = await getWorkspaceDisabledExtensionsJsonUri();
  return readDisabledExtensionIdsFromUri(uri);
};
const readDisabledExtensionIdsSafe = async () => {
  try {
    return await readDisabledExtensionIds();
  } catch {
    return [];
  }
};
const writeDisabledExtensionIds = async (uri, disabledExtensions) => {
  await writeFile(uri, stringifyJson({
    disabledExtensions
  }));
};
const disableExtension$1 = async id => {
  string(id);
  const configDirUri = await getWorkspaceConfigDirUri();
  const uri = joinUri(configDirUri, DisabledExtensionsFileName);
  const configDirExists = await exists(configDirUri);
  if (!configDirExists) {
    await mkdir(configDirUri);
  }
  const oldDisabled = await readDisabledExtensionIdsFromUri(uri);
  const newDisabled = oldDisabled.includes(id) ? oldDisabled : [...oldDisabled, id];
  await writeDisabledExtensionIds(uri, newDisabled);
};
const enableExtension$1 = async id => {
  string(id);
  const uri = await getWorkspaceDisabledExtensionsJsonUri();
  const exists$1 = await exists(uri);
  if (!exists$1) {
    return;
  }
  const oldDisabled = await readDisabledExtensionIdsFromUri(uri);
  const newDisabled = oldDisabled.filter(item => item !== id);
  await writeDisabledExtensionIds(uri, newDisabled);
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const withWorkspaceDisabledState = (extensions, disabledIds) => {
  if (disabledIds.length === 0) {
    return extensions;
  }
  const disabledIdsSet = new Set(disabledIds);
  return extensions.map(extension => {
    if (!disabledIdsSet.has(extension.id)) {
      return extension;
    }
    return {
      ...extension,
      disabled: true
    };
  });
};
const getExtensionsWithWorkspaceState = async extensions => {
  if (extensions.length === 0) {
    return extensions;
  }
  const workspaceDisabledIds = await readDisabledExtensionIdsSafe();
  return withWorkspaceDisabledState(extensions, workspaceDisabledIds);
};
const getAllExtensionsWithState = async (extensionsState, assetDir, platform) => {
  const {
    assetDir: resolvedAssetDir,
    platform: resolvedPlatform
  } = await getRuntimeContext(assetDir, platform);
  string(resolvedAssetDir);
  number(resolvedPlatform);
  const meta = extensionsState.webExtensions;
  if (resolvedPlatform === Web) {
    const webExtensions = await getWebExtensions(resolvedAssetDir);
    const compatibleExtensions = [...webExtensions, ...meta].filter(extension => isExtensionCompatible(extension, resolvedPlatform));
    return getExtensionsWithWorkspaceState(compatibleExtensions);
  }
  const local = await invoke$2('ExtensionManagement.getAllExtensions');
  return getExtensionsWithWorkspaceState([...local, ...meta]);
};

const getAllExtensions = async (assetDir, platform) => {
  return getAllExtensionsWithState(get$4(), assetDir, platform);
};

const activatingExtensions = Object.create(null);
const runningExtensions = Object.create(null);
const matchesEvent = (extension, event) => {
  return !extension.disabled && isExtensionIsolated(extension) && Array.isArray(extension.activation) && extension.activation.includes(event);
};
const getExtensionId$3 = extension => {
  return extension.id;
};
const getAbsolutePath$1 = (extension, assetDir, platform) => {
  return getExtensionAbsolutePath(extension.id, extension.isWeb, extension.builtin, extension.path || extension.uri, extension.browser, globalThis.location.origin, platform, assetDir);
};
const doActivateExtension = async (extension, absolutePath, event, platform) => {
  const extensionId = getExtensionId$3(extension);
  try {
    await activateExtension3(extension, absolutePath, event, platform);
    runningExtensions[extensionId] = true;
  } finally {
    delete activatingExtensions[extensionId];
  }
};
const activateExtension = async (extension, event, assetDir, platform) => {
  const extensionId = getExtensionId$3(extension);
  if (runningExtensions[extensionId]) {
    return;
  }
  if (!Object.hasOwn(activatingExtensions, extensionId)) {
    const absolutePath = getAbsolutePath$1(extension, assetDir, platform);
    activatingExtensions[extensionId] = doActivateExtension(extension, absolutePath, event, platform);
  }
  await activatingExtensions[extensionId];
};
const activateByEvent = async (event, assetDir, platform) => {
  try {
    if (event === 'none') {
      await Promise.all(Object.values(activatingExtensions));
      return {
        error: undefined,
        hasActivatedExtensions: Object.keys(activatingExtensions).length > 0
      };
    }
    const {
      assetDir: resolvedAssetDir,
      platform: resolvedPlatform
    } = await getRuntimeContext(assetDir, platform);
    const extensions = await getAllExtensions(resolvedAssetDir, resolvedPlatform);
    const matchingExtensions = extensions.filter(extension => matchesEvent(extension, event));
    for (const extension of matchingExtensions) {
      await activateExtension(extension, event, resolvedAssetDir, resolvedPlatform);
    }
    return {
      error: undefined,
      hasActivatedExtensions: matchingExtensions.length > 0
    };
  } catch (error) {
    return {
      error: error instanceof Error ? error : new Error(String(error)),
      hasActivatedExtensions: false
    };
  }
};

const getWebExtensionManifest = async (path, manifestPath) => {
  try {
    const manifest = await getJson$1(manifestPath);
    return {
      ...manifest,
      path,
      uri: path
    };
  } catch (error) {
    const id = interExtensionId(path);
    throw new VError(error, `Failed to load extension manifest for ${id}`);
  }
};

const getWebManifestPath = path => {
  const manifestPath = `${path}/extension.json`;
  return manifestPath;
};

const invalidateExtensionsCache = async () => {
  await invoke$3('ExtensionManagement.invalidateExtensionsCache');
};

const state = {
  rpc: undefined
};
const set$2 = value => {
  state.rpc = value;
};
const invoke = async (method, ...params) => {
  if (!state.rpc) {
    return undefined;
  }
  return state.rpc.invoke(method, ...params);
};

const handleChange = async id => {
  await invoke('StatusBar.handleChange', id);
};

const hasStatusBarItems = manifest => {
  return Array.isArray(manifest.statusBarItems) && manifest.statusBarItems.length > 0;
};
const addWebExtension = async path => {
  if (hasWebExtensionUri(path)) {
    return undefined;
  }
  const manifestPath = getWebManifestPath(path);
  const manifest = await getWebExtensionManifest(path, manifestPath);
  addWebExtension$1(manifest);
  clearCachedExtensions();
  await invalidateExtensionsCache();
  if (hasStatusBarItems(manifest)) {
    await handleChange(manifest.id || path);
  }
  return manifest;
};

const ModuleWorkerAndWorkaroundForChromeDevtoolsBug = 6;

const createWebViewWorkerRpc2 = async (rpcInfo, port) => {
  // TODO this function is called from the iframe worker to create a direct
  // connection between a webview/iframe and it's webworker. For this to work
  // the iframe worker creates a messagechannel and sends one messageport to the webview
  // and the other messageport to the webworker. This enables direct communication via
  // the two message ports

  // TODO have a way so that the worker already includes the webview api and the extension
  // host sub-worker doesn't need to import the other file
  await invokeAndTransfer('IpcParent.create', {
    method: ModuleWorkerAndWorkaroundForChromeDevtoolsBug,
    name: rpcInfo.name,
    port,
    raw: true,
    url: rpcInfo.url
  });
};

const sourcePathMarker = '/extension-management-worker/src/';
const getExtensionHostSubWorkerUrl = (currentUrl = import.meta.url) => {
  const relativePath = currentUrl.includes(sourcePathMarker) ? '../../../../extension-host-sub-worker/src/extensionHostSubWorkerMain.js' : '../../extension-host-sub-worker/dist/extensionHostSubWorkerMain.js';
  return new URL(relativePath, currentUrl).href;
};
const extensionHostSubWorkerUrl = getExtensionHostSubWorkerUrl();

// TODO

/**
 * @deprecated use createWebViewWorkerRpc2 which passes the worker url as a parameter
 */
const createWebViewWorkerRpc = async (rpcInfo, port) => {
  object(rpcInfo);
  object(port);
  // TODO this function is called from the iframe worker to create a direct
  // connection between a webview/iframe and it's webworker. For this to work
  // the iframe worker creates a messagechannel and sends one messageport to the webview
  // and the other messageport to the webworker. This enables direct communication via
  // the two message ports

  // TODO have a way so that the worker already includes the webview api and the extension
  // host sub-worker doesn't need to import the other file
  await invokeAndTransfer$1('IpcParent.create', {
    method: ModuleWorkerAndWorkaroundForChromeDevtoolsBug,
    name: rpcInfo.name,
    port,
    raw: true,
    url: extensionHostSubWorkerUrl
  });
};

const ContentType = 'Content-Type';
const ContentLength = 'Content-Length';

const createResponseFromData = data => {
  const responseString = JSON.stringify(data);
  const response = new Response(responseString, {
    headers: {
      [ContentLength]: String(responseString.length),
      [ContentType]: 'application/json'
    }
  });
  return response;
};

const cacheName = 'Extensions'; // TODO

const getJson = async cacheKey => {
  const response = await caches.match(cacheKey, {
    cacheName
  });
  if (!response) {
    return undefined;
  }
  const json = await response.json();
  return json;
};
const setJson = async (cacheKey, data) => {
  try {
    const cache = await caches.open(cacheName);
    const response = createResponseFromData(data);
    await cache.put(cacheKey, response);
  } catch (error) {
    throw new VError(error, `Failed to add to cache`);
  }
};

const disabledExtensionsCacheKey = '/cache/disabledExtensions.json';

const disableExtension2$1 = async (id, platform) => {
  const isTest = platform === Test;
  const isWeb = platform === Web;
  const oldState = get$4(); // TODO maybe pass in an application id? Would allow multiple editors with different extensions.
  if (isTest) {
    const newState = {
      ...oldState,
      disabledIds: [...oldState.disabledIds, id]
    };
    set$4(newState);
  } else if (isWeb) {
    const cached = await getJson(disabledExtensionsCacheKey);
    const oldDisabled = cached?.disabledExtensions || [];
    const newDisabled = [...oldDisabled, id];
    const newData = {
      disabledExtensions: newDisabled
    };
    await setJson(disabledExtensionsCacheKey, newData);
  } else {
    await invoke$2('ExtensionManagement.disable', id);
  }
};
const enableExtension2$1 = async (id, platform) => {
  const isTest = platform === Test;
  const isWeb = platform === Web;
  const oldState = get$4();
  if (isTest) {
    const newState = {
      ...oldState,
      disabledIds: oldState.disabledIds.filter(existing => existing !== id)
    };
    set$4(newState);
  } else if (isWeb) {
    const cached = await getJson(disabledExtensionsCacheKey);
    const oldDisabled = cached?.disabledExtensions || [];
    const newDisabled = oldDisabled.filter(item => item !== id);
    const newData = {
      disabledExtensions: newDisabled
    };
    await setJson(disabledExtensionsCacheKey, newData);
  }
};

const disableExtension2 = async (id, platform) => {
  string(id);
  number(platform);
  try {
    await disableExtension2$1(id, platform);
    await invalidateExtensionsCache();
    return undefined;
  } catch (error) {
    return error;
  }
};

const disableExtension = async (id, isTest) => {
  const oldState = get$4();
  return disableExtension2(id, oldState.platform);
};

const disableWorkspaceExtension = async id => {
  string(id);
  await disableExtension$1(id);
  await invalidateExtensionsCache();
};

const enableExtension2 = async (id, platform) => {
  string(id);
  number(platform);
  if (platform === Remote || platform === Electron) {
    const disabledExtensionsJsonPath = await invoke$3('WebView.compatSharedProcessInvoke', 'PlatformPaths.getDisabledExtensionsJsonUri');
    const exists$1 = await exists(disabledExtensionsJsonPath);
    if (!exists$1) {
      return undefined;
    }
    const content = await readFile$1(disabledExtensionsJsonPath);
    const parsed = JSON.parse(content);
    const oldDisabled = parsed.disabledExtensions || [];
    const newDisabled = oldDisabled.filter(item => item !== id);
    const newData = {
      disabledExtensions: newDisabled
    };
    const newContent = JSON.stringify(newData, null, 2) + '\n';
    await writeFile(disabledExtensionsJsonPath, newContent);
  }
  await enableExtension2$1(id, platform);
  await invalidateExtensionsCache();
};

const enableExtension = async (id, isTest) => {
  const oldState = get$4();
  return enableExtension2(id, oldState.platform);
};

const enableWorkspaceExtension = async id => {
  string(id);
  await enableExtension$1(id);
  await invalidateExtensionsCache();
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const getExtensionId$2 = extension => {
  return extension.id || interExtensionId(extension.uri || extension.path || '');
};
const contributesCommand = (extension, id) => {
  return Array.isArray(extension.commands) && extension.commands.some(command => command.id === id);
};
const getContributingExtension = async (extensionsState, id, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, '', platform);
  return extensions.find(extension => isExtensionIsolated(extension) && contributesCommand(extension, id));
};
const getRpcForCommand = async (extensionsState, id, platform) => {
  const extension = await getContributingExtension(extensionsState, id, platform);
  if (!extension) {
    return undefined;
  }
  const extensionId = getExtensionId$2(extension);
  const existingRpc = get$3(extensionId);
  if (existingRpc) {
    return existingRpc;
  }
  await activateByEvent(`onCommand:${id}`, '', platform);
  return get$3(extensionId);
};
const executeRendererCommand = (id, args) => {
  return invoke$3(id, ...args);
};
const executeCommand = async (extensionsState, id, ...args) => {
  const {
    result,
    wasFound
  } = await executeExtensionCommand(extensionsState, id, ...args);
  if (wasFound) {
    return result;
  }
  return executeRendererCommand(id, args);
};
const executeExtensionCommand = async (extensionsState, id, ...args) => {
  const {
    platform
  } = extensionsState;
  const rpc = await getRpcForCommand(extensionsState, id, platform);
  if (rpc) {
    const result = await rpc.invoke('ExtensionApi.executeCommand', id, ...args);
    return {
      result,
      wasFound: true
    };
  }
  return {
    result: undefined,
    wasFound: false
  };
};

const getOrigin = () => {
  return globalThis.location?.origin || 'http://localhost';
};

const getExtensionId$1 = extension => {
  return extension.id || interExtensionId(extension.uri || extension.path || '');
};
const getAbsolutePath = (extension, assetDir, platform) => {
  return getExtensionAbsolutePath(getExtensionId$1(extension), extension.isWeb === true, extension.builtin === true, extension.path || extension.uri || '', extension.browser || '', getOrigin(), platform, assetDir);
};
const getRpc$1 = async (extension, assetDir, platform) => {
  const extensionId = getExtensionId$1(extension);
  const existingRpc = get$3(extensionId);
  if (existingRpc) {
    return existingRpc;
  }
  const absolutePath = getAbsolutePath(extension, assetDir, platform);
  return getOrCreateIsolatedExtensionHostWorker(extensionId, absolutePath, extension.workerName || '');
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const contributesCompletionProvider = (extension, languageId) => {
  return Array.isArray(extension.completionProviders) && extension.completionProviders.some(provider => provider.languageId === languageId);
};
const getMatchingExtensions$4 = async (extensionsState, textDocument, assetDir, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, assetDir, platform);
  return extensions.filter(extension => isExtensionIsolated(extension) && contributesCompletionProvider(extension, textDocument.languageId));
};
const executeRpcCompletionProvider = async (rpc, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeCompletionProvider', textDocument, ...args);
};
const executeRpcResolveCompletionItemProvider = async (rpc, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeResolveCompletionItemProvider', textDocument, ...args);
};
const executeCompletionProvider = async (extensionsState, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions$4(extensionsState, textDocument, assetDir, platform);
  const rpcs = await Promise.all(extensions.map(extension => getRpc$1(extension, assetDir, platform)));
  const results = await Promise.all(rpcs.map(rpc => executeRpcCompletionProvider(rpc, textDocument, args)));
  return results[0] || [];
};
const executeResolveCompletionItemProvider = async (extensionsState, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions$4(extensionsState, textDocument, assetDir, platform);
  const rpcs = await Promise.all(extensions.map(extension => getRpc$1(extension, assetDir, platform)));
  const results = await Promise.all(rpcs.map(rpc => executeRpcResolveCompletionItemProvider(rpc, textDocument, args)));
  return results[0];
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const contributesDiagnosticProvider = (extension, languageId) => {
  return Array.isArray(extension.diagnosticProviders) && extension.diagnosticProviders.some(provider => provider.languageId === languageId);
};
const getMatchingExtensions$3 = async (extensionsState, textDocument, assetDir, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, assetDir, platform);
  return extensions.filter(extension => isExtensionIsolated(extension) && contributesDiagnosticProvider(extension, textDocument.languageId));
};
const executeRpcDiagnosticProvider = async (rpc, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeDiagnosticProvider', textDocument, ...args);
};
const executeDiagnosticProvider = async (extensionsState, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions$3(extensionsState, textDocument, assetDir, platform);
  const rpcs = await Promise.all(extensions.map(extension => getRpc$1(extension, assetDir, platform)));
  const results = await Promise.all(rpcs.map(rpc => executeRpcDiagnosticProvider(rpc, textDocument, args)));
  return results[0] || [];
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const contributesFormattingProvider = (extension, languageId) => {
  return Array.isArray(extension.formattingProviders) && extension.formattingProviders.some(provider => provider.languageId === languageId);
};
const getMatchingExtensions$2 = async (extensionsState, textDocument, assetDir, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, assetDir, platform);
  return extensions.filter(extension => isExtensionIsolated(extension) && contributesFormattingProvider(extension, textDocument.languageId));
};
const executeRpcFormattingProvider = async (rpc, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeFormattingProvider', textDocument, ...args);
};
const executeFormattingProvider = async (extensionsState, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions$2(extensionsState, textDocument, assetDir, platform);
  const rpcs = await Promise.all(extensions.map(extension => getRpc$1(extension, assetDir, platform)));
  const results = await Promise.all(rpcs.map(rpc => executeRpcFormattingProvider(rpc, textDocument, args)));
  return results[0] || [];
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const contributesHoverProvider = (extension, languageId) => {
  return Array.isArray(extension.hoverProviders) && extension.hoverProviders.some(provider => provider.languageId === languageId);
};
const getMatchingExtensions$1 = async (extensionsState, textDocument, assetDir, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, assetDir, platform);
  return extensions.filter(extension => isExtensionIsolated(extension) && contributesHoverProvider(extension, textDocument.languageId));
};
const executeRpcHoverProvider = async (rpc, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeHoverProvider', textDocument, ...args);
};
const executeHoverProvider = async (extensionsState, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions$1(extensionsState, textDocument, assetDir, platform);
  const rpcs = await Promise.all(extensions.map(extension => getRpc$1(extension, assetDir, platform)));
  const results = await Promise.all(rpcs.map(rpc => executeRpcHoverProvider(rpc, textDocument, args)));
  return results[0];
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const activationEventByKind = {
  'brace completion': 'onBraceCompletion',
  'closing tag': 'onClosingTag',
  definition: 'onDefinition',
  implementation: 'onImplementation',
  reference: 'onReferences',
  rename: 'onRename',
  'tab completion': 'onTabCompletion',
  'type definition': 'onTypeDefinition'
};
const contributesLanguageProvider = (extension, kind, languageId) => {
  const activationEvent = activationEventByKind[kind] || 'onLanguage';
  return Array.isArray(extension.activation) && extension.activation.includes(`${activationEvent}:${languageId}`);
};
const getMatchingExtensions = async (extensionsState, kind, textDocument, assetDir, platform) => {
  const extensions = await getAllExtensionsWithState(extensionsState, assetDir, platform);
  return extensions.filter(extension => isExtensionIsolated(extension) && contributesLanguageProvider(extension, kind, textDocument.languageId));
};
const executeRpcLanguageProvider = async (rpc, kind, methodName, textDocument, args) => {
  return rpc.invoke('ExtensionApi.executeLanguageProvider', kind, methodName, textDocument, ...args);
};
const executeLanguageProvider = async (extensionsState, kind, methodName, textDocument, ...args) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions(extensionsState, kind, textDocument, assetDir, platform);
  if (extensions.length === 0) {
    return {
      found: false
    };
  }
  const rpc = await getRpc$1(extensions[0], assetDir, platform);
  const result = await executeRpcLanguageProvider(rpc, kind, methodName, textDocument, args);
  return {
    found: true,
    result
  };
};
const executeOrganizeImportsProvider = async (extensionsState, textDocument) => {
  const {
    assetDir,
    platform
  } = await getRuntimeContext('', extensionsState.platform);
  const extensions = await getMatchingExtensions(extensionsState, 'code action', textDocument, assetDir, platform);
  if (extensions.length === 0) {
    return {
      found: false
    };
  }
  const rpc = await getRpc$1(extensions[0], assetDir, platform);
  const result = await rpc.invoke('ExtensionApi.executeOrganizeImportsProvider', textDocument);
  return {
    found: true,
    result
  };
};

const readFile = uri => {
  return readFile$1(uri);
};

const instances = Object.create(null);
const set$1 = (uid, instance) => {
  instances[uid] = instance;
};
const get$1 = uid => {
  return instances[uid];
};
const remove = uid => {
  delete instances[uid];
};

const serializeError = error => {
  if (error instanceof Error) {
    return {
      message: error.message,
      name: error.name,
      ...(error.stack && {
        stack: error.stack
      })
    };
  }
  return {
    message: String(error),
    name: 'Error'
  };
};
const hasView = (extension, viewId) => {
  return Array.isArray(extension.views) && extension.views.some(view => view.id === viewId);
};
const getExtensionForView = async (viewId, assetDir, platform) => {
  const extensions = await getAllExtensions(assetDir, platform);
  const extension = extensions.find(extension => isExtensionIsolated(extension) && hasView(extension, viewId));
  if (!extension) {
    throw new Error(`view ${viewId} not found`);
  }
  return extension;
};
const getRpcForView = async (viewId, assetDir, platform) => {
  const {
    assetDir: resolvedAssetDir,
    platform: resolvedPlatform
  } = await getRuntimeContext(assetDir, platform);
  const extension = await getExtensionForView(viewId, resolvedAssetDir, resolvedPlatform);
  const existingRpc = get$3(getExtensionId$1(extension));
  if (existingRpc) {
    return existingRpc;
  }
  const activationResult = await activateByEvent(`onView:${viewId}`, resolvedAssetDir, resolvedPlatform);
  if (activationResult.error) {
    throw activationResult.error;
  }
  return getRpc$1(extension, resolvedAssetDir, resolvedPlatform);
};
const getRpcForInstance = async (viewId, uid, assetDir, platform) => {
  const instance = get$1(uid);
  if (instance) {
    if (instance.status === 'error') {
      return undefined;
    }
    return instance.rpc;
  }
  return getRpcForView(viewId, assetDir, platform);
};
const createViewInstance = async (viewId, uid, context, assetDir, platform) => {
  try {
    const rpc = await getRpcForView(viewId, assetDir, platform);
    const result = await rpc.invoke('ExtensionApi.createViewInstance', viewId, uid, context);
    set$1(uid, {
      rpc,
      status: 'ready',
      viewId
    });
    return {
      ok: true,
      result
    };
  } catch (error) {
    const serializedError = serializeError(error);
    set$1(uid, {
      error: serializedError,
      status: 'error',
      viewId
    });
    return {
      error: serializedError,
      ok: false
    };
  }
};
const dispatchViewEvent = async (viewId, uid, event, assetDir, platform) => {
  const rpc = await getRpcForInstance(viewId, uid, assetDir, platform);
  if (!rpc) {
    return undefined;
  }
  return rpc.invoke('ExtensionApi.dispatchViewEvent', uid, event);
};
const getViewMenuEntries = async (viewId, uid, menuId, assetDir, platform) => {
  const instance = get$1(uid);
  if (!instance || instance.status === 'error') {
    return [];
  }
  return instance.rpc.invoke('ExtensionApi.getViewMenuEntries', uid, menuId);
};
const getViewActions = async (viewId, uid, assetDir, platform) => {
  const instance = get$1(uid);
  if (!instance || instance.status === 'error') {
    return [];
  }
  return instance.rpc.invoke('ExtensionApi.getViewActions', uid);
};
const requestViewRerender = async uid => {
  await invoke$3('Viewlet.executeViewletCommand', uid, 'rerender');
};
const showViewContextMenu = async (uid, viewId, menuId, x, y) => {
  await invoke$3('ExtensionManagement.showViewContextMenu', uid, viewId, menuId, x, y);
};
const renderViewInstance = async (viewId, uid, assetDir, platform) => {
  const instance = get$1(uid);
  if (!instance || instance.status === 'error') {
    return undefined;
  }
  return instance.rpc.invoke('ExtensionApi.renderViewInstance', uid);
};
const disposeViewInstance = async (viewId, uid, assetDir, platform) => {
  const rpc = await getRpcForInstance(viewId, uid, assetDir, platform);
  if (!rpc) {
    remove(uid);
    return;
  }
  await rpc.invoke('ExtensionApi.disposeViewInstance', uid);
  remove(uid);
};
const saveViewInstanceState = async (viewId, uid, assetDir, platform) => {
  const rpc = await getRpcForInstance(viewId, uid, assetDir, platform);
  if (!rpc) {
    return undefined;
  }
  return rpc.invoke('ExtensionApi.saveViewInstanceState', uid);
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
const warn = (...args) => {
  console.warn(...args);
};

const transparent = (color, factor) => {
  return color;
};
const toColorRule = ([key, value]) => {
  return `  --${key}: ${value};`;
};
const toTokenColorRule = tokenColor => {
  return `.${tokenColor.name} { color: ${tokenColor.foreground} }`;
};
const addFallbackColors = colors => {
  const newColors = {
    ...colors
  };
  if (!newColors.ActivityBarInactiveForeground) {
    // TODO don't assign, avoid mutation
    newColors.ActivityBarInactiveForeground = transparent(newColors.ActivityBarForeground);
  }
  newColors.CssVariableName ||= colors.VariableName;
  return newColors;
};
const createColorThemeFromJson = (colorThemeId, colorThemeJson) => {
  if (!colorThemeJson) {
    warn(`color theme json for "${colorThemeId}" is empty: "${colorThemeJson}"`);
    return '';
  }
  if (typeof colorThemeJson !== 'object') {
    warn(`color theme json for "${colorThemeId}" cannot be converted to css: "${colorThemeJson}"`);
    return '';
  }
  if (Array.isArray(colorThemeJson)) {
    warn(`color theme json for "${colorThemeId}" cannot be converted to css, it must be of type object but was of type array`);
    return '';
  }
  const {
    colors
  } = colorThemeJson;
  if (!colors) {
    return '';
  }
  const newColors = addFallbackColors(colors);
  const colorRules = Object.entries(newColors).map(toColorRule);
  const tokenColors = colorThemeJson.tokenColors || [];
  const tokenColorRules = tokenColors.map(toTokenColorRule);
  const extraRules = [];
  if (colors.ContrastBorder) {
    extraRules.push(`#ActivityBar, #SideBar {
  border-left: 1px solid var(--ContrastBorder);
}`, `#Panel {
  border-top: 1px solid var(--ContrastBorder);
}`, `#StatusBar {
  border-top: 1px solid var(--ContrastBorder);
}`, `.ActivityBarItemBadge {
  border: 1px solid var(--ContrastBorder);
}`, `#QuickPick {
  border: 1px solid var(--ContrastBorder);
}`);
  }
  const colorThemeCss = `:root {\n${colorRules.join(NewLine)}\n}\n\n${tokenColorRules.join(NewLine)}\n\n${extraRules.join(NewLine)}`;
  return colorThemeCss;
};

// for (let i = 0; i < 10000; i++) {
//   createColorThemeFromJson({
//     type: 'dark',
//     colors: {
//       ActivityBarBackground: 'rgb(40, 46, 47)',
//       ActivityBarForeground: '#878f8c',
//       ActivityBarActiveBackground: '#1f2727',

//       EditorBackGround: '#1e2324',
//       EditorScrollBarBackground: 'rgba(57, 71, 71, 0.6)',
//       EditorCursorBackground: '#a8df5a',

//       ListActiveSelectionBackground: '#515f59',
//       ListActiveSelectionForeground: '#ffffff',
//       ListHoverBackground: '#405c5033',
//       ListHoverForeground: '#e0e0e0',
//       ListInactiveSelectionBackground: '#3b474280',

//       MainBackground: '#1e2324',

//       PanelBackground: '#1b2020',
//       PanelBorderTopColor: 'rgba(128, 128, 128, 0.35)',

//       SideBarBackground: '#1b2020',

//       StatusBarBackground: 'rgb(40, 46, 47)',
//       StatusBarBorderTopColor: '#222222',

//       TabActiveBackground: '#24292a',
//       TabInactiveBackground: '#282e2f',

//       TitleBarBackground: 'rgb(40, 46, 47)',
//       TitleBarBorderBottomColor: '#222',
//       TitleBarColor: '#cccccc',
//       TitleBarColorInactive: 'rgba(204, 204, 204, 0.6)',
//     },
//   }) //?.
// }

const get = colorThemeId => {
  return '';
};
const set = (colorThemeId, data) => {
  //  noop
};
const cache = {
  get,
  set
};

// TODO make storage configurable via settings as localstorage or indexeddb
// also allow disabling caching via settings
// then measure which option could be fastest

const getCacheFn = config => {
  switch (config) {
    default:
      return cache;
  }
};
const getColorThemeCssCached = async (colorThemeId, platform, getData) => {
  const config = '';
  const module = getCacheFn(config);
  const cachedData = module.get(colorThemeId);
  if (cachedData) {
    return cachedData;
  }
  const newData = await getData(colorThemeId, platform);
  module.set(colorThemeId, newData);
  return newData;
};

const readJson = url => {
  return invoke$3('FileSystem.readJson', url);
};

const join = (pathSeparator, ...parts) => {
  return parts.join(pathSeparator);
};

const getColorThemeUriFromExtension = (extension, colorThemeId) => {
  if (!extension.colorThemes) {
    return '';
  }
  for (const colorTheme of extension.colorThemes) {
    if (colorTheme.id === colorThemeId) {
      return join('/', extension.uri, colorTheme.path);
    }
  }
  return '';
};
const getColorThemeUri = (extensions, colorThemeId) => {
  for (const extension of extensions) {
    const absolutePath = getColorThemeUriFromExtension(extension, colorThemeId);
    if (absolutePath) {
      return absolutePath;
    }
  }
  return '';
};

const getColorThemeJson$2 = async (colorThemeId, assetDir, platform) => {
  const extensions = await getAllExtensions(assetDir, platform);
  const colorThemeUri = getColorThemeUri(extensions, colorThemeId);
  if (!colorThemeUri) {
    return {};
  }
  const json = await readJson(colorThemeUri);
  return json;
};

const getColorThemeUrlWeb = (assetDir, colorThemeId) => {
  return `${assetDir}/extensions/builtin.theme-${colorThemeId}/color-theme.json`;
};
const getColorThemeJson$1 = (colorThemeId, assetDir) => {
  const url = getColorThemeUrlWeb(assetDir, colorThemeId);
  // TODO handle error ?
  return getJson$1(url);
};

const getColorThemeJson = (colorThemeId, platform, assetDir) => {
  if (platform === Web) {
    return getColorThemeJson$1(colorThemeId, assetDir);
  }
  return getColorThemeJson$2(colorThemeId, assetDir, platform);
};

const getColorThemeCssFromJson = async (colorThemeId, colorThemeJson) => {
  const colorThemeCss = createColorThemeFromJson(/* colorThemeId */colorThemeId, /* colorThemeJson */colorThemeJson);
  return colorThemeCss;
  // TODO generate color theme from jsonc
};
const getColorThemeCssNew = async (colorThemeId, platform, assetDir) => {
  const colorThemeJson = await getColorThemeJson(colorThemeId, platform, assetDir);
  const colorThemeCss = await getColorThemeCssFromJson(colorThemeId, colorThemeJson);
  return colorThemeCss;
};
const getColorThemeCss = (colorThemeId, platform) => {
  return getColorThemeCssCached(colorThemeId, platform, getColorThemeCssNew);
};

const getExtensionColorThemeNames = extension => {
  return extension.colorThemes || [];
};
const getColorThemeId = colorTheme => {
  return colorTheme.id;
};

// TODO should send names to renderer worker or names with ids?
const getColorThemeNamesFromExtensions = async extensions => {
  const colorThemes = extensions.flatMap(getExtensionColorThemeNames);
  const colorThemeNames = colorThemes.map(getColorThemeId);
  return colorThemeNames;
};

const getColorThemeNames = async (assetDir, platform) => {
  string(assetDir);
  number(platform);
  const extensions = await getAllExtensions(assetDir, platform);
  const colorThemeNames = getColorThemeNamesFromExtensions(extensions);
  return colorThemeNames;
};

const getDynamicWebExtensions = () => {
  return get$4().webExtensions;
};

const getExtension = async (id, assetDir, platform) => {
  const allExtensions = await getAllExtensions(assetDir, platform);
  for (const extension of allExtensions) {
    if (extension.id === id) {
      return extension;
    }
  }
  return undefined;
};

const getExtensionId = extension => {
  return extension.id || interExtensionId(extension.uri || extension.path || '');
};
const toKeyBinding = (extension, keybinding) => {
  if (typeof keybinding.key !== 'string' || typeof keybinding.command !== 'string') {
    return undefined;
  }
  if (keybinding.when !== undefined && typeof keybinding.when !== 'string') {
    return undefined;
  }
  if (keybinding.args !== undefined && !Array.isArray(keybinding.args)) {
    return undefined;
  }
  return {
    ...(keybinding.args && {
      args: keybinding.args
    }),
    command: keybinding.command,
    extensionId: getExtensionId(extension),
    key: keybinding.key,
    ...(keybinding.when && {
      when: keybinding.when
    })
  };
};
const getKeyBindings = async (assetDir, platform) => {
  const extensions = await getAllExtensions(assetDir, platform);
  const keybindings = [];
  for (const extension of extensions) {
    if (!Array.isArray(extension.keybindings)) {
      continue;
    }
    for (const keybinding of extension.keybindings) {
      const normalized = toKeyBinding(extension, keybinding);
      if (normalized) {
        keybindings.push(normalized);
      }
    }
  }
  return keybindings;
};

const getPortTuple = () => {
  const {
    port1,
    port2
  } = new MessageChannel();
  return {
    port1,
    port2
  };
};

const createWebViewIpc = async webView => {
  const {
    origin,
    uid
  } = webView;
  const {
    port1,
    port2
  } = getPortTuple();
  const rpcPromise = create$3({
    commandMap: {},
    isMessagePortOpen: false,
    messagePort: port2
  });
  const portType = 'test';
  await invokeAndTransfer('WebView.setPort', uid, port1, origin, portType);
  // TODO maybe don't send a message port only to get object url?
  // TODO dispose rpc to avoid memory leak
  const rpc = await rpcPromise;
  return rpc;
};

const webViews = Object.create(null);
const getWebView = id => {
  return webViews[id];
};

// TODO if webViewId is provided,
// 1. read file as blob
// 2. send blob to webview
// 3. create object URL in webview
// 4. send back object URL to extension host worker
// 5. provide objectUrl to extension

const getRemoteUrlForWebView = async (uri, options = {}) => {
  // TODO webviews should be stored in iframe worker
  const webView = getWebView(options.webViewId);
  if (!webView) {
    throw new Error(`webview ${options.webViewId} not found`);
  }
  const [rpc, blob] = await Promise.all([createWebViewIpc(webView), invoke$1('FileSystem.getBlob', uri)]);
  const objectUrl = await rpc.invoke('createObjectUrl', blob);
  return objectUrl;
};

const getRpcInfo = rpcId => {
  const info = get$2(rpcId);
  if (!info) {
    throw new Error(`Rpc not found ${rpcId}`);
  }
  return info;
};

const getRunningExtensionsFromState = (extensions, runtimeStatuses) => {
  return extensions.flatMap(extension => {
    const runtimeStatus = runtimeStatuses[extension.id];
    if (!runtimeStatus || runtimeStatus.status !== Activated) {
      return [];
    }
    return [{
      ...extension,
      activationEvent: runtimeStatus.activationEvent,
      activationTime: runtimeStatus.activationTime
    }];
  }).toSorted((a, b) => b.activationTime - a.activationTime);
};

const getRunningExtensions = async (assetDir, platform) => {
  const extensions = await getAllExtensions(assetDir, platform);
  const {
    runtimeStatuses
  } = get$4();
  return getRunningExtensionsFromState(extensions, runtimeStatuses);
};

const emptyStatus = {
  activationEndTime: 0,
  activationEvent: '',
  activationStartTime: 0,
  activationTime: 0,
  id: '',
  importEndTime: 0,
  importStartTime: 0,
  importTime: 0,
  status: None
};
const getRuntimeStatus = extensionId => {
  return getRuntimeStatus$1(extensionId) || emptyStatus;
};

const getItems = async rpc => {
  return rpc.invoke('ExtensionApi.getStatusBarItems');
};
const getStatusBarItems = async () => {
  const rpcs = getAll();
  const results = await Promise.all(rpcs.map(getItems));
  return results.flat();
};

const contributesViews = extension => {
  return Array.isArray(extension.views) && extension.views.length > 0;
};
const getManifestView = (extension, id) => {
  return extension.views?.find(view => view.id === id);
};
const getCss = (extension, manifestView, assetDir, platform) => {
  const css = manifestView?.css;
  if (typeof css !== 'string' || css.length === 0) {
    return '';
  }
  return getAbsolutePath({
    ...extension,
    browser: css
  }, assetDir, platform);
};
const isAbsoluteIcon = icon => {
  return icon.startsWith('http://') || icon.startsWith('https://') || icon.startsWith('file://') || icon.startsWith('/');
};
const isRelativeIconPath = icon => {
  return icon.startsWith('./') || icon.startsWith('../') || icon.includes('/') || /\.(?:bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(icon);
};
const getIcon = (extension, manifestView, registeredView, assetDir, platform) => {
  const manifestIcon = manifestView?.icon;
  if (typeof manifestIcon === 'string' && manifestIcon.length > 0) {
    if (isAbsoluteIcon(manifestIcon) || !isRelativeIconPath(manifestIcon)) {
      return manifestIcon;
    }
    return getAbsolutePath({
      ...extension,
      browser: manifestIcon
    }, assetDir, platform);
  }
  return registeredView.icon || '';
};
const getIframe = (extension, manifestView, assetDir, platform) => {
  const iframe = manifestView?.iframe;
  if (!iframe || typeof iframe.path !== 'string' || iframe.path.length === 0) {
    return undefined;
  }
  return {
    credentialless: iframe.credentialless !== false,
    csp: iframe.csp || '',
    sandbox: Array.isArray(iframe.sandbox) ? iframe.sandbox.filter(item => typeof item === 'string') : ['allow-scripts'],
    src: getAbsolutePath({
      ...extension,
      browser: iframe.path
    }, assetDir, platform)
  };
};
const toView = (extension, registeredView, assetDir, platform) => {
  const id = registeredView.id || '';
  const manifestView = getManifestView(extension, id);
  const css = getCss(extension, manifestView, assetDir, platform);
  return {
    ...(css && {
      css
    }),
    ...(registeredView.eventListeners && {
      eventListeners: registeredView.eventListeners
    }),
    extensionId: getExtensionId$1(extension),
    icon: getIcon(extension, manifestView, registeredView, assetDir, platform),
    id,
    iframe: getIframe(extension, manifestView, assetDir, platform),
    kind: registeredView.kind || manifestView?.kind || '',
    title: registeredView.title || manifestView?.title || id
  };
};
const getRpcViewRegistrySnapshot = async rpc => {
  return rpc.invoke('ExtensionApi.getViewRegistrySnapshot');
};
const getExtensionViews = async (extension, assetDir, platform) => {
  const rpc = await getRpc$1(extension, assetDir, platform);
  const snapshot = await getRpcViewRegistrySnapshot(rpc);
  if (!Array.isArray(snapshot.views)) {
    return [];
  }
  return snapshot.views.filter(view => view && typeof view.id === 'string').map(view => toView(extension, view, assetDir, platform));
};
const getViewsFromExtensionWorkers = async (extensions, assetDir, platform) => {
  const matchingExtensions = extensions.filter(extension => isExtensionIsolated(extension) && contributesViews(extension));
  const results = await Promise.all(matchingExtensions.map(extension => getExtensionViews(extension, assetDir, platform)));
  return results.flat();
};
const getViews = async (assetDir, platform) => {
  const {
    assetDir: resolvedAssetDir,
    platform: resolvedPlatform
  } = await getRuntimeContext(assetDir, platform);
  const extensions = await getAllExtensions(resolvedAssetDir, resolvedPlatform);
  return getViewsFromExtensionWorkers(extensions, resolvedAssetDir, resolvedPlatform);
};

const handleData = () => {};

const StatusBarWorker = 200;

const handleMessagePort = async (port, rpcId) => {
  const rpc = await create$8({
    commandMap: commandMapRef,
    messagePort: port
  });
  if (rpcId === StatusBarWorker) {
    set$2(rpc);
  }
};

const handleViewContextChange = async (uid, viewId, context) => {
  await invoke$3('ExtensionManagement.handleViewContextChange', uid, viewId, context);
};

const getRpcRemote = async () => {
  const rpc = await create$4({
    commandMap: commandMapRef,
    type: 'shared-process'
  });
  return rpc;
};
const getRpcElectron = async () => {
  const rpc = create$7({
    commandMap: commandMapRef,
    async send(port) {
      await sendMessagePortToSharedProcess(port);
    }
  });
  return rpc;
};
const getRpc = async platform => {
  // TODO create connection to shared process
  if (platform === Remote) {
    return getRpcRemote();
  }
  if (platform === Electron) {
    return getRpcElectron();
  }
  return undefined;
};
const initializeSharedProcess = async platform => {
  const rpc = await getRpc(platform);
  if (rpc) {
    set$5(rpc);
  }
};

const initialize = async platform => {
  setPlatform(platform);
  await initializeSharedProcess(platform);
};

const installExtension = async () => {
  // TODO
  await invalidateExtensionsCache();
};

const getRemoteUrl = uri => {
  if (uri.startsWith('http://') || uri.startsWith('https://')) {
    return uri;
  }
  if (uri.startsWith('/')) {
    return `/remote${uri}`;
  }
  return `/remote/${uri}`;
};

const getLanguagesFromExtension = (extension, platform) => {
  // TODO what if extension is null? should not crash process, handle error gracefully
  // TODO what if extension languages is not of type array?
  // TODO what if language is null?
  if (!extension) {
    return [];
  }
  if (!extension.languages) {
    return [];
  }
  const extensionPath = extension.path;
  const getLanguageFromExtension = language => {
    if (language.tokenize) {
      if (typeof language.tokenize !== 'string') {
        console.warn(`[info] ${language.id}: language.tokenize must be of type string but was of type ${typeof language.tokenize}`);
        return {
          ...language,
          extensionPath,
          tokenize: ''
        };
      }
      const relativePath = `${extensionPath}/${language.tokenize}`;
      const absolutePath = platform === Web ? relativePath : getRemoteUrl(relativePath);
      return {
        ...language,
        extensionPath,
        tokenize: absolutePath
      };
    }
    return language;
  };
  return extension.languages.map(getLanguageFromExtension);
};

const getLanguages = async (platform, assetDir) => {
  try {
    number(platform);
    string(assetDir);
    const extensions = await getAllExtensions(assetDir, platform);
    const languages = extensions.flatMap(extension => getLanguagesFromExtension(extension, platform));
    return languages;
  } catch (error) {
    throw new VError(error, 'Failed to load languages');
  }
};

const getPreference = async key => {
  return invoke$3('Preferences.get', key);
};
const setPreference = async (key, value) => {
  await invoke$3('Preferences.update', {
    [key]: value
  });
};

const sendMessagePortToElectron = async (port, initialCommand) => {
  await invokeAndTransfer$1('SendMessagePortToElectron.sendMessagePortToElectron', port, initialCommand);
};

const sendMessagePortToFileSystemWorker = async port => {
  await sendMessagePortToFileSystemWorker$1(port, 0);
};

const uninstallExtension = async () => {
  // TODO
  await invalidateExtensionsCache();
};

/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */

const wrapCommand = command => {
  return (...args) => {
    return command(get$4(), ...args);
  };
};
const commandMap = {
  'ExtensionApi.readFile': readFile,
  'Extensions.activate2': activateExtension2,
  'Extensions.activate3': activateExtension3,
  'Extensions.activateByEvent': activateByEvent,
  'Extensions.addWebExtension': addWebExtension,
  'Extensions.createViewInstance': createViewInstance,
  'Extensions.createWebViewWorkerRpc': createWebViewWorkerRpc,
  'Extensions.createWebViewWorkerRpc2': createWebViewWorkerRpc2,
  'Extensions.disable': disableExtension,
  'Extensions.disable2': disableExtension2,
  'Extensions.disableWorkspace': disableWorkspaceExtension,
  'Extensions.dispatchViewEvent': dispatchViewEvent,
  'Extensions.disposeViewInstance': disposeViewInstance,
  'Extensions.enable': enableExtension,
  'Extensions.enable2': enableExtension2,
  'Extensions.enableWorkspace': enableWorkspaceExtension,
  'Extensions.executeCommand': wrapCommand(executeCommand),
  'Extensions.executeCompletionProvider': wrapCommand(executeCompletionProvider),
  'Extensions.executeDiagnosticProvider': wrapCommand(executeDiagnosticProvider),
  'Extensions.executeExtensionCommand': wrapCommand(executeExtensionCommand),
  'Extensions.executeFormattingProvider': wrapCommand(executeFormattingProvider),
  'Extensions.executeHoverProvider': wrapCommand(executeHoverProvider),
  'Extensions.executeLanguageProvider': wrapCommand(executeLanguageProvider),
  'Extensions.executeOrganizeImportsProvider': wrapCommand(executeOrganizeImportsProvider),
  'Extensions.executeResolveCompletionItemProvider': wrapCommand(executeResolveCompletionItemProvider),
  'Extensions.getAllExtensions': getAllExtensions,
  'Extensions.getColorThemeCss': getColorThemeCss,
  'Extensions.getColorThemeCssFromJson': getColorThemeCssFromJson,
  'Extensions.getColorThemeJson': getColorThemeJson,
  'Extensions.getColorThemeNames': getColorThemeNames,
  'Extensions.getDynamicWebExtensions': getDynamicWebExtensions,
  'Extensions.getExtension': getExtension,
  'Extensions.getKeyBindings': getKeyBindings,
  'Extensions.getLanguages': getLanguages,
  'Extensions.getPreference': getPreference,
  'Extensions.getRemoteUrlForWebView': getRemoteUrlForWebView,
  'Extensions.getRpcInfo': getRpcInfo,
  'Extensions.getRunningExtensions': getRunningExtensions,
  'Extensions.getRuntimeStatus': getRuntimeStatus,
  'Extensions.getStatusBarItems': getStatusBarItems,
  'Extensions.getViewActions': getViewActions,
  'Extensions.getViewMenuEntries': getViewMenuEntries,
  'Extensions.getViews': getViews,
  'Extensions.handleData': handleData,
  'Extensions.handleMessagePort': handleMessagePort,
  'Extensions.handleViewContextChange': handleViewContextChange,
  'Extensions.importExtension': importExtension,
  'Extensions.initialize': initialize,
  'Extensions.install': installExtension,
  'Extensions.invalidateExtensionsCache': invalidateExtensionsCache,
  'Extensions.renderViewInstance': renderViewInstance,
  'Extensions.requestViewRerender': requestViewRerender,
  'Extensions.saveViewInstanceState': saveViewInstanceState,
  'Extensions.sendMessagePortToElectron': sendMessagePortToElectron,
  'Extensions.sendMessagePortToFileSystemWorker': sendMessagePortToFileSystemWorker,
  'Extensions.setPreference': setPreference,
  'Extensions.showViewContextMenu': showViewContextMenu,
  'Extensions.uninstall': uninstallExtension,
  'StatusBar.handleChange': handleChange
};

const initializeExtensionHostWorker = async () => {
  const rpc = await create$6({
    commandMap: commandMapRef,
    async send(port) {
      await sendMessagePortToExtensionHostWorker(port, 0);
    }
  });
  set$8(rpc);
};

const initializeFileSystemWorker = async () => {
  const rpc = await create$6({
    commandMap: commandMapRef,
    async send(port) {
      await sendMessagePortToFileSystemWorker$1(port, 0);
    }
  });
  set$7(rpc);
};

const initializeIframeWorker = async () => {
  const rpc = await create$6({
    commandMap: {},
    async send(port) {
      await sendMessagePortToIconThemeWorker(port, 0);
    }
  });
  return rpc;
};

const initializeRendererWorker = async () => {
  const rpc = await create$2({
    commandMap: commandMap
  });
  set$6(rpc);
};

const listen = async () => {
  Object.assign(commandMapRef, commandMap);
  await Promise.all([initializeRendererWorker(), initializeFileSystemWorker(), initializeIframeWorker(), initializeExtensionHostWorker()]);
};

const main = async () => {
  await listen();
};

main();
