const toCommandId = key => {
  const dotIndex = key.indexOf('.');
  return key.slice(dotIndex + 1);
};
const create$a = () => {
  const commandQueues = new Map();
  const generations = Object.create(null);
  const states = Object.create(null);
  const commandMapRef = {};
  const getGeneration = uid => generations[uid] || 0;
  const isCurrentGeneration = (uid, generation) => {
    return states[uid] !== undefined && getGeneration(uid) === generation;
  };
  const updateState = (uid, generation, fallbackState, updater) => {
    if (!isCurrentGeneration(uid, generation)) {
      return Promise.resolve(fallbackState);
    }
    const current = states[uid];
    const updatedState = updater(current.newState);
    if (updatedState !== current.newState) {
      states[uid] = {
        newState: updatedState,
        oldState: current.oldState,
        scheduledState: updatedState
      };
    }
    return Promise.resolve(updatedState);
  };
  const createAsyncCommandContext = (uid, generation) => {
    let latestState = states[uid].newState;
    return {
      getState: () => {
        if (isCurrentGeneration(uid, generation)) {
          latestState = states[uid].newState;
        }
        return latestState;
      },
      updateState: async updater => {
        latestState = await updateState(uid, generation, latestState, updater);
        return latestState;
      }
    };
  };
  const enqueueCommand = async (uid, command) => {
    const previous = commandQueues.get(uid) || Promise.resolve();
    const run = async () => {
      try {
        await previous;
      } catch {
        // The previous caller receives its error; later commands must still run.
      }
      await command();
    };
    const current = run();
    commandQueues.set(uid, current);
    try {
      await current;
    } finally {
      if (commandQueues.get(uid) === current) {
        commandQueues.delete(uid);
      }
    }
  };
  return {
    clear() {
      commandQueues.clear();
      for (const key of Object.keys(states)) {
        delete states[key];
      }
    },
    diff(uid, modules, numbers) {
      const {
        oldState,
        scheduledState
      } = states[uid];
      const diffResult = [];
      for (let i = 0; i < modules.length; i++) {
        const fn = modules[i];
        if (!fn(oldState, scheduledState)) {
          diffResult.push(numbers[i]);
        }
      }
      return diffResult;
    },
    dispose(uid) {
      commandQueues.delete(uid);
      delete states[uid];
    },
    get(uid) {
      return states[uid];
    },
    getCommandIds() {
      const keys = Object.keys(commandMapRef);
      const ids = keys.map(toCommandId);
      return ids;
    },
    getKeys() {
      return Object.keys(states).map(Number);
    },
    registerCommands(commandMap) {
      Object.assign(commandMapRef, commandMap);
    },
    set(uid, oldState, newState, scheduledState) {
      const current = states[uid];
      if (!current || oldState === newState && newState !== current.newState) {
        generations[uid] = getGeneration(uid) + 1;
      }
      states[uid] = {
        newState,
        oldState,
        scheduledState: scheduledState ?? newState
      };
    },
    wrapAsyncCommand(fn) {
      const wrapped = async (uid, ...args) => {
        const generation = getGeneration(uid);
        const context = createAsyncCommandContext(uid, generation);
        await fn(context, ...args);
      };
      return wrapped;
    },
    wrapCommand(fn) {
      const wrapped = async (uid, ...args) => {
        const generation = getGeneration(uid);
        const {
          newState,
          oldState
        } = states[uid];
        const newerState = await fn(newState, ...args);
        if (oldState === newerState || newState === newerState) {
          return;
        }
        if (!isCurrentGeneration(uid, generation)) {
          return;
        }
        const latestOld = states[uid];
        const latestNew = {
          ...latestOld.newState,
          ...newerState
        };
        states[uid] = {
          newState: latestNew,
          oldState: latestOld.oldState,
          scheduledState: latestNew
        };
      };
      return wrapped;
    },
    wrapGetter(fn) {
      const wrapped = (uid, ...args) => {
        const {
          newState
        } = states[uid];
        return fn(newState, ...args);
      };
      return wrapped;
    },
    wrapLoadContent(fn) {
      const wrapped = async (uid, ...args) => {
        const generation = getGeneration(uid);
        const {
          newState,
          oldState
        } = states[uid];
        const result = await fn(newState, ...args);
        const {
          error,
          state
        } = result;
        if (oldState === state || newState === state) {
          return {
            error
          };
        }
        if (!isCurrentGeneration(uid, generation)) {
          return {
            error
          };
        }
        const latestOld = states[uid];
        const latestNew = {
          ...latestOld.newState,
          ...state
        };
        states[uid] = {
          newState: latestNew,
          oldState: latestOld.oldState,
          scheduledState: latestNew
        };
        return {
          error
        };
      };
      return wrapped;
    },
    wrapSerialAsyncCommand(fn) {
      const wrapped = async (uid, ...args) => {
        await enqueueCommand(uid, async () => {
          if (!states[uid]) {
            return;
          }
          const generation = getGeneration(uid);
          const context = createAsyncCommandContext(uid, generation);
          await fn(context, ...args);
        });
      };
      return wrapped;
    },
    wrapSerialCommand(fn) {
      const wrapped = async (uid, ...args) => {
        await enqueueCommand(uid, async () => {
          if (!states[uid]) {
            return;
          }
          const generation = getGeneration(uid);
          const {
            newState,
            oldState
          } = states[uid];
          const newerState = await fn(newState, ...args);
          if (oldState === newerState || newState === newerState) {
            return;
          }
          if (!isCurrentGeneration(uid, generation)) {
            return;
          }
          const latestOld = states[uid];
          const latestNew = {
            ...latestOld.newState,
            ...newerState
          };
          states[uid] = {
            newState: latestNew,
            oldState: latestOld.oldState,
            scheduledState: latestNew
          };
        });
      };
      return wrapped;
    }
  };
};
const terminate = () => {
  globalThis.close();
};

const {
  diff,
  get: get$2,
  getCommandIds,
  registerCommands,
  set: set$3,
  wrapCommand,
  wrapGetter
} = create$a();

// TODO parentUid might ot be needed
const create$9 = (id, uri, x, y, width, height, args, parentUid, platform = 0) => {
  const state = {
    accountEnabled: true,
    activityBarItems: [],
    currentViewletId: '',
    filteredItems: [],
    focus: 0,
    focused: false,
    focusedIndex: -1,
    height,
    initial: true,
    itemHeight: 48,
    numberOfVisibleItems: 0,
    platform,
    scrollBarHeight: 0,
    selectedIndex: -1,
    sideBarLocation: 0,
    sideBarVisible: false,
    uid: id,
    updateProgress: 0,
    updateState: '',
    userLoginProvider: 'GitHub',
    userLoginState: 'logged out',
    userName: '',
    width,
    x,
    y
  };
  set$3(id, state, state);
  return state;
};

const getCustomIconSignature = items => {
  return items.map(item => {
    if (!item.customIconClass || !item.customIconUrl) {
      return '';
    }
    return `${item.customIconClass}\n${item.customIconUrl}`;
  }).filter(Boolean).join('\n');
};

const isEqual$2 = (oldState, newState) => {
  return oldState.itemHeight === newState.itemHeight && getCustomIconSignature(oldState.filteredItems) === getCustomIconSignature(newState.filteredItems);
};

const isEqual$1 = (oldState, newState) => {
  return oldState.focused === newState.focused && oldState.focus === newState.focus;
};

const isEqual = (oldState, newState) => {
  return oldState.activityBarItems === newState.activityBarItems && oldState.filteredItems === newState.filteredItems && oldState.focusedIndex === newState.focusedIndex && oldState.sideBarLocation === newState.sideBarLocation && oldState.sideBarVisible === newState.sideBarVisible && oldState.updateProgress === newState.updateProgress && oldState.updateState === newState.updateState;
};

const RenderItems = 4;
const RenderFocus = 6;
const RenderFocusContext = 7;
const RenderCss = 11;
const RenderIncremental = 12;

const modules = [isEqual, isEqual$1, isEqual$1, isEqual$2];
const numbers = [RenderIncremental, RenderFocus, RenderFocusContext, RenderCss];

const diff2 = uid => {
  return diff(uid, modules, numbers);
};

const List = 1;

const focus = state => {
  const {
    focus
  } = state;
  if (focus) {
    return state;
  }
  return {
    ...state,
    focus: List
  };
};

const focusIndex = (state, index) => {
  return {
    ...state,
    focused: true,
    focusedIndex: index
  };
};

