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

@sigx/lynx-web-host

v0.28.0

Published

Host-page bridge for SignalX apps on web — clipboard/share/linking/picker handlers + appearance and URL publishers for @lynx-js/web-core

Readme

@sigx/lynx-web-host

Host-page bridge for SignalX apps running on web via upstream @lynx-js/web-core.

On web, a SignalX app's background code runs in a Web Worker where page-only browser APIs (navigator.clipboard, window.open, matchMedia, <input type=file>, vibration) don't exist. This package is the page side of that gap: it handles the worker's sigx.* RPC calls and publishes page-level state into the card.

sigx run:web wires it automatically — you only need this package directly when hosting a SignalX web bundle in your own page.

Usage

<lynx-view url="/app/main.web.bundle"></lynx-view>
<script type="module">
  import { installSigxWebHost } from '@sigx/lynx-web-host';
  installSigxWebHost(document.querySelector('lynx-view'));
</script>

dist/host.js (exported as @sigx/lynx-web-host/host) is a self-contained ESM file with zero imports, so it can also be served/loaded directly without a bundler — that's what sigx run:web does (/host/sigx-host.js).

Call it before the card loads where possible; web-core caches early bridge.calls until the handler is assigned, but globalProps should be seeded up front. Returns an uninstall function (removes the page listeners).

What it provides

| Surface | Backing | |---|---| | sigx.clipboard.* | navigator.clipboard (read denial → empty result) | | sigx.linking.openURL / canOpenURL | window.open + browser-openable scheme allowlist (http, https, mailto, tel, sms) | | sigx.share.* | navigator.share (capability-probed) | | sigx.picker.pick | hidden <input type=file> → blob URLs + metadata (+ image dimensions); cancel → [] | | sigx.haptics.vibrate | navigator.vibrate best-effort, never throws | | sigx.location.* | navigator.geolocation + Permissions API (denial maps to blocked; requestPermission prompts via a position request) | | sigx.notifications.* | local notifications via the Notification API (page-lifetime timers/repeats, permission mapping, Badging-API badges) | | Appearance publisher | globalProps.appearance = {colorScheme} from prefers-color-scheme, live appearanceChanged events — @sigx/lynx-appearance works unchanged, no web shim needed | | Inbound-link publisher | globalProps.initialURL + urlReceived on popstate/hashchange — consumed by @sigx/lynx-linking unchanged | | Text-color parity style | adopts x-text { color: inherit } into the <lynx-view> shadow root — upstream web-core defaults top-level text to color: initial (black), native inherits the ancestor color, so themed dark-mode text painted black on web only. Opt out: installSigxWebHost(view, { textColorInheritance: false }) | | Viewport browser-config | overrides web-core's SystemInfo.pixelWidth/pixelHeight with the <lynx-view>'s own box (see below). Opt out: installSigxWebHost(view, { viewport: false }) | | ignore-focus parity | a capture-phase mousedown on the shadow root preventDefaults taps on a non-focusable [ignore-focus] element, so a toolbar / suggestion-popup tap doesn't blur a focused editor (native honors ignore-focus; web-core doesn't). A focusable descendant (the editor lives inside the composer's ignore-focus row) is left alone so it can still focus. Opt out: installSigxWebHost(view, { ignoreFocus: false }) |

The worker side calls these through webHostCall() from @sigx/lynx-core (used by the per-package .web.ts shims). Protocol: sigx.<module>.<method>, JSON-cloneable payloads, responses {ok: true, value} | {ok: false, error}.

Publishers can be skipped via options: installSigxWebHost(view, { appearance: false, linking: false }).

Viewport dimensions (viewportBrowserConfig)

web-core derives SystemInfo.pixelWidth/pixelHeight from screen.availWidth/availHeight — the physical display. Everything downstream treats those as the screen the app occupies: @sigx/lynx-navigation slides cards in from SCREEN_WIDTH px away and rests sheets at a fraction of SCREEN_HEIGHT, @sigx/lynx-gestures' Swiper falls back to it for page width, and Platform.isPad derives from it. Inside a <lynx-view> smaller than the monitor, a sheet can settle below the visible area entirely.

browser-config overrides those fields, and installSigxWebHost sets it from the element's box when the host page hasn't. If you write your own host page, prefer setting the attribute inline while the document parses — that is strictly before the engine module upgrades <lynx-view> and reads the value, whereas a module script races the element's own render kickoff:

<lynx-view id="app" url="/app/main.web.bundle" style="height:100vh;width:100vw"></lynx-view>
<script>
  var v = document.getElementById('app');
  var r = window.devicePixelRatio || 1;
  v.setAttribute('browser-config', JSON.stringify({
    pixelRatio: r,
    pixelWidth: Math.round(window.innerWidth * r),
    pixelHeight: Math.round(window.innerHeight * r),
  }));
</script>

viewportBrowserConfig(view) computes the same object if you'd rather assign view.browserConfig yourself; it returns null when nothing is measurable. web-core freezes SystemInfo when the view is constructed, so resizes are not tracked.

Upstream coupling

Relies on web-core's NativeModules.bridge worker module and the <lynx-view> onNativeModulesCall / globalProps / updateGlobalProps / sendGlobalEvent surface (an existing handler is preserved — non-sigx.* calls fall through to it). Tested against the @lynx-js/web-core version range pinned by @sigx/lynx-cli.

Errors

A handler failure is replied as {ok: false, error} and re-thrown in the worker by @sigx/lynx-core's webHostCall, so the message is the only thing the app developer sees. Each one names its scope and the RPC method it came from:

[@sigx/lynx-web-host] linking.openURL failed: URL scheme "file:" cannot be opened in a browser

No SigxError, no createLogger — a documented CONVENTIONS.md C10 exemption. src/host.ts is deliberately import-free so the compiled dist/host.js loads in a host page with no bundler (sigx run:web serves it verbatim as /host/sigx-host.js); a bare @sigx/lynx-core specifier in that file would fail to resolve in the browser. The prefix is therefore written out literally at each throw, and the package emits no console.* diagnostics. Callers that need to branch on a failure should branch on the handler they called, not on the message text.

License

MIT