npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jitsi/electron-sdk

v10.0.3

Published

Utilities for jitsi-meet-electron project

Readme

Jitsi Meet Electron SDK

SDK for integrating Jitsi Meet into Electron applications.

The SDK is built for contextIsolation: true (and, where possible, sandbox: true) on the window that hosts Jitsi Meet, following Electron's security guidelines. Native code that used to run in the renderer (remote control via robotjs) now runs only in the main process, and every renderer ↔ main message goes through a single, validated contextBridge surface.

Upgrading from v9? The single require('@jitsi/electron-sdk') entry has been removed and replaced by three context-specific entry points. See Migrating from v9.

Installation

Install from npm:

npm install @jitsi/electron-sdk

Note: This package contains native code on Windows for the remote control module. Binary prebuilds are packaged with prebuildify as part of the npm package. @jitsi/robotjs is a dependency but is only ever loaded in the main process.

Architecture

The SDK ships three entry points, each named after the Electron context its code runs in. There is no default (.) entry — importing @jitsi/electron-sdk directly fails with a module-resolution error by design.

| Entry point | Runs in | Exposes | | --- | --- | --- | | @jitsi/electron-sdk/main | Electron main process | setupRemoteControlMain, setupScreenSharingMain, setupPowerMonitorMain, cleanupPowerMonitorMain, setupPictureInPictureMain, initPopupsConfigurationMain, getPopupTarget, popupsConfigRegistry | | @jitsi/electron-sdk/preload | app preload script | install() — exposes the SDK bridge on the main world via contextBridge | | @jitsi/electron-sdk/renderer | the page ("main world") | setupRemoteControlRender, setupScreenSharingRender, setupPowerMonitorRender, setupPictureInPictureRender, initPopupsConfigurationRender |

╔═ renderer process ═══════════════════════════════════════════════╗
║  page / "main world"  →  @jitsi/electron-sdk/renderer             ║
║    owns api.* events + postis; no electron/node/native requires   ║
║                     │  window.jitsiElectronSDK (validated bridge) ║
║  preload / isolated  →  @jitsi/electron-sdk/preload               ║
║    thin ipcRenderer wrappers, per-feature, payload-validated      ║
╚═════════════════════│═════════════════════════════════════════════╝
                      │  IPC — namespaced, sender-validated channels
┌═ main process ══════┴═════════════════════════════════════════════┐
│  @jitsi/electron-sdk/main  →  setup*Main (+ robotjs execution)     │
└───────────────────────────────────────────────────────────────────┘

The bridge (window.jitsiElectronSDK)

The preload entry exposes one namespaced object to the page. Renderer code never touches ipcRenderer directly — it talks to the main process only through this surface. Only cloneable data crosses the bridge; callbacks are supported as subscriptions that return an unsubscribe function. Every bridge-backed setup*Render reads its fragment off window.jitsiElectronSDK, so the preload must be installed — and the window created with context isolation — before they are called. (initPopupsConfigurationRender is the one exception: it is a no-op and does not use the bridge.)

Setup

1. Window configuration

Create the window that hosts Jitsi Meet with context isolation on and a preload that installs the bridge:

const jitsiMeetWindow = new BrowserWindow({
    webPreferences: {
        contextIsolation: true,
        sandbox: true, // robotjs no longer runs in the renderer, so the page can be sandboxed
        preload: '/absolute/path/to/your/bundled/preload.js'
    }
});

2. Preload script

A sandboxed preload cannot require from node_modules, so the app's preload must be bundled (esbuild, webpack, etc.). Call install() from it to expose the bridge:

// app preload (bundled)
import { install } from '@jitsi/electron-sdk/preload';

install();

install() puts the bridge on the main world under an SDK-internal key that the /renderer helpers read for you — your code never names it. Call it once, from a preload running with contextIsolation enabled.

3. Main process

Set up the main-process components before the renderer components, and clean handlers up on window close to prevent leaks:

const { setupScreenSharingMain } = require('@jitsi/electron-sdk/main');

setupScreenSharingMain(jitsiMeetWindow, appName, osxBundleId);

4. Renderer

Bundle the renderer entry into the app's page code and call the setup*Render helpers with the live JitsiMeetExternalAPI instance:

import { setupScreenSharingRender } from '@jitsi/electron-sdk/renderer';

// api - the JitsiMeetExternalAPI instance created by the page.
setupScreenSharingRender(api);

Usage

The setup* function names and signatures are unchanged from v9 — only the entry point you import them from has changed.

Remote Control

Enables remote desktop control during a Jitsi Meet session. Mouse/keyboard events are forwarded over the bridge and executed in the main process by robotjs; the renderer never loads a native module.

Requirements:

  1. Jitsi Meet must be initialized through the iframe API.
  2. setupRemoteControlRender requires the Jitsi Meet iframe API object.

In the main process:

const { setupRemoteControlMain } = require('@jitsi/electron-sdk/main');

// jitsiMeetWindow - the BrowserWindow where Jitsi Meet is loaded.
setupRemoteControlMain(jitsiMeetWindow);

User consent: every session start is gated on an explicit confirmation collected in the main process, because the start request reaches the renderer as an iframe → top-frame postMessage and therefore carries no trustworthy identity. By default a native, modal message box parented to jitsiMeetWindow is shown; web content can neither render, click nor dismiss it. Pass requestConsent to provide your own wording (for instance a localized dialog); it receives { sourceId } and must resolve to true only when the user explicitly allowed the session. Whatever you supply must not be renderable or dismissable by web content — a prompt inside the meeting page is not a consent gate.