const focusFirst = state => {
  return focusIndex(state, -1);
};

const focusLast = state => {
  return focusIndex(state, -1);
};

const focusNext = state => {
  return focusIndex(state, -1);
};

const focusNone = state => {
  const {
    focusedIndex
  } = state;
  if (focusedIndex === -1) {
    return state;
  }
  return focusIndex(state, -1);
};

const Button$3 = 'button';
const None$1 = 'none';
const Tab$1 = 'tab';
const ToolBar = 'toolbar';

const Audio = 0;
const Button$2 = 1;
const Col = 2;
const ColGroup = 3;
const Div = 4;
const H1 = 5;
const Input = 6;
const Kbd = 7;
const Span = 8;
const Table = 9;
const TBody = 10;
const Td = 11;
const Text = 12;
const Th = 13;
const THead = 14;
const Tr = 15;
const I = 16;
const Img = 17;
const Root = 0;
const Ins = 20;
const Del = 21;
const H2 = 22;
const H3 = 23;
const H4 = 24;
const H5 = 25;
const H6 = 26;
const Article = 27;
const Aside = 28;
const Footer = 29;
const Header = 30;
const Nav = 40;
const Section = 41;
const Search$3 = 42;
const Dd = 43;
const Dl = 44;
const Figcaption = 45;
const Figure = 46;
const Hr = 47;
const Li = 48;
const Ol = 49;
const P = 50;
const Pre = 51;
const A = 53;
const Abbr = 54;
const Br = 55;
const Cite = 56;
const Data = 57;
const Time = 58;
const Tfoot = 59;
const Ul = 60;
const Video = 61;
const TextArea = 62;
const Select = 63;
const Option = 64;
const Code = 65;
const Label = 66;
const Dt = 67;
const Iframe = 68;
const Main = 69;
const Strong = 70;
const Em = 71;
const Style = 72;
const Html = 73;
const Head = 74;
const Title = 75;
const Meta = 76;
const Canvas = 77;
const Form = 78;
const BlockQuote = 79;
const Quote = 80;
const Circle = 81;
const Defs = 82;
const Ellipse = 83;
const G = 84;
const Line = 85;
const Path = 86;
const Polygon = 87;
const Polyline = 88;
const Rect = 89;
const Svg = 90;
const Use = 91;
const Reference = 100;

const VirtualDomElements = {
  __proto__: null,
  A,
  Abbr,
  Article,
  Aside,
  Audio,
  BlockQuote,
  Br,
  Button: Button$2,
  Canvas,
  Circle,
  Cite,
  Code,
  Col,
  ColGroup,
  Data,
  Dd,
  Defs,
  Del,
  Div,
  Dl,
  Dt,
  Ellipse,
  Em,
  Figcaption,
  Figure,
  Footer,
  Form,
  G,
  H1,
  H2,
  H3,
  H4,
  H5,
  H6,
  Head,
  Header,
  Hr,
  Html,
  I,
  Iframe,
  Img,
  Input,
  Ins,
  Kbd,
  Label,
  Li,
  Line,
  Main,
  Meta,
  Nav,
  Ol,
  Option,
  P,
  Path,
  Polygon,
  Polyline,
  Pre,
  Quote,
  Rect,
  Reference,
  Root,
  Search: Search$3,
  Section,
  Select,
  Span,
  Strong,
  Style,
  Svg,
  TBody,
  THead,
  Table,
  Td,
  Text,
  TextArea,
  Tfoot,
  Th,
  Time,
  Title,
  Tr,
  Ul,
  Use,
  Video
};

const Button$1 = 'event.button';
const ClientX = 'event.clientX';
const ClientY = 'event.clientY';
const TargetName = 'event.target.name';

const Enter = 3;
const Space = 9;
const PageUp = 10;
const PageDown = 11;
const End = 255;
const Home = 12;
const UpArrow = 14;
const DownArrow = 16;

const ActivityBar$3 = 1;
const Settings$1 = 12;
const ActivityBarAdditionalViews = 17;

const Separator = 1;
const None = 0;
const SubMenu = 4;
const Checked = 2;
const Unchecked = 3;

const LeftClick = 0;

const Electron = 2;

const ExtensionManagementWorker = 9006;
const RendererWorker = 1;

const Left = 1;
const Right = 2;

const SetCss = 'Viewlet.setCss';
const SetDom2 = 'Viewlet.setDom2';
const SetFocusContext = 'Viewlet.setFocusContext';
const SetPatches = 'Viewlet.setPatches';

const FocusActivityBar = 5;
const FocusExplorer = 13;

const getKeyBindings = () => {
  return [{
    command: 'ActivityBar.focusNext',
    key: DownArrow,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.focusPrevious',
    key: UpArrow,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.focusFirst',
    key: Home,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.focusFirst',
    key: PageUp,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.focusLast',
    key: PageDown,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.focusLast',
    key: End,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.selectCurrent',
    key: Space,
    when: FocusActivityBar
  }, {
    command: 'ActivityBar.selectCurrent',
    key: Enter,
    when: FocusActivityBar
  }];
};

const ACCOUNT_SUBMENU_ID = 32_123;
const getAccountLabel = state => {
  const {
    userLoginProvider,
    userName
  } = state;
  const name = userName || 'Account';
  const provider = userLoginProvider || 'GitHub';
  return `${name} (${provider})`;
};
const getMenuEntriesAccountLoggedIn = state => {
  return [{
    args: [{
      menuId: ACCOUNT_SUBMENU_ID
    }],
    command: '',
    flags: SubMenu,
    id: ACCOUNT_SUBMENU_ID,
    label: getAccountLabel(state)
  }];
};
const getMenuEntriesAccountSubMenu = state => {
  const {
    userLoginState
  } = state;
  const signOutLabel = userLoginState === 'logging out' ? 'Signing Out...' : 'Sign Out';
  return [{
    command: 'ActivityBar.handleClickSignOut',
    flags: None,
    id: 'signOut',
    label: signOutLabel
  }];
};
const getMenuEntriesAccountLoggedOut = state => {
  const {
    userLoginState
  } = state;
  const signInLabel = userLoginState === 'logging in' ? 'Signing In...' : 'Sign In';
  return [{
    command: 'ActivityBar.handleClickSignIn',
    flags: None,
    id: 'signIn',
    label: signInLabel
  }];
};
const getMenuEntriesAccount = state => {
  // TODO maybe query it now from layout?
  const {
    userLoginState
  } = state;
  if (userLoginState === 'logged in' || userLoginState === 'logging out') {
    return getMenuEntriesAccountLoggedIn(state);
  }
  return getMenuEntriesAccountLoggedOut(state);
};

const Tab = 1;
const Button = 1 << 1;
const Progress = 1 << 2;
const Enabled = 1 << 3;
const Selected = 1 << 4;
const Focused = 1 << 5;
const MarginTop = 1 << 6;

const emptyObject = {};
const i18nString = (key, placeholders = emptyObject) => {
  if (placeholders === emptyObject) {
    return key;
  }
  let result = key;
  for (const [placeholder, replacement] of Object.entries(placeholders)) {
    result = result.split(`{${placeholder}}`).join(String(replacement));
  }
  return result;
};

const Account$1 = 'Account';
const Explorer$1 = 'Explorer';
const Search$2 = 'Search';
const SourceControl$2 = 'Source Control';
const RunAndDebug$1 = 'Run and Debug';
const Extensions$2 = 'Extensions';
const Settings = 'Settings';
const AdditionalViews = 'Additional Views';
const ActivityBar$2 = 'Activity Bar';
const MoveSideBarLeft = 'Move Side Bar Left';
const MoveSideBarRight = 'Move Side Bar Right';
const HideActivityBar = 'Hide Activity Bar';
const CheckForUpdates = 'Check For Updates';
const ColorTheme = 'Color Theme';
const CommandPalette = 'Command Palette';
const KeyboardShortcuts = 'Keyboard Shortcuts';

