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

@memberjunction/ai-bridge-zoom

v5.48.0

Published

MemberJunction: Zoom Realtime Bridge driver — the first real platform bridge. Connects the realtime agent engine to a Zoom meeting (audio in/out, diarized roster, participant mute, in-meeting chat) via an injectable Zoom Meeting SDK seam, and contributes

Readme

@memberjunction/ai-bridge-zoom

The Zoom Realtime Bridge driver — the first real platform bridge in MemberJunction's Realtime Bridges program. It connects the one realtime agent engine to a Zoom meeting: bidirectional audio, a diarized participant roster, participant mute, in-meeting chat, and a Meeting Controls facilitator channel — all behind an injectable Zoom Meeting SDK seam so the driver builds and unit-tests with no network and no real Zoom SDK.

See the Realtime Bridges Guide and /plans/realtime/realtime-bridges-architecture.md (§3 provider abstraction, §4b channels, §8 Zoom capability row) for the full architecture.

Install

npm install @memberjunction/ai-bridge-zoom

What it provides

  • ZoomBridge@RegisterClass(BaseRealtimeBridge, 'ZoomBridge'). The MJ: AI Bridge Providers row with DriverClass = 'ZoomBridge' resolves to this driver via the ClassFactory. Implements the four BaseRealtimeBridge abstracts (Connect / Disconnect / SendMedia / OnMedia) and the capability-gated virtuals Zoom supports (GetParticipants, OnParticipantChange), plus GetMeetingControlsEventSource for the facilitator channel and a PostChatMessage helper.
  • IZoomMeetingSdk — the injectable seam the driver depends on instead of the real SDK.
  • ZoomMeetingControlsEventSource — adapts the seam's roster / hand-raise / speaking / mute into the bridge's IBridgeMeetingControlsEventSource, so the engine wires the Meeting Controls channel.

Capability coverage (the Zoom seed row)

| Capability | Status | |---|---| | On-demand + scheduled join | ✅ | | Audio in / out | ✅ | | Video in/out, Screen in/out (directional flags) | ✅ (transport carries them; models light audio first) | | Speaker diarization (roster + per-speaker labels) | ✅ | | Participant mute (Meeting Controls) | ✅ | | In-meeting chat | ✅ | | DTMF / call transfer / recording | ➖ not Zoom-meeting features — the gated base methods throw BridgeCapabilityNotSupportedError |

Capability gating is two-layer (defense-in-depth): the engine checks the provider's SupportedFeatures first, and the driver re-asserts each flag with RequireFeature at the top of its overrides.

The Zoom Meeting SDK seam (IZoomMeetingSdk)

The driver never imports the real Zoom SDK. It depends only on this minimal interface:

export interface IZoomMeetingSdk {
    join(args: ZoomJoinArgs): Promise<ZoomJoinResult>;
    leave(): Promise<void>;
    sendAudioFrame(pcm: ArrayBuffer): void;                                 // agent's voice out (virtual mic)
    onAudioFrame(cb: (frame: ZoomAudioFrame) => void): void;                // raw per-participant audio in (diarization)
    onParticipantJoin(cb: (p: ZoomParticipant) => void): void;
    onParticipantLeave(cb: (id: string) => void): void;
    onHandRaise(cb: (id: string, raised: boolean) => void): void;
    getParticipants(): Promise<ZoomParticipant[]>;
    postChatMessage(text: string): Promise<void>;
    muteParticipant(participantId: string): Promise<void>;
    onMeetingEnded(cb: () => void): void;
}

Real Zoom binding — ZoomRtmsMeetingSdk (RTMS)

This package now ships a real IZoomMeetingSdk binding: ZoomRtmsMeetingSdk, built over Zoom's Realtime Media Streams (RTMS) Node SDK (@zoom/rtms). It gives the agent hearing in a live Zoom meeting — RTMS streams per-participant inbound audio to your server over a webhook-initiated WebSocket, and the adapter maps each frame to the bridge's diarized { Pcm, ParticipantId } path.

import { ZoomBridge, BindZoomRtms } from '@memberjunction/ai-bridge-zoom';

// Once, where bridge drivers are configured. Creds + RTMS connection params resolve from the
// session Configuration the engine passes at Connect (see below) — no secrets inline.
bridge.SetSdkFactory(BindZoomRtms());

BindZoomRtms() returns the SetSdkFactory-shaped factory that constructs a ZoomRtmsMeetingSdk from the engine's per-session Configuration. The driver and its tests do not change.

🔴 Outbound-audio limitation (read this)

RTMS is RECEIVE-ONLY. It delivers inbound per-participant audio/transcripts but cannot send the agent's synthesized audio back into the meeting. So a real RTMS binding gives the agent hearing (diarized inbound audio) but not a voice in the meeting.

In ZoomRtmsMeetingSdk the outbound/host-control surfaces are therefore documented, one-time-warned no-ops (they never throw, so a live session is not killed when the model emits audio):

