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

@wix/duplexer-js

v2.0.6

Published

browser & react-naitve client for Duplexer

Readme

@wix/duplexer-js

Establish a connection to wix-duplexer-sockets-server, subscribe and listen to channels & events from the browser.

Requirements

| Environment | Minimum version | | --- | --- | | Node.js | 18.0.0 | | Chrome | 42 | | Firefox | 39 | | Safari | 10.1 | | Edge | 14 |

The following Web APIs must be available at runtime:

  • fetch / Response
  • AbortController / AbortSignal (for request cancellation)

Testing in Node.js

Node 18+ includes a global fetch (based on undici). If your test framework intercepts HTTP with nock, ensure you are using nock v13+ which supports intercepting native fetch.

Features

Send events

Send event directly from the client (browser). Read more about sending client event.

Private channels

Allow authorized-only clients to subscribe specific channels. Read more about private channels.

Multiplexing

It means that N different clients can utilize/share same the physical socket while having a full isolation and, hence, improve general performance.

Environments

Install

npm install @wix/duplexer-js

Usage

import { Duplexer } from '@wix/duplexer-js';

const instanceUpdater = {
  getInstance() {
    return window.__APP_INSTANCE__;
  }
};

const siteRevision = '1';

const duplexer = new Duplexer('duplexer.wix.com', {
  instanceUpdater,
  siteRevision,
});

const connection = duplexer.connect({
  appDefId: '224b330b-f3dc-4898-8876-d177ab3877ca'
});

const channel = connection.subscribe('some-channel');

connection.on('@duplexer:connected', () => {
  // connection established
})

channel.on('some-event', payload => {
  // do something with your payload
});

Note: in case you use jsdom, you must specify its url with http:// protocol in order to make Duplexer testkit to work properly (exposed websocket & http server are not under SSL).

require('jsdom-global)('', { url: 'http://localhost:7000' });

Note: in case you run Duplexer in a Node.js environment (e.g. testing with Jest/Mocha), you need:

  1. Node.js 18+ (provides global fetch, AbortController).
  2. A WebSocket implementation on the global object. You can install ws:
global.WebSocket = require('ws');

API

new Duplexer(opts): Duplexer

Create a new Duplexer instance that will open socket against url. It must be provided with duplexer.wix.com as the url, as it communicates with the sockets server directly (opens a connection, send commands etc.).

Parameters:

  • opts (Object):
    • url (String) - url to wix-duplexer-sockets-server service, must be protocol-less.
    • siteRevision (String) - the site's revision number.
    • instanceUpdater (InstanceUpdater) - an object that exposes getInstance: () => string member that is responsible of retrieving Wix's instance.
    • autoConnect (Boolean, default: true) - whether to enable auto reconnect when a sudden disconnection accurs. Used for testing purposes.

Duplexer.connect(opts): VirtualSocket

Establish a connection according to given opts.appDefId.

Parameters:

  • opts
    • appDefId (String)

Duplexer.getConnectionServerTime(): Promise

Retrieves the server time that the connection was established with. Promise is getting resolved upon successful connect.

Note: it refers to the physical connection establishment (connection_establish packet).

Duplexer.triggerInstanceChanged(): void

In case the signed instance is no longer valid (say, expired) and connection closed with status 401, you should make the instance updater to return a new valid signed instance. After you do that, you can call triggerInstanceChanged(), so Duplexer will try to reconnect (... and resubscribe).

VirtualSocket.disconnect(): void

Closes namespace (might close the entire underlying connection or not, depends if pool contains more namespaces or not).

VirtualSocket.subscribe(channel, opts): Channel

Subscribe to channel and start getting emitted events.

Note: current limitation is up to 10 different subscriptions (channels) per api key.

Parameters:

  • channel (String)
  • opts (Object) (Optional)
    • restoreStrategy (Object) - custom restore strategy taht will be attached to the subscribe command, see RestoreStrategyBuilderFactory for more information about possible restore strategies.
    • resourceId - if you have a specific channel for each resource, like scores/1 and scores/2.

VirtualSocket.subscribeToUserChannel(): Channel

Subscribe to user's dedicated channel. This channel acts like his own inbox, so nobody else can listen to.

In order to publish to user channel (backend perspective), the USER context should be used along with the recipients field (that represents the user IDs that should receive the message).

VirtualSocket.unsubscribe(channel): void

Unsubscribe channel, stop getting emitted events.

Parameters:

  • channel (String)

VirtualSocket.on(event, handler)

Listen to event and execute handler on every event that emitted on this connection.

Parameters:

  • event (String)
  • handler (Function: payload? => void)

Reserved events

| Event | Description | | -------------------------- | ----------- | | @duplexer:connected | Emitted on connection successfully established | | @duplexer:disconnected | Emitted on connection closed, either intentionally or caused by error. If connection was closed due to error, a TransportError instance will be passed. In case TransportError contains { recoverable: false }, you will have to conneect manually (you should check the status and act accordingly; for instance, in case it's 401 - the provided signed instance is invalid) | | @duplexer:connect_error | Emitted on every connect try error, a TransportError instance will be passed. In case error is unrecoverable, @duplexer:connect_error won't be thrown, but @duplexer:diconnected with TransportError that contains { recoverable: false } |

Note: all above events might be called multiple times, for instance:

connected -> disconnected (with error) -> connect_erorr -> connect_erorr -> connected

This happens because duplexer client tries to recover itself in case of unexpected disconnection.

VirtualSocket.off(event, handler?)

Remove handler from being executed on event. In case no handler passed, all handlers will be removed.

Parameters:

  • event (String)
  • handler (Optional) (Function)

Channel.on(event, handler): Channel

Listen to event and execute handler on every event that emitted on this channel.

Parameters:

  • event (String)
  • handler (Function: (payload?, attachments?) => void) - handler that will be executed every time an event received:
    • payload (any)
    • attachments (Object)
      • user (Object) - user informartion that was attached to event (from signed subscription token).
channel.on('client-typing', (_, {user}) => {
  // ${user.info.name} is typing!
})

Reserved events

| Event | Description | | -------------------------------- | ----------- | | @duplexer:subscription_succeeded | Subscription established successfully and from now on messages will be delivered. Note: will be called on every resubscribe (in case of reconnect for instance), so make sure your handler is idempotent.Payload is an object that contains:- isSynced (Boolean) - determines if app server should resync (possibly) missed messages. Will always return false at the beginning, and app server might needs to fetch its recent messages in this phase. | | @duplexer:subscription_failed | Emitted on authorization failure - in case request returns status other than 2xx.Payload is an object that contains:- status (Boolean) - status code the request returned with.- message (String) - detailed message about the error | | @duplexer:unsubscribe_succeeded | Unsubscribed successfully from channel and messages will stop being delivered. |

Channel.off(event, handler?)

Remove handler from being executed on event. In case no handler passed, all handlers will be removed.

Parameters:

  • event (String)
  • handler (Optional) (Function)

Channel.send(event, payload): void

Send a client event. User is implicitly attached.

Parameters:

  • event (String)
  • payload (Object)

RestoreStrategyBuilderFactory

Possible restore strategies, see wix-duplexer-protocol#RestoreStrategyBuilderFactory