setupRemoteControlMain(jitsiMeetWindow, {
    async requestConsent({ sourceId }) { // eslint-disable-line no-unused-vars
        const { response } = await dialog.showMessageBox(jitsiMeetWindow, {
            type: 'warning',
            buttons: [ t('remoteControl.deny'), t('remoteControl.allow') ],
            defaultId: 0,
            cancelId: 0,
            message: t('remoteControl.message'),
            detail: t('remoteControl.detail')
        });

        return response === 1;
    }
});

Passing requestConsent: false disables the gate: every requested session starts, with no prompt and no interaction.

// Starts remote control sessions unconditionally. Read the warning below first.
setupRemoteControlMain(jitsiMeetWindow, { requestConsent: false });

[!WARNING] Only do this when you can guarantee that a start request cannot originate from untrusted web content — a kiosk or support appliance that loads one deployment you control, and that has already obtained consent out of band.

In the renderer (page hosting Jitsi Meet):

import { setupRemoteControlRender } from '@jitsi/electron-sdk/renderer';

// api - the Jitsi Meet iframe api object.
const remoteControl = setupRemoteControlRender(api);

To disable remote control:

remoteControl.dispose();

NOTE: dispose is called automatically on the Jitsi Meet API readyToClose event or when the iframe API's own dispose method runs.

Screen Sharing

Custom screen/window picker plus an always-on-top "X is sharing your screen" tracker window.

In the main process:

const { setupScreenSharingMain } = require('@jitsi/electron-sdk/main');

// jitsiMeetWindow - the BrowserWindow where Jitsi Meet is loaded.
// appName     - shown in the tracker window: "{appName} is sharing your screen".
// osxBundleId - macOS bundle id; screen-capture permissions are reset if the user denied them.
setupScreenSharingMain(jitsiMeetWindow, appName, osxBundleId);

In the renderer:

import { setupScreenSharingRender } from '@jitsi/electron-sdk/renderer';

// api             - the Jitsi Meet iframe api object.
// loggerTransports - optional array of @jitsi/logger transports.
setupScreenSharingRender(api, loggerTransports);

Picture in Picture

Enables the browser's native picture-in-picture for the active speaker video, so users can keep it in a floating window while using other applications.

Requirements:

  1. Jitsi Meet must be initialized through the iframe API.
  2. The main process executes the PiP request with userGesture privileges to bypass browser transient-activation restrictions.

In the main process:

const { setupPictureInPictureMain } = require('@jitsi/electron-sdk/main');

// jitsiMeetWindow  - the BrowserWindow where Jitsi Meet is loaded.
// loggerTransports - optional array of @jitsi/logger transports.
const pipMain = setupPictureInPictureMain(jitsiMeetWindow, loggerTransports);

In the renderer:

import { setupPictureInPictureRender } from '@jitsi/electron-sdk/renderer';

// api              - the JitsiMeetExternalAPI instance.
// loggerTransports - optional array of @jitsi/logger transports.
const pipRender = setupPictureInPictureRender(api, loggerTransports);

Power Monitor

Query Electron for system idle state and receive power-monitor events (suspend, resume, lock, unlock).

In the main process:

const { setupPowerMonitorMain, cleanupPowerMonitorMain } = require('@jitsi/electron-sdk/main');

// jitsiMeetWindow - the BrowserWindow where Jitsi Meet is loaded.
setupPowerMonitorMain(jitsiMeetWindow);

// On shutdown, tear down all power-monitor hooks:
// cleanupPowerMonitorMain();

In the renderer:

import { setupPowerMonitorRender } from '@jitsi/electron-sdk/renderer';

setupPowerMonitorRender(api);

Popups Configuration

Configures handling of popup windows for OAuth authentication flows (Google, Dropbox). It sets a setWindowOpenHandler on the Jitsi Meet window that allows OAuth popups and delegates all other window.open requests to a handler you provide.

In the main process:

const { shell } = require('electron');
const { initPopupsConfigurationMain } = require('@jitsi/electron-sdk/main');

// Called for window.open requests that are not OAuth popups.
const windowOpenHandler = ({ url }) => {
    shell.openExternal(url); // open external links in the default browser
    return { action: 'deny' };
};

// jitsiMeetWindow    - the BrowserWindow where Jitsi Meet is loaded.
// windowOpenHandler  - optional; if omitted, non-OAuth window.open requests are denied.
initPopupsConfigurationMain(jitsiMeetWindow, windowOpenHandler);

initPopupsConfigurationRender(api) is exported from the renderer entry for API compatibility but is a no-op.

Migrating from v9

v10 is a breaking release. The public API functions are the same; what changed is how you load them and how the window is configured.

  • The default entry is gone. require('@jitsi/electron-sdk') no longer resolves. Import from @jitsi/electron-sdk/main, @jitsi/electron-sdk/preload, or @jitsi/electron-sdk/renderer depending on where the code runs.
  • The Jitsi Meet window must use contextIsolation: true. Because robotjs left the renderer, that window can also run with sandbox: true.
  • Install the bridge from the preload. The app's (bundled) preload must call install() from @jitsi/electron-sdk/preload. Renderer code no longer receives ipcRenderer and must not assign the SDK helpers onto window itself.
  • Move setup*Render calls into the app's renderer bundle and call them directly with the JitsiMeetExternalAPI instance (instead of via a window.* object bridged from the preload). The signatures are unchanged.

Apps that must stay on contextIsolation: false can pin to @jitsi/electron-sdk@9.

Example

For a full integration example see the Jitsi Meet Electron project.

Development

Enable husky to avoid accidental pushes to the main branch:

npx husky install

To rebuild the native code (Windows), use:

npx node-gyp rebuild

Publishing

On every push to the master branch, .github/workflows/ci.yml creates a new patch version and publishes to npm. For a major or minor release, manually bump the version in package.json gh-action-bump-version workflow.