| Surface | RTMS behavior | |---|---| | sendAudioFrame (agent's voice out) | no-op + one-time warning — RTMS has no send path | | postChatMessage | no-op — chat is a Meeting-SDK/host control, not RTMS | | muteParticipant | no-op — host mute is a Meeting-SDK control | | onHandRaise | no-op — RTMS surfaces no hand-raise signal |

For full two-way audio (the agent speaking into Zoom), this package now ships the second binding: ZoomNativeMeetingSdk (zoom-native-sdk.ts) — a real, two-way IZoomMeetingSdk adapter whose sendAudioFrame forwards to the native virtual-mic send path and whose host controls (chat/mute) actually act. Activate it with bridge.SetSdkFactory(BindZoomNative()) (or just let the engine auto-bind it — it is the registered default for DriverClass = 'ZoomBridge'; pass StartBridgeSessionParams.BindSdk with BindZoomRtms() to choose the receive-only RTMS binding instead).

ZoomNativeMeetingSdk is the MJ-side adapter, fully unit-tested against a fake native module. It still requires a real backing media client at deployment — one of:

  • the native Zoom Meeting SDK (a C++/Linux server-bot build with the raw-data send+receive entitlement), wrapped as a N-API addon or sidecar exposing the adapter's NativeMeetingModule surface and pointed at via ZoomNativeSdkConfig.NativeModuleSpecifier; or
  • a third-party meeting-bot service that injects audio on your behalf, behind the same module surface.

Both satisfy the same NativeMeetingModule contract, so the ZoomNativeMeetingSdk adapter and its tests are unchanged. See plans/realtime/native-bridge-buildout-plan.md §3 for the build steps.

All three bindings (ZoomRtmsMeetingSdk receive-only, ZoomNativeMeetingSdk two-way, and a test FakeZoomSdk) implement the same IZoomMeetingSdk seam, so the ZoomBridge driver and its tests are unchanged regardless of which is bound.

Webhook + credential configuration a deployment provides

RTMS is webhook-initiated. A deployment must:

  1. Create a Zoom app with the RTMS scopes/entitlement enabled (per-participant audio).

  2. Subscribe to the RTMS webhooksmeeting.rtms_started and meeting.rtms_stopped (a.k.a. rtms.stopped). Zoom signs every webhook; verify the signature before processing.

  3. Wire a webhook endpoint that, on meeting.rtms_started, hands the connection params the payload carries into the bridge session's Configuration under a Connection block:

    // session Configuration the engine passes to ZoomBridge.Connect → BindZoomRtms factory:
    {
      "ClientId":     "<resolved upstream from the MJ credential system — NEVER inline>",
      "ClientSecret": "<resolved upstream — NEVER inline>",
      "Connection": {                         // straight from the meeting.rtms_started webhook payload
        "meeting_uuid":   "payload.object.meeting_uuid",
        "rtms_stream_id": "payload.object.rtms_stream_id",
        "server_urls":    "payload.object.server_urls",
        "signature":      "<optional: HMAC-SHA256(client_secret, client_id + meeting_uuid + rtms_stream_id)>"
      }
    }
  4. On meeting.rtms_stopped, end the corresponding bridge session.

Credentials (ClientId / ClientSecret) resolve upstream via the MJ credential system / the provider Configuration — they are never inlined at a call site. If the Connection block is absent or malformed, ZoomRtmsMeetingSdk.join() throws a precise "RTMS is webhook-initiated — wire the meeting.rtms_started webhook" error.

Optionality

@zoom/rtms is an optionalDependency (a native addon requiring Node ≥ 22). The adapter loads it lazily behind the seam, so this package builds and unit-tests without @zoom/rtms installed. When absent at runtime, join() throws an actionable "install @zoom/rtms" error. Tests inject a fake module — no network, no native addon.

⚠️ The exact @zoom/rtms API surface is pinned from the SDK README + quickstart and marked with // VERIFY against @zoom/rtms notes in zoom-rtms-sdk.ts (callback arity, metadata field names, join() payload, leave/session-update semantics). A live test against a real Zoom app should confirm these before relying on them in production.

The old default

Out of the box, ZoomBridge's default factory still throws an explicit "bind the real Zoom SDK" error until SetSdkFactory is called — so an unconfigured deployment fails loudly. Call SetSdkFactory(BindZoomRtms()) to activate real RTMS; tests inject a FakeZoomSdk.

Usage (engine-driven)

The bridge is not used directly — AIBridgeEngine.StartBridgeSession (@memberjunction/ai-bridge-server) resolves it from the provider's DriverClass, wires the transport seam to the injected IRealtimeSession, and (when a channel host is supplied) wires the Meeting Controls channel from GetMeetingControlsEventSource. See the bridge-server package and the guide's "Channel plane" section.

Testing

FakeZoomSdk (in src/__tests__/) is an in-memory IZoomMeetingSdk with drive helpers and capture sinks. The driver suite covers connect/disconnect, audio in→OnMedia (speaker labels) and out→seam, participant join/leave → roster + event source, native hand-raise → Meeting Controls perception, capability gating (a feature Zoom lacks throws), and chat — all with no network.

A second suite (zoom-rtms-sdk.test.ts) covers the real RTMS adapter against a fake @zoom/rtms module (no native addon, no network): the pure RTMS-frame→{ Pcm, ParticipantId } mapping (both documented callback arities + numeric/string ids), readRtmsConfig extraction, the join/hearing path and participant discovery, the meeting-ended signals, the receive-only no-op guards, the BindZoomRtms factory, and the actionable error when @zoom/rtms is absent.

cd packages/AI/RealtimeBridge/Providers/Zoom && npm run test