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

reflected

v0.2.7

Published

A primitive to allow workers to call synchronously any functionality exposed on the main thread.

Downloads

107

Readme

reflected

Social Media Photo by Marc-Olivier Jodoin on Unsplash

A primitive to allow workers to call synchronously any functionality exposed on the main thread, without blocking it.

Strategies

This module uses 3 synchronous strategies + 1 asynchronous fallback:

  • message based on SharedArrayBuffer and MessageChannel, the fastest and most reliable "channel strategy" that requires headers to enable Cross Origin Isolation on the page.
  • broadcast also based on SharedArrayBuffer but with BroadcastChannel instead to satisfy a long standing Firefox bug. This also requires headers to enable Cross Origin Isolation on the page.
  • xhr based on synchronous XMLHttpRequest and a dedicated ServiceWorker able to intercept such POST requests, broadcast to all listening channels the request and resolve as response for the worker.
  • async which will always return a Promise and will not need special headers or ServiceWorker. This is also a fallback for the xhr case if the serviceWorker option field has not been provided.

All strategies are automatically detected through the default/main import but all dedicated strategies can be retrieved directly, for example:

  • import reflect from 'reflected' will decide automatically which strategy should be used.
  • import reflect from 'reflected/message' will return the right message based module on the main thread and the worker mode within the worker.
  • import reflect from 'reflected/main/message' will return the message strategy for the main thread only. This requires the least amount of bandwidth when you are sure that message strategy will work on main.
  • import reflect from 'reflected/worker/message' will return the message strategy for the worker thread only. This requires the least amount of bandwidth when you are sure that message strategy will work within the worker.

Swap message with broadcast, xhr or async, and all exports will work equally well according to the chosen "channel strategy".

| Import | Use case | |--------|----------| | reflected | Auto-pick strategy (main + worker) | | reflected/message | broadcast | xhr | async | Specific strategy, context-aware | | reflected/main/<strategy> | Main thread only (smaller bundle) | | reflected/worker/<strategy> | Worker only (smaller bundle) |

Requirements: Synchronous strategies except for xhr need Cross-Origin Isolation (e.g. Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp). The async strategy works without those headers and always returns a Promise.

Worker Thread API

// file: worker.js (always loaded as module)
import reflect from 'https://esm.run/reflected';

// ℹ️ must await the initialization
const reflected = await reflect({
  // receives the returned data from the main thread.
  // use this helper to transform such data into something
  // that the worker can use/understand after invoke
  // ⚠️ must be synchronous and it's invoked synchronously
  onsync(response:unknown) {
    return response;
  },

  // receives the data from the main thread when
  // `worker.send(payload, ...rest)` is invoked.
  // use this helper to transform the main thread request
  // into something compatible with structuredClone algorithm
  // ℹ️ works even if synchronous but it's resolved asynchronously
  async onsend(payload) {
    const data = await fetch('./data.json').then(r => r.json());
    return process(payload, data);
  },
});

// retrieve the result of `test_sum(1, 2, 3)`
// directly from the main thread.
// only the async channel variant would need to await
const value = reflected({
  invoke: 'test_sum',
  args: [1, 2, 3]
});

console.log(value); // 6

Main Thread API

// file: index.js as module
import reflect from 'https://esm.run/reflected';

function test_sum(...args:number[]) {
  let i = 0;
  while (args.length)
    i += args.pop();
  return i;
}

// ℹ️ must await the initialization
const worker = await reflect(
  // Worker scriptURL
  './worker.js',
  // Worker options + required utilities / helpers
  // ℹ️ type is enforced to be 'module' due to top-level await
  {
    // invoked when the worker asks to synchronize a call
    // ℹ️ works even if synchronous but it's resolved asynchronously
    // ⚠️ the worker is not responsive until this returns so
    //     be sure you handle errors gracefully to still provide
    //     a result the worker can consume out of the shared buffer!
    async onsync(payload:unknown) {
      const { invoke, args } = payload;

      if (invoke === 'test_sum') {
        // just demoing this can be async too
        return await test_sum(...args);
      }

      // it is trivial to return no result or even errors
      return new Error('unknown ' + invoke);
    },

    // *optional* helper to process data returned from the worker when
    // the main thread `await worker.send(payload, ...rest)` operation
    // is invoked. If not present, whatever payload the worker returned
    // will be directly returned as invoke result, just like in here.
    // ℹ️ works even if synchronous but it's resolved asynchronously
    onsend(payload:unknown) {
       return payload;
    },

    // optional: the initial SharedArrayBuffer length
    initByteLength: 1024,

    // optional: the max possible SharedArrayBuffer growth
    maxByteLength: 8192,

    // optional: the service worker as fallback
    //   * if it's a string, it's used to register it
    //   * if it's an object, it's used to initialize it
    //     but it must contain a `url` field to register it
    // ℹ️ if already registered it will not try to register it
    serviceWorker: undefined,
  }
);

const value = await worker.send({ any: 'payload' });

Test live or read the main thread and worker thread code.

Latest ffi should allow workers to drive the main thread without even needing SharedArrayBuffer but of course, if SharedArrayBuffer is available, these will be much faster.

reflected/ffi

This module also exports a bare-minimum way to directly drive, whenever the channel is not async, the main thread from a worker.

// main.js module
import reflect from 'https://esm.run/reflected/ffi/main';

// returns a worker with a special `ffi` field/namespace
// directly from reflected-ffi project
const worker = await reflect('./worker.js', { serviceWorker: './sw.js' });


// worker.js module
import reflect from 'https://esm.run/reflected/ffi/worker';

// retrieve the reflected-ffi namespace as it is
const ffi = await worker();

// will directly append a text node to the main thread body
ffi.global.document.body.append('it worked 🥳');

To know more about reflected-ffi module and features, please visit the related project.

Extras

  • Named export channel: After initialization, import reflect, { channel } from 'reflected' gives the active strategy name ('message', 'broadcast', 'xhr', or 'async').
  • Errors: From main-thread onsync, return new Int32Array(0) (or a convention of your choice) so the worker always gets a result; handle that in the worker’s onsync to avoid hanging.
  • Types: you can import MainOptions and WorkerOptions from the root of the porject because main reflect(string, MainOptions) and worker reflect(WorkerOptions) are different in a subtle way you probably don't want to mess around with (in particular, the onsync which must be sync on the worker side of affairs or it cannnot work)