const account = () => {
  return i18nString(Account$1);
};
const explorer = () => {
  return i18nString(Explorer$1);
};
const search = () => {
  return i18nString(Search$2);
};
const sourceControl = () => {
  return i18nString(SourceControl$2);
};
const runAndDebug = () => {
  return i18nString(RunAndDebug$1);
};
const extensions = () => {
  return i18nString(Extensions$2);
};
const settings = () => {
  return i18nString(Settings);
};
const additionalViews = () => {
  return i18nString(AdditionalViews);
};
const activityBar = () => {
  return i18nString(ActivityBar$2);
};
const moveSideBarRight = () => {
  return i18nString(MoveSideBarRight);
};
const moveSideBarLeft = () => {
  return i18nString(MoveSideBarLeft);
};
const hideActivityBar = () => {
  return i18nString(HideActivityBar);
};
const checkForUpdates = () => {
  return i18nString(CheckForUpdates);
};
const commandPalette = () => {
  return i18nString(CommandPalette);
};
const keyboardShortcuts = () => {
  return i18nString(KeyboardShortcuts);
};
const colorTheme = () => {
  return i18nString(ColorTheme);
};

const menuEntryMoveSideBar = sideBarLocation => {
  switch (sideBarLocation) {
    case Left:
      return {
        command: 'Layout.moveSideBarRight',
        flags: None,
        id: 'moveSideBarRight',
        label: moveSideBarRight()
      };
    case Right:
      return {
        command: 'Layout.moveSideBarLeft',
        flags: None,
        id: 'moveSideBarLeft',
        label: moveSideBarLeft()
      };
    default:
      throw new Error('unexpected side bar location');
  }
};

const menuEntrySeparator = {
  command: '',
  flags: Separator,
  id: 'separator',
  label: ''
};

const toContextMenuItem$1 = activityBarItem => {
  const isEnabled = activityBarItem.flags & Enabled;
  return {
    args: [activityBarItem.id],
    command: 'ActivityBar.toggleActivityBarItem',
    flags: isEnabled ? Checked : Unchecked,
    id: `toggle-${activityBarItem.id}`,
    label: activityBarItem.id
  };
};

const getMenuEntriesActivityBar = state => {
  const {
    activityBarItems,
    sideBarLocation
  } = state;
  const topItems = activityBarItems.filter(item => !(item.flags & Button));
  const bottomItems = activityBarItems.filter(item => item.flags & Button);
  const entries = topItems.map(toContextMenuItem$1);
  if (bottomItems.length > 0) {
    entries.push(menuEntrySeparator, ...bottomItems.map(toContextMenuItem$1));
  }
  return [...entries, menuEntrySeparator, menuEntryMoveSideBar(sideBarLocation), {
    command: 'Layout.hideActivityBar',
    flags: None,
    id: 'hideActivityBar',
    label: hideActivityBar()
  }];
};

const getNumberOfVisibleItems = state => {
  const {
    height,
    itemHeight
  } = state;
  const numberOfVisibleItemsTop = Math.floor(height / itemHeight);
  return numberOfVisibleItemsTop;
};
const getHiddenItems = state => {
  const {
    activityBarItems
  } = state;
  const numberOfVisibleItems = getNumberOfVisibleItems(state);
  const items = activityBarItems.filter(item => item.flags & Enabled);
  if (numberOfVisibleItems >= items.length) {
    return [];
  }
  return items.slice(numberOfVisibleItems - 2, -1);
};

const toContextMenuItem = activityBarItem => {
  return {
    command: '-1',
    // TODO
    flags: None,
    id: '8000',
    // TODO
    label: activityBarItem.id
  };
};
const getMenuEntriesAdditionalViews = state => {
  const hiddenActivityBarItems = getHiddenItems(state);
  return hiddenActivityBarItems.map(toContextMenuItem);
};

const keyBindingsUri = 'app://keybindings';
const getMenuEntriesSettings = state => {
  const {
    platform
  } = state;
  const items = [{
    command: 'QuickPick.showEverything',
    flags: None,
    id: 'commandPalette',
    label: commandPalette()
  }, menuEntrySeparator, {
    command: 'Preferences.openSettingsJson',
    flags: None,
    id: 'settings',
    label: settings()
  }, {
    args: [keyBindingsUri],
    command: 'Main.openUri',
    flags: None,
    id: 'keyboardShortcuts',
    label: keyboardShortcuts()
  }, {
    command: 'QuickPick.showColorTheme',
    flags: None,
    id: 'colorTheme',
    label: colorTheme()
  }];
  if (platform === Electron) {
    items.push(menuEntrySeparator, {
      command: 'AutoUpdater.checkForUpdates',
      flags: None,
      id: 'checkForUpdates',
      label: checkForUpdates()
    });
  }
  return items;
};

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$2 = '\n';
const getNewLineIndex$1 = (string, startIndex = undefined) => {
  return string.indexOf(NewLine$2, 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;
    }
  }
}

class AssertionError extends Error {
  constructor(message) {
    super(message);
    this.name = 'AssertionError';
  }
}
const Object$1 = 1;
const Number$1 = 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$1;
    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 number = value => {
  const type = getType(value);
  if (type !== Number$1) {
    throw new AssertionError('expected value to be of type number');
  }
};

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);
    }
  }
};
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$1 = '\n';
const joinLines$1 = lines => {
  return lines.join(NewLine$1);
};
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$1);
};
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;
      if (stack) {
        Object.defineProperty(cause, 'stack', {
          configurable: true,
          enumerable: false,
          value: stack,
          writable: true
        });
      }
      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 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
};

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$1 = id => {
  return callbacks[id];
};
const remove$1 = id => {
  delete callbacks[id];
};
class JsonRpcError extends Error {
  constructor(message) {
    super(message);
    this.name = 'JsonRpcError';
  }
}
const NewLine = '\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);
};
const splitLines = lines => {
  return lines.split(NewLine);
};
const getCurrentStack = () => {
  const stackLinesToSkip = 3;
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
  return currentStack;
};
const getNewLineIndex = (string, startIndex) => {
  {
    return string.indexOf(NewLine);
  }
};
const getParentStack = error => {
  let parentStack = error.stack || error.data || error.message || '';
  if (parentStack.startsWith('    at')) {
    parentStack = error.message + NewLine + parentStack;
  }
  return parentStack;
};
const MethodNotFound = -32601;
const Custom = -32001;
const restoreExistingError = (error, currentStack) => {
  if (typeof error.stack === 'string') {
    error.stack = error.stack + NewLine + currentStack;
  }
  return error;
};
const restoreMethodNotFoundError = (error, currentStack) => {
  const restoredError = new JsonRpcError(error.message);
  const parentStack = getParentStack(error);
  restoredError.stack = parentStack + NewLine + currentStack;
  return restoredError;
};
const restoreStackFromData = (restoredError, error, currentStack) => {
  if (error.data.stack && error.data.type && error.message) {
    restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
    return;
  }
  if (error.data.stack) {
    restoredError.stack = error.data.stack;
  }
};
const applyDataProperties = (restoredError, error) => {
  if (!error.data) {
    return;
  }
  restoreStackFromData(restoredError, error, getCurrentStack());
  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;
  }
};
const applyDirectProperties = (restoredError, error) => {
  if (error.stack) {
    const lowerStack = restoredError.stack || '';
    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;
  }
};
const restoreMessageError = (error, _currentStack) => {
  const restoredError = constructError(error.message, error.type, error.name);
  if (error.data) {
    applyDataProperties(restoredError, error);
  } else {
    applyDirectProperties(restoredError, error);
  }
  return restoredError;
};
const restoreJsonRpcError = error => {
  const currentStack = getCurrentStack();
  if (error && error instanceof Error) {
    return restoreExistingError(error, currentStack);
  }
  if (error && error.code && error.code === MethodNotFound) {
    return restoreMethodNotFoundError(error, currentStack);
  }
  if (error && error.message) {
    return restoreMessageError(error);
  }
  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 = (...args) => {
  console.warn(...args);
};
const resolve = (id, response) => {
  const fn = get$1(id);
  if (!fn) {
    console.log(response);
    warn(`callback ${id} may already be disposed`);
    return;
  }
  fn(response);
  remove$1(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$8 = (message, result) => {
  return {
    id: message.id,
    jsonrpc: Two$1,
    result: result ?? null
  };
};
const getSuccessResponse = (message, result) => {
  const resultProperty = result ?? null;
  return create$8(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$7 = (method, params) => {
  return {
    jsonrpc: Two,
    method,
    params
  };
};

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

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

const registerPromise = map => {
  const id = create$5();
  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$6(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$7(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$4 = 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$3 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  const {
    port1,
    port2
  } = new MessageChannel();
  await send(port1);
  return create$4({
    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$2 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  return createSharedLazyRpc(() => {
    return create$3({
      commandMap,
      isMessagePortOpen,
      send
    });
  });
};

const create$1 = 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 = Object.create(null);
const set$2 = (id, rpc) => {
  rpcs[id] = rpc;
};
const get = id => {
  return rpcs[id];
};
const remove = id => {
  delete rpcs[id];
};

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

const {
  invoke: invoke$1,
  set: set$1
} = create(ExtensionManagementWorker);

const {
  invoke,
  invokeAndTransfer,
  set
} = create(RendererWorker);
const showContextMenu2 = async (uid, menuId, x, y, args) => {
  number(uid);
  number(menuId);
  number(x);
  number(y);
  await invoke('ContextMenu.show2', uid, menuId, x, y, args);
};
const sendMessagePortToExtensionManagementWorker = async (port, rpcId) => {
  const command = 'Extensions.handleMessagePort';
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionManagementWorker', port, command, rpcId);
};

const show2 = async (uid, menuId, x, y, args) => {
  await showContextMenu2(uid, menuId, x, y, args);
};

const ACCOUNT_MENU_ID = 32_122;
const handleClickAccount = async (state, eventX, eventY, viewletId) => {
  const {
    sideBarLocation,
    uid
  } = state;
  try {
    await invoke('Layout.refreshAuthState');
  } catch {
    // Keep the account menu available when auth is unavailable.
  }
  await show2(uid, ACCOUNT_MENU_ID, eventX, eventY, {
    menuId: ACCOUNT_MENU_ID,
    openSubMenuToLeft: sideBarLocation === Right
  });
  return state;
};

const getMenuEntries = (state, options) => {
  const {
    menuId
  } = options;
  switch (menuId) {
    case ACCOUNT_MENU_ID:
      return getMenuEntriesAccount(state);
    case ACCOUNT_SUBMENU_ID:
      return getMenuEntriesAccountSubMenu(state);
    case ActivityBar$3:
      return getMenuEntriesActivityBar(state);
    case ActivityBarAdditionalViews:
      return getMenuEntriesAdditionalViews(state);
    case Settings$1:
      return getMenuEntriesSettings(state);
    default:
      return [];
  }
};

const getMenuEntryIds = () => {
  return [ActivityBar$3, ActivityBarAdditionalViews, Settings$1, ACCOUNT_MENU_ID, ACCOUNT_SUBMENU_ID];
};

const updateItemsWithBadgeCount = async items => {
  try {
    const badgeCounts = await invoke('Layout.getBadgeCounts');
    const newItems = items.map(item => {
      const badgeCount = badgeCounts[item.id] || 0;
      const badgeText = badgeCount ? String(badgeCount) : '';
      return {
        ...item,
        badgeText
      };
    });
    return newItems;
  } catch {
    return items;
  }
};

const updateStateItems = (state, activityBarItems) => {
  const {
    filteredItems: currentFilteredItems
  } = state;
  const itemById = new Map(activityBarItems.map(item => [item.id, item]));
  const filteredItems = currentFilteredItems.map(item => itemById.get(item.id) || item);
  return {
    ...state,
    activityBarItems,
    filteredItems
  };
};
const applyBadgeCountChanges = (state, badgeCounts) => {
  const {
    activityBarItems: currentActivityBarItems
  } = state;
  const activityBarItems = currentActivityBarItems.map(item => {
    if (!Object.hasOwn(badgeCounts, item.id)) {
      return item;
    }
    const badgeCount = badgeCounts[item.id];
    return {
      ...item,
      badgeText: badgeCount ? String(badgeCount) : ''
    };
  });
  return updateStateItems(state, activityBarItems);
};
const handleBadgeCountChange = async (state, badgeCounts) => {
  if (badgeCounts) {
    return applyBadgeCountChanges(state, badgeCounts);
  }
  const {
    activityBarItems
  } = state;
  const newActivityBarItems = await updateItemsWithBadgeCount(activityBarItems);
  if (newActivityBarItems === activityBarItems) {
    return state;
  }
  return updateStateItems(state, newActivityBarItems);
};

const handleBlur = state => {
  return {
    ...state,
    focused: false
  };
};

const isBottomItem = item => {
  return item.id === 'Account' || item.id === 'Settings';
};
const getBottomItemCount = items => {
  if (typeof items === 'number') {
    return items > 1 ? 1 : 0;
  }
  return items.filter(isBottomItem).length;
};
const getItemCount = items => {
  if (typeof items === 'number') {
    return items;
  }
  return items.length;
};
const getIndexFromPosition = (y, _eventX, eventY, itemHeight, items, height) => {
  const itemCount = getItemCount(items);
  if (itemCount === 0) {
    return -1;
  }
  // If there's only one item, treat it as a top item (not Settings at bottom)
  if (itemCount === 1) {
    const relativeY = eventY - y;
    const index = Math.floor(relativeY / itemHeight);
    if (index < 0 || index >= itemCount) {
      return -1;
    }
    return index;
  }
  const bottomItemCount = getBottomItemCount(items);
  const bottomItemsHeight = bottomItemCount * itemHeight;
  const bottomItemsTopY = y + height - bottomItemsHeight;
  if (bottomItemCount > 0 && eventY >= bottomItemsTopY && eventY < y + height) {
    const relativeBottomY = eventY - bottomItemsTopY;
    return itemCount - bottomItemCount + Math.floor(relativeBottomY / itemHeight);
  }
  const topItemCount = itemCount - bottomItemCount;
  const relativeY = eventY - y;
  const index = Math.floor(relativeY / itemHeight);
  if (index < 0 || index >= topItemCount) {
    return -1;
  }
  return index;
};

const handleClickAdditionalViews = async (state, eventX, eventY, viewletId) => {
  const {
    uid
  } = state;
  await show2(uid, ActivityBarAdditionalViews, eventX, eventY, {
    menuId: ActivityBarAdditionalViews,
    viewletId
  });
  return state;
};

const findIndex = (activityBarItems, id) => {
  for (let i = 0; i < activityBarItems.length; i++) {
    if (activityBarItems[i].id === id) {
      return i;
    }
  }
  return -1;
};

const Account = 'Account';
const DebugAlt2 = 'DebugAlt2';
const Extensions$1 = 'Extensions';
const Files = 'Files';
const Search$1 = 'Search';
const SettingsGear = 'SettingsGear';
const SourceControl$1 = 'SourceControl';
const Ellipsis = 'Ellipsis';

const getFilteredActivityBarItems = (items, height, itemHeight) => {
  const enabledItems = items.filter(item => item.flags & Enabled);
  const numberOfVisibleItems = getNumberOfVisibleItems({
    height,
    itemHeight
  });
  if (numberOfVisibleItems >= enabledItems.length) {
    return enabledItems;
  }
  const showMoreItem = {
    flags: Button,
    icon: Ellipsis,
    id: 'Additional Views',
    keyShortcuts: '',
    title: additionalViews()
  };
  return [...enabledItems.slice(0, numberOfVisibleItems - 2), showMoreItem, enabledItems.at(-1)];
};

const getSideBarChange = (sideBarVisible, currentViewletId, viewletId) => {
  if (sideBarVisible) {
    if (currentViewletId === viewletId) {
      return {
        type: 'hide',
        viewletId
      };
    }
    return {
      type: 'switch',
      viewletId
    };
  }
  return {
    type: 'show',
    viewletId
  };
};

const setFlag = (item, flag, enabled) => {
  return {
    ...item,
    flags: enabled ? item.flags | flag : item.flags & ~flag
  };
};

const markSelected = (items, selectedIndex) => {
  return items.map((item, index) => {
    const isSelected = index === selectedIndex;
    return setFlag(item, Selected, isSelected);
  });
};

const toggle = async id => {
  await invoke('Layout.toggleSideBarView', id);
};

const handleClickOther = async (state, viewletId) => {
  const {
    activityBarItems,
    currentViewletId,
    height,
    itemHeight,
    sideBarVisible
  } = state;
  const sideBarChange = getSideBarChange(sideBarVisible, currentViewletId, viewletId);
  await toggle(viewletId);
  if (sideBarChange.type === 'hide') {
    const newActivityBarItems = markSelected(activityBarItems, -1);
    const filteredItems = getFilteredActivityBarItems(newActivityBarItems, height, itemHeight);
    return {
      ...state,
      activityBarItems: newActivityBarItems,
      filteredItems,
      selectedIndex: -1,
      sideBarVisible: false
    };
  }
  const selectedIndex = findIndex(activityBarItems, viewletId);
  const newActivityBarItems = markSelected(activityBarItems, selectedIndex);
  const filteredItems = getFilteredActivityBarItems(newActivityBarItems, height, itemHeight);
  return {
    ...state,
    activityBarItems: newActivityBarItems,
    currentViewletId: viewletId,
    filteredItems,
    selectedIndex,
    sideBarVisible: true
  };
};

const handleClickSettings = async (state, eventX, eventY, viewletId) => {
  const {
    uid
  } = state;
  await show2(uid, Settings$1, eventX, eventY, {
    menuId: Settings$1
  });
  return state;
};

const handleClickIndex = async (state, button, index, x, y) => {
  if (button !== LeftClick) {
    return state;
  }
  if (index === -1) {
    return state;
  }
  const {
    filteredItems
  } = state;
  const item = filteredItems[index];
  const viewletId = item.id;
  switch (viewletId) {
    case 'Account':
      return handleClickAccount(state, x, y);
    case 'Additional Views':
      return handleClickAdditionalViews(state, x, y, viewletId);
    case 'Settings':
      return handleClickSettings(state, x, y);
    default:
      return handleClickOther(state, viewletId);
  }
};

const getIndexFromTarget = (state, targetName) => {
  if (!targetName) {
    return -1;
  }
  const {
    filteredItems
  } = state;
  return filteredItems.findIndex(item => item.id === targetName);
};
const handleClick = async (state, button, eventX, eventY, targetName = '') => {
  const {
    filteredItems,
    height,
    itemHeight,
    y
  } = state;
  const targetIndex = getIndexFromTarget(state, targetName);
  const index = targetIndex === -1 ? getIndexFromPosition(y, eventX, eventY, itemHeight, filteredItems, height) : targetIndex;
  return handleClickIndex(state, button, index, eventX, eventY);
};

const handleClickSignIn = async state => {
  await invoke('Layout.signIn');
  return state;
};

const handleClickSignOut = async state => {
  await invoke('Layout.signOut');
  return state;
};

const handleContextMenu = async (state, button, eventX, eventY) => {
  const {
    uid
  } = state;
  await show2(uid, ActivityBar$3, eventX, eventY, {
    menuId: ActivityBar$3
  });
  return state;
};

const commandMap$1 = {};

const handleExtensionManagementMessagePort = async port => {
  const rpc = await create$4({
    commandMap: commandMap$1,
    messagePort: port
  });
  set$1(rpc);
};

const hashString = value => {
  let hash = 2_166_136_261;
  for (const character of value) {
    hash ^= character.codePointAt(0) || 0;
    hash = Math.imul(hash, 16_777_619);
  }
  return (hash >>> 0).toString(36);
};
const getCustomIconClass = (id, iconUrl) => {
  const hashInput = id + '\n' + iconUrl;
  return `MaskIconCustomView${hashString(hashInput)}`;
};

const isCustomIconUrl = icon => {
  return icon.startsWith('http://') || icon.startsWith('https://') || icon.startsWith('file://') || icon.startsWith('lvce://') || icon.startsWith('/');
};

const Explorer = 'Explorer';
const Extensions = 'Extensions';
const RunAndDebug = 'Run And Debug';
const Search = 'Search';
const SourceControl = 'Source Control';

const toActivityBarItem = view => {
  const icon = view.icon || Extensions$1;
  const customIconUrl = isCustomIconUrl(icon) ? icon : undefined;
  const customIconClass = customIconUrl ? getCustomIconClass(view.id, customIconUrl) : undefined;
  const item = {
    flags: Tab | Enabled,
    icon,
    id: view.id,
    keyShortcuts: '',
    title: view.title || view.id
  };
  if (customIconClass && customIconUrl) {
    return {
      ...item,
      customIconClass,
      customIconUrl
    };
  }
  return item;
};
const getActivityBarItems = (state, contributedViews = []) => {
  const {
    accountEnabled
  } = state;
  const settingsFlags = Button | Enabled | (accountEnabled ? 0 : MarginTop);
  const items = [
  // Top
  {
    flags: Tab | Enabled,
    icon: Files,
    id: Explorer,
    keyShortcuts: 'Control+Shift+E',
    title: explorer()
  }, {
    flags: Tab | Enabled,
    icon: Search$1,
    id: Search,
    keyShortcuts: 'Control+Shift+F',
    title: search()
  }, {
    flags: Tab | Enabled,
    icon: SourceControl$1,
    id: SourceControl,
    keyShortcuts: 'Control+Shift+G',
    title: sourceControl()
  }, {
    flags: Tab | Enabled,
    icon: DebugAlt2,
    id: RunAndDebug,
    keyShortcuts: 'Control+Shift+D',
    title: runAndDebug()
  }, {
    flags: Tab | Enabled,
    icon: Extensions$1,
    id: Extensions,
    keyShortcuts: 'Control+Shift+X',
    title: extensions()
  }, ...contributedViews.map(toActivityBarItem)
  // Bottom
  ];
  if (accountEnabled) {
    items.push({
      flags: Button | Enabled | MarginTop,
      icon: Account,
      id: 'Account',
      keyShortcuts: '',
      title: account()
    });
  }
  items.push({
    flags: settingsFlags,
    icon: SettingsGear,
    id: 'Settings',
    keyShortcuts: '',
    title: settings()
  });
  return items;
};

const getContributedViews = async platform => {
  try {
    const views = await invoke$1('Extensions.getViews', '', platform);
    if (!Array.isArray(views)) {
      return [];
    }
    return views.filter(view => view?.type !== 'preview');
  } catch {
    return [];
  }
};

const handleExtensionsChanged = async state => {
  const {
    height,
    itemHeight,
    platform,
    selectedIndex
  } = state;
  const contributedViews = await getContributedViews(platform);
  const items = getActivityBarItems(state, contributedViews);
  const itemsWithSelected = markSelected(items, selectedIndex);
  const activityBarItems = await updateItemsWithBadgeCount(itemsWithSelected);
  const filteredItems = getFilteredActivityBarItems(activityBarItems, height, itemHeight);
  return {
    ...state,
    activityBarItems,
    filteredItems
  };
};

const handleFocus = state => {
  return {
    ...state,
    focused: true
  };
};

const handleResize = (state, dimensions) => {
  const {
    activityBarItems,
    itemHeight
  } = state;
  const {
    height,
    width,
    x,
    y
  } = dimensions;
  const filteredItems = getFilteredActivityBarItems(activityBarItems, height, itemHeight);
  return {
    ...state,
    filteredItems,
    height,
    width,
    x,
    y
  };
};

const getAccountEnabled = async defaultValue => {
  try {
    const value = await invoke('Preferences.get', 'activityBar.accountEnabled');
    return typeof value === 'boolean' ? value : defaultValue;
  } catch {
    return defaultValue;
  }
};

const getSideBarPosition = async () => {
  try {
    return await invoke('Layout.getSideBarPosition');
  } catch {
    return Left;
  }
};

const handleSettingsChanged = async state => {
  const {
    accountEnabled: currentAccountEnabled,
    height,
    itemHeight,
    platform,
    selectedIndex
  } = state;
  const [accountEnabled, contributedViews, sidebarLocation] = await Promise.all([getAccountEnabled(currentAccountEnabled), getContributedViews(platform), getSideBarPosition()]);
  const newState = {
    ...state,
    accountEnabled
  };
  const items = getActivityBarItems(newState, contributedViews);
  const itemsWithSelected = markSelected(items, selectedIndex);
  const activityBarItems = await updateItemsWithBadgeCount(itemsWithSelected);
  const filteredItems = getFilteredActivityBarItems(activityBarItems, height, itemHeight);
  return {
    ...newState,
    activityBarItems,
    filteredItems,
    sideBarLocation: sidebarLocation
  };
};

const getSideBarVisible = async () => {
  try {
    const visible = await invoke('Layout.getSideBarVisible');
    return visible;
  } catch {
    return true;
  }
};

const clearItem = item => {
  const withoutSelected = setFlag(item, Selected, false);
  return setFlag(withoutSelected, Focused, false);
};
const handleSideBarStateChange = async (state, id, sideBarVisibleOverride) => {
  const {
    activityBarItems,
    currentViewletId,
    height,
    itemHeight
  } = state;
  const resolvedId = id === undefined ? currentViewletId : id;
  const sideBarVisible = typeof sideBarVisibleOverride === 'boolean' ? sideBarVisibleOverride : await getSideBarVisible();
  if (!sideBarVisible) {
    const itemsCleared = activityBarItems.map(clearItem);
    const filteredItems = getFilteredActivityBarItems(itemsCleared, height, itemHeight);
    return {
      ...state,
      activityBarItems: itemsCleared,
      filteredItems,
      focusedIndex: -1,
      selectedIndex: -1,
      sideBarVisible: false
    };
  }
  const selectedIndex = findIndex(activityBarItems, resolvedId);
  const newActivityBarItems = markSelected(activityBarItems, selectedIndex);
  const filteredItems = getFilteredActivityBarItems(newActivityBarItems, height, itemHeight);
  return {
    ...state,
    activityBarItems: newActivityBarItems,
    currentViewletId: resolvedId,
    filteredItems,
    selectedIndex,
    sideBarVisible
  };
};

const CheckingForUpdate = 1;
const WaitingForRestart = 4;

const getNewItems = (items, state) => {
  return items.map(item => {
    if (item.id === 'Settings') {
      if (state === CheckingForUpdate) {
        return {
          ...item,
          badgeIcon: 'clock',
          flags: item.flags | Progress
        };
      }
      if (state === WaitingForRestart) {
        return {
          ...item,
          badgeIcon: '',
          badgeText: '1'
        };
      }
      return item;
    }
    return item;
  });
};
const handleUpdateStateChange = async (state, config) => {
  const {
    filteredItems
  } = state;
  const newItems = getNewItems(filteredItems, config.state);
  return {
    ...state,
    filteredItems: newItems,
    updateProgress: config.progress,
    updateState: config.state
  };
};

const getActiveView = async () => {
  try {
    const activeView = await invoke('Layout.getActiveSideBarView');
    return activeView;
  } catch {
    return Explorer;
  }
};

const loadPreferences = async (accountEnabled, platform) => {
  const [accountEnabledNew, activeView, contributedViews, sidebarLocation, sideBarVisible] = await Promise.all([getAccountEnabled(accountEnabled), getActiveView(), getContributedViews(platform), getSideBarPosition(), getSideBarVisible()]);
  return {
    accountEnabled: accountEnabledNew,
    activeView,
    contributedViews,
    sidebarLocation,
    sideBarVisible
  };
};

const loadContent = async state => {
  const {
    accountEnabled,
    height,
    itemHeight,
    platform
  } = state;
  const {
    accountEnabled: accountEnabledNew,
    activeView,
    contributedViews,
    sidebarLocation,
    sideBarVisible
  } = await loadPreferences(accountEnabled, platform);
  const newState = {
    ...state,
    accountEnabled: accountEnabledNew
  };
  const items = getActivityBarItems(newState, contributedViews);
  const index = items.findIndex(item => item.id === activeView);
  const selectedIndex = sideBarVisible ? index : -1;
  const itemsWithSelected = markSelected(items, selectedIndex);
  const activityBarItems = await updateItemsWithBadgeCount(itemsWithSelected);
  const filteredItems = getFilteredActivityBarItems(activityBarItems, height, itemHeight);
  return {
    ...newState,
    activityBarItems,
    currentViewletId: Explorer,
    filteredItems,
    initial: false,
    selectedIndex,
    sideBarLocation: sidebarLocation,
    sideBarVisible
  };
};

const escapeCssUrl = url => {
  return url.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('\n', '\\a ').replaceAll('\r', '\\d ').replaceAll('\f', '\\c ');
};

const getCustomIconCss = items => {
  const seen = new Set();
  let css = '';
  for (const item of items) {
    const {
      customIconClass,
      customIconUrl
    } = item;
    if (!customIconClass || !customIconUrl || seen.has(customIconClass)) {
      continue;
    }
    seen.add(customIconClass);
    css += `.${customIconClass} {
  mask-image: url("${escapeCssUrl(customIconUrl)}");
}
`;
  }
  return css;
};

const getCss = (itemHeight, items = []) => {
  return `:root {
  --ActivityBarItemHeight: var(--${itemHeight}px);
}
${getCustomIconCss(items)}`;
};

const renderCss = (oldState, newState) => {
  const {
    filteredItems,
    itemHeight,
    uid
  } = newState;
  const css = getCss(itemHeight, filteredItems);
  return [SetCss, uid, css];
};

const renderFocusContext = (oldState, newState) => {
  if (newState.focus === List) {
    return [SetFocusContext, newState.uid, FocusExplorer];
  }
  return [];
};

const mergeClassNames = (...classNames) => {
  return classNames.filter(Boolean).join(' ');
};

const text = data => {
  return {
    childCount: 0,
    text: data,
    type: Text
  };
};

new Set(Object.values(VirtualDomElements));

const SetText = 1;
const Replace = 2;
const SetAttribute = 3;
const RemoveAttribute = 4;
const Add = 6;
const NavigateChild = 7;
const NavigateParent = 8;
const RemoveChild = 9;
const NavigateSibling = 10;
const SetReferenceNodeUid = 11;

const isKey = key => {
  return key !== 'type' && key !== 'childCount';
};

const getKeys = node => {
  const keys = Object.keys(node).filter(isKey);
  return keys;
};

const arrayToTree = nodes => {
  const result = [];
  let i = 0;
  while (i < nodes.length) {
    const node = nodes[i];
    const {
      children,
      nodesConsumed
    } = getChildrenWithCount(nodes, i + 1, node.childCount || 0);
    result.push({
      node,
      children
    });
    i += 1 + nodesConsumed;
  }
  return result;
};
const getChildrenWithCount = (nodes, startIndex, childCount) => {
  if (childCount === 0) {
    return {
      children: [],
      nodesConsumed: 0
    };
  }
  const children = [];
  let i = startIndex;
  let remaining = childCount;
  let totalConsumed = 0;
  while (remaining > 0 && i < nodes.length) {
    const node = nodes[i];
    const nodeChildCount = node.childCount || 0;
    const {
      children: nodeChildren,
      nodesConsumed
    } = getChildrenWithCount(nodes, i + 1, nodeChildCount);
    children.push({
      node,
      children: nodeChildren
    });
    const nodeSize = 1 + nodesConsumed;
    i += nodeSize;
    totalConsumed += nodeSize;
    remaining--;
  }
  return {
    children,
    nodesConsumed: totalConsumed
  };
};

const compareNodes = (oldNode, newNode) => {
  // Check if node type changed - return null to signal incompatible nodes
  // (caller should handle this with a Replace operation)
  if (oldNode.type !== newNode.type) {
    return null;
  }
  const patches = [];
  // Handle reference nodes - special handling for uid changes
  if (oldNode.type === Reference) {
    if (oldNode.uid !== newNode.uid) {
      patches.push({
        type: SetReferenceNodeUid,
        uid: newNode.uid
      });
    }
    return patches;
  }
  // Handle text nodes
  if (oldNode.type === Text && newNode.type === Text) {
    if (oldNode.text !== newNode.text) {
      patches.push({
        type: SetText,
        value: newNode.text
      });
    }
    return patches;
  }
  // Compare attributes
  const oldKeys = getKeys(oldNode);
  const newKeys = getKeys(newNode);
  // Check for attribute changes
  for (const key of newKeys) {
    if (oldNode[key] !== newNode[key]) {
      patches.push({
        type: SetAttribute,
        key,
        value: newNode[key]
      });
    }
  }
  // Check for removed attributes
  for (const key of oldKeys) {
    if (!Object.hasOwn(newNode, key)) {
      patches.push({
        type: RemoveAttribute,
        key
      });
    }
  }
  return patches;
};

const treeToArray = node => {
  const result = [node.node];
  for (const child of node.children) {
    result.push(...treeToArray(child));
  }
  return result;
};

const navigateToChild = (patches, currentChildIndex, index) => {
  if (currentChildIndex === -1) {
    patches.push({
      type: NavigateChild,
      index
    });
    return index;
  }
  if (currentChildIndex !== index) {
    patches.push({
      type: NavigateSibling,
      index
    });
  }
  return index;
};
const navigateToParent = (patches, currentChildIndex) => {
  if (currentChildIndex >= 0) {
    patches.push({
      type: NavigateParent
    });
  }
  return -1;
};
const addTree = (newNode, patches) => {
  patches.push({
    type: Add,
    nodes: treeToArray(newNode)
  });
};
const replaceTree = (newNode, patches) => {
  patches.push({
    type: Replace,
    nodes: treeToArray(newNode)
  });
};
const diffExistingChild = (oldNode, newNode, patches, currentChildIndex, index) => {
  const nodePatches = compareNodes(oldNode.node, newNode.node);
  if (nodePatches === null) {
    const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
    replaceTree(newNode, patches);
    return nextChildIndex;
  }
  const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
  if (nodePatches.length === 0 && !hasChildrenToCompare) {
    return currentChildIndex;
  }
  const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
  if (nodePatches.length > 0) {
    patches.push(...nodePatches);
  }
  if (hasChildrenToCompare) {
    diffChildren(oldNode.children, newNode.children, patches);
  }
  return nextChildIndex;
};
const diffRootNode = (oldNode, newNode, patches) => {
  const nodePatches = compareNodes(oldNode.node, newNode.node);
  if (nodePatches === null) {
    replaceTree(newNode, patches);
    return;
  }
  if (nodePatches.length > 0) {
    patches.push(...nodePatches);
  }
  if (oldNode.children.length > 0 || newNode.children.length > 0) {
    diffChildren(oldNode.children, newNode.children, patches);
  }
};
const diffChildren = (oldChildren, newChildren, patches) => {
  const maxLength = Math.max(oldChildren.length, newChildren.length);
  let currentChildIndex = -1;
  const indicesToRemove = [];
  for (let i = 0; i < maxLength; i++) {
    const oldNode = oldChildren[i];
    const newNode = newChildren[i];
    if (!oldNode && !newNode) {
      continue;
    }
    if (!oldNode) {
      currentChildIndex = navigateToParent(patches, currentChildIndex);
      addTree(newNode, patches);
      continue;
    }
    if (!newNode) {
      indicesToRemove.push(i);
      continue;
    }
    currentChildIndex = diffExistingChild(oldNode, newNode, patches, currentChildIndex, i);
  }
  navigateToParent(patches, currentChildIndex);
  for (let j = indicesToRemove.length - 1; j >= 0; j--) {
    patches.push({
      type: RemoveChild,
      index: indicesToRemove[j]
    });
  }
};
const diffTrees = (oldTree, newTree, patches, path) => {
  if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
    diffRootNode(oldTree[0], newTree[0], patches);
    return;
  }
  diffChildren(oldTree, newTree, patches);
};

const removeTrailingNavigationPatches = patches => {
  // Find the last non-navigation patch
  let lastNonNavigationIndex = -1;
  for (let i = patches.length - 1; i >= 0; i--) {
    const patch = patches[i];
    if (patch.type !== NavigateChild && patch.type !== NavigateParent && patch.type !== NavigateSibling) {
      lastNonNavigationIndex = i;
      break;
    }
  }
  // Return patches up to and including the last non-navigation patch
  return lastNonNavigationIndex === -1 ? [] : patches.slice(0, lastNonNavigationIndex + 1);
};

const diffTree = (oldNodes, newNodes) => {
  // Step 1: Convert flat arrays to tree structures
  const oldTree = arrayToTree(oldNodes);
  const newTree = arrayToTree(newNodes);
  // Step 3: Compare the trees
  const patches = [];
  diffTrees(oldTree, newTree, patches, []);
  // Remove trailing navigation patches since they serve no purpose
  return removeTrailingNavigationPatches(patches);
};

const Vertical = 'vertical';

const ActivityBar$1 = 'ActivityBar';
const ActivityBarItem = 'ActivityBarItem';
const ActivityBarItemNested = 'ActivityBarItemNested';
const ActivityBarItemSelected = 'ActivityBarItemSelected';
const ActivityBarItemBadge = 'ActivityBarItemBadge';
const BadgeContent = 'BadgeContent';
const FocusOutline = 'FocusOutline';
const Icon = 'Icon';
const MarginTopAuto = 'MarginTopAuto';
const Viewlet = 'Viewlet';
const MaskIconProgress = 'MaskIconProgress';
const ActivityBarBadgeIcon = 'ActivityBarBadgeIcon';

const HandleBlur = 1;
const HandleContextMenu = 2;
const HandleFocus = 3;
const HandleMouseDown = 4;

const ActivityBar = 'ActivityBar';

const getActivityBarItemHasPopup = item => {
  return item.id === 'Account' || item.id === 'Settings';
};

const getAriaSelected = (isTab, isSelected) => {
  if (!isTab) {
    return undefined;
  }
  return Boolean(isSelected);
};

const getBadgeVirtualDom = () => {
  return [{
    childCount: 1,
    className: ActivityBarItemBadge,
    type: Div
  }, {
    childCount: 1,
    className: BadgeContent,
    type: Div
  }, {
    childCount: 0,
    className: mergeClassNames(Icon, ActivityBarBadgeIcon, MaskIconProgress),
    type: Div
  }];
};

const getClassName = (isFocused, marginTop, isSelected) => {
  const classNames = [ActivityBarItem];
  if (isFocused) {
    classNames.push(FocusOutline);
  }
  if (marginTop) {
    classNames.push(MarginTopAuto);
  }
  if (isSelected) {
    classNames.push(ActivityBarItemSelected);
  }
  return mergeClassNames(...classNames);
};

const getIconClass = (item, builtinPrefix) => {
  if (item.customIconClass) {
    return item.customIconClass;
  }
  return `${builtinPrefix}${item.icon}`;
};

const getActivityBarItemInProgressDom = item => {
  const {
    flags,
    title
  } = item;
  const isTab = flags & Tab;
  const isSelected = flags & Selected;
  const isFocused = flags & Focused;
  const role = isTab ? Tab$1 : Button$3;
  const ariaSelected = getAriaSelected(isTab, isSelected);
  const ariaHasPopup = getActivityBarItemHasPopup(item) || undefined;
  const marginTop = flags & MarginTop;
  let className = getClassName(isFocused, marginTop, isSelected);
  className += ' ' + ActivityBarItemNested;
  return [{
    ariaHasPopup,
    ariaSelected,
    childCount: 2,
    className,
    role,
    title,
    type: Div
  }, {
    childCount: 0,
    className: mergeClassNames(Icon, getIconClass(item, 'MaskIcon')),
    role: None$1,
    type: Div
  }, ...getBadgeVirtualDom()];
};

const getActivityBarItemWithBadgeDom = item => {
  const {
    badgeText,
    flags,
    id,
    title
  } = item;
  if (!badgeText) {
    // TODO should not happen
    return [];
  }
  const isTab = flags & Tab;
  const isSelected = flags & Selected;
  const isFocused = flags & Focused;
  const role = isTab ? Tab$1 : Button$3;
  const ariaSelected = getAriaSelected(isTab, isSelected);
  const ariaHasPopup = getActivityBarItemHasPopup(item) || undefined;
  const marginTop = flags & MarginTop;
  let className = getClassName(isFocused, marginTop, isSelected);
  className += ' ' + ActivityBarItemNested;
  return [{
    ariaHasPopup,
    ariaSelected,
    childCount: 2,
    className,
    name: id,
    role,
    title,
    type: Div
  }, {
    childCount: 0,
    className: mergeClassNames(Icon, getIconClass(item, 'MaskIcon')),
    name: id,
    role: None$1,
    type: Div
  }, {
    childCount: 1,
    className: ActivityBarItemBadge,
    name: id,
    type: Div
  }, text(badgeText)];
};

const getIconVirtualDom = (icon, type = Div, customIconClass = '') => {
  return {
    childCount: 0,
    className: customIconClass ? `MaskIcon ${customIconClass}` : `MaskIcon MaskIcon${icon}`,
    role: None$1,
    type
  };
};

const getActivityBarItemVirtualDom = item => {
  const {
    badgeText,
    flags,
    icon,
    id,
    title
  } = item;
  const ariaHasPopup = getActivityBarItemHasPopup(item) || undefined;
  const isTab = flags & Tab;
  const isSelected = flags & Selected;
  const isFocused = flags & Focused;
  const isProgress = flags & Progress;
  const role = isTab ? Tab$1 : Button$3;
  const ariaSelected = getAriaSelected(isTab, isSelected);
  const marginTop = flags & MarginTop;
  const className = getClassName(isFocused, marginTop, isSelected);
  if (isSelected && !badgeText) {
    return [{
      ariaHasPopup,
      ariaSelected,
      childCount: 1,
      className,
      name: id,
      role,
      title,
      type: Div
    }, {
      ...getIconVirtualDom(icon, Div, item.customIconClass),
      name: id
    }];
  }

  // TODO support progress on selected activity bar item
  if (isProgress) {
    return getActivityBarItemInProgressDom(item);
  }
  if (badgeText) {
    return getActivityBarItemWithBadgeDom(item);
  }
  return [{
    ariaHasPopup,
    ariaSelected,
    childCount: 0,
    className: mergeClassNames(className, getIconClass(item, 'Icon')),
    name: id,
    role,
    title,
    type: Div
  }];
};

const getVirtualDom = visibleItems => {
  const dom = visibleItems.flatMap(getActivityBarItemVirtualDom);
  return dom;
};

const Focusable = 0;

const className = mergeClassNames(Viewlet, ActivityBar$1);
const getActivityBarVirtualDom = visibleItems => {
  return [{
    ariaOrientation: Vertical,
    ariaRoleDescription: activityBar(),
    childCount: visibleItems.length,
    className,
    id: ActivityBar,
    onBlur: HandleBlur,
    onContextMenu: HandleContextMenu,
    onFocus: HandleFocus,
    onMouseDown: HandleMouseDown,
    role: ToolBar,
    tabIndex: Focusable,
    type: Div
  }, ...getVirtualDom(visibleItems)];
};

const renderItems = (oldState, newState) => {
  const {
    filteredItems,
    initial,
    uid
  } = newState;
  if (initial) {
    return [SetDom2, uid, []];
  }
  const dom = getActivityBarVirtualDom(filteredItems);
  return [SetDom2, uid, dom];
};

const renderIncremental = (oldState, newState) => {
  const oldDom = renderItems(oldState, oldState)[2];
  const newDom = renderItems(newState, newState)[2];
  const patches = diffTree(oldDom, newDom);
  if (patches.length === 0) {
    return [];
  }
  return [SetPatches, newState.uid, patches];
};

const getRenderer = diffType => {
  switch (diffType) {
    case RenderCss:
      return renderCss;
    case RenderFocus:
      return renderFocusContext;
    case RenderFocusContext:
      return renderFocusContext;
    case RenderIncremental:
      return renderIncremental;
    case RenderItems:
      return renderItems;
    default:
      throw new Error('unknown renderer');
  }
};

const applyRender = (oldState, newState, diffResult) => {
  const commands = [];
  for (const item of diffResult) {
    const fn = getRenderer(item);
    const result = fn(oldState, newState);
    if (result.length > 0) {
      commands.push(result);
    }
  }
  return commands;
};

const render2 = (uid, diffResult) => {
  const {
    newState,
    oldState
  } = get$2(uid);
  set$3(uid, newState, newState);
  const commands = applyRender(oldState, newState, diffResult);
  return commands;
};

const renderEventListeners = () => {
  return [{
    name: HandleBlur,
    params: ['handleBlur']
  }, {
    name: HandleFocus,
    params: ['handleFocus']
  }, {
    name: HandleContextMenu,
    params: ['handleContextMenu', Button$1, ClientX, ClientY],
    preventDefault: true
  }, {
    name: HandleMouseDown,
    params: ['handleClick', Button$1, ClientX, ClientY, TargetName],
    preventDefault: false,
    stopPropagation: false
  }];
};

const saveState = state => {
  return {};
};

const setAccountEnabled = (state, enabled) => {
  const {
    height,
    itemHeight,
    selectedIndex
  } = state;
  const newState = {
    ...state,
    accountEnabled: enabled
  };
  const newActivityBarItems = getActivityBarItems(newState);
  const markedItems = markSelected(newActivityBarItems, selectedIndex);
  const filteredItems = getFilteredActivityBarItems(markedItems, height, itemHeight);
  return {
    ...newState,
    activityBarItems: markedItems,
    filteredItems: filteredItems
  };
};

const providerKeys = ['userLoginProvider', 'loginProvider', 'authProvider', 'provider'];
const getUserLoginProvider = userInfo => {
  if (!userInfo || typeof userInfo !== 'object') {
    return 'GitHub';
  }
  const record = userInfo;
  for (const key of providerKeys) {
    if (typeof record[key] === 'string' && record[key]) {
      return record[key];
    }
  }
  return 'GitHub';
};

const getUserName = userInfo => {
  if (!userInfo || typeof userInfo !== 'object') {
    return '';
  }
  if (!('userName' in userInfo) || typeof userInfo.userName !== 'string') {
    return '';
  }
  return userInfo.userName;
};

const setUserLoginState = (state, userLoginState, userInfo) => {
  return {
    ...state,
    userLoginProvider: getUserLoginProvider(userInfo),
    userLoginState,
    userName: getUserName(userInfo)
  };
};

const toggleActivityBarItem = async (state, itemId) => {
  const {
    activityBarItems,
    height,
    itemHeight
  } = state;
  const updatedItems = activityBarItems.map(item => {
    if (item.id === itemId) {
      const isCurrentlyEnabled = item.flags & Enabled;
      return {
        ...item,
        flags: isCurrentlyEnabled ? item.flags & -9 : item.flags | Enabled
      };
    }
    return item;
  });
  const filteredItems = getFilteredActivityBarItems(updatedItems, height, itemHeight);
  return {
    ...state,
    activityBarItems: updatedItems,
    filteredItems
  };
};

const commandMap = {
  'ActivityBar.create': create$9,
  'ActivityBar.diff2': diff2,
  'ActivityBar.focus': wrapCommand(focus),
  'ActivityBar.focusFirst': wrapCommand(focusFirst),
  'ActivityBar.focusIndex': wrapCommand(focusIndex),
  'ActivityBar.focusLast': wrapCommand(focusLast),
  'ActivityBar.focusNext': wrapCommand(focusNext),
  'ActivityBar.focusNone': wrapCommand(focusNone),
  'ActivityBar.getCommandIds': getCommandIds,
  'ActivityBar.getKeyBindings': getKeyBindings,
  'ActivityBar.getMenuEntries': wrapGetter(getMenuEntries),
  'ActivityBar.getMenuEntryIds': getMenuEntryIds,
  'ActivityBar.handleBadgeCountChange': wrapCommand(handleBadgeCountChange),
  'ActivityBar.handleBlur': wrapCommand(handleBlur),
  'ActivityBar.handleClick': wrapCommand(handleClick),
  'ActivityBar.handleClickAccount': wrapCommand(handleClickAccount),
  'ActivityBar.handleClickAdditionalViews': wrapCommand(handleClickAdditionalViews),
  'ActivityBar.handleClickIndex': wrapCommand(handleClickIndex),
  'ActivityBar.handleClickSettings': wrapCommand(handleClickSettings),
  'ActivityBar.handleClickSignIn': wrapCommand(handleClickSignIn),
  'ActivityBar.handleClickSignOut': wrapCommand(handleClickSignOut),
  'ActivityBar.handleContextMenu': wrapCommand(handleContextMenu),
  'ActivityBar.handleExtensionManagementMessagePort': handleExtensionManagementMessagePort,
  'ActivityBar.handleExtensionsChanged': wrapCommand(handleExtensionsChanged),
  'ActivityBar.handleFocus': wrapCommand(handleFocus),
  'ActivityBar.handleSettingsChanged': wrapCommand(handleSettingsChanged),
  'ActivityBar.handleSideBarStateChange': wrapCommand(handleSideBarStateChange),
  'ActivityBar.handleUpdateStateChange': wrapCommand(handleUpdateStateChange),
  'ActivityBar.loadContent': wrapCommand(loadContent),
  'ActivityBar.render2': render2,
  'ActivityBar.renderEventListeners': renderEventListeners,
  'ActivityBar.resize': wrapCommand(handleResize),
  'ActivityBar.saveState': wrapGetter(saveState),
  'ActivityBar.setAccountEnabled': wrapCommand(setAccountEnabled),
  'ActivityBar.setUserLoginState': wrapCommand(setUserLoginState),
  'ActivityBar.terminate': terminate,
  'ActivityBar.toggleActivityBarItem': wrapCommand(toggleActivityBarItem)
};

const send = async port => {
  await sendMessagePortToExtensionManagementWorker(port, 0);
};
const initializeExtensionManagementWorker = async () => {
  const rpc = await create$2({
    commandMap: {},
    send
  });
  set$1(rpc);
};

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

const listen = async () => {
  registerCommands(commandMap);
  await Promise.all([initializeRendererWorker(), initializeExtensionManagementWorker()]);
};

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

main();
