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

@tanqory/app-bridge

v0.7.1

Published

Typed postMessage bridge between the Tanqory dashboard (host) and an embedded app rendered in an iframe (guest). Handles origin validation, request/response correlation, token handoff, and route mirroring.

Readme

@tanqory/app-bridge

Typed postMessage bridge between the Tanqory dashboard (host — owns the iframe and the session) and an embedded app (guest — served from its own origin).

Both halves validate event.origin against an explicit allow-list and post with an explicit target origin. Never '*'.

Why a code, not a token, in the iframe URL

The host mints a 30-second single-use authorization code (POST /auth/issue-code with an audience) and puts that in the iframe URL. The guest exchanges it once for an access token plus a refresh cookie scoped to its own origin, then strips ?code= from its URL.

An access token in a URL persists in browser history, Referer headers, and nginx access logs for its full lifetime. A code is dead in 30 seconds and after one use.

The exchange also leaves the guest self-sufficient: it can refresh off its own cookie, and it can be opened directly in a tab for debugging. A guest handed a raw token has neither.

Host

import { createBridgeHost, jwtExpiresAtMs } from '@tanqory/app-bridge'

const host = createBridgeHost({
  getIframe: () => iframeRef.current,
  allowedOrigins: [EMAIL_APP_ORIGIN, /^https:\/\/dev-email\.tanqory\.com$/],
  handlers: {
    onInit: () => ({ storeId, storeName, permissions, locale, currency, apiBaseUrl, ... }),
    onTokenRequest: () => {
      const token = getAccessToken()
      return { token, expiresAt: jwtExpiresAtMs(token) ?? Date.now() + 60_000 }
    },
    onRouteChanged: ({ path }) => window.history.replaceState({}, '', `${base}${path}`),
    onFullscreen: ({ enabled }) => setFullscreen(enabled),
    onMediaPicker: (options, respond) => openPicker(options, respond),
    onAuthExpired: () => recoverAuth(),
  },
})

useEffect(() => host.start(), [host])
host.post('THEME_CHANGED', { theme })

The host is the token authority. It holds the in-memory access token and rotates it off the httpOnly refresh cookie, so the guest pulls a fresh token per use rather than reusing whatever it got at boot. Derive expiresAt from the JWT's own exp — a hardcoded lifetime means the guest keeps using a token past its real expiry and every call 401s.

Guest

import { createBridgeGuest } from '@tanqory/app-bridge'

const guest = createBridgeGuest({ allowedOrigins: [DASHBOARD_ORIGIN] })
const stop = guest.start()

const ctx = await guest.init() // storeId, permissions, locale, apiBaseUrl, …
guest.ready() // host drops its skeleton

const { token } = await guest.requestToken()
guest.post('ROUTE_CHANGED', { path: '/builder' })
guest.on('THEME_CHANGED', ({ theme }) => setTheme(theme))

guest.isEmbedded is false when the app is opened in a top-level tab; every method degrades cleanly so one build serves both.

apiBaseUrl must come from INIT. A store lives in one commerce cell, and the guest is served from a single central origin — it cannot derive the cell from its own hostname the way the dashboard does.

A guest must never navigate itself to a login page. That renders login inside a box. On auth failure: ask the host for a token, fall back to its own refresh cookie, then report AUTH_EXPIRED and let the host decide.

Embedding permission

An embeddable app must not send X-Frame-Options — it has no allow-list form, so SAMEORIGIN vetoes the CSP in any browser that still reads it. Pass frameAncestors to @tanqory/next-config for local dev; in production the ingress sets the header and strips the upstream one.

Messages

| Message | Direction | Purpose | | ---------------------------------- | ------------ | --------------------------------------------- | | READY | guest → host | Guest mounted; host drops the skeleton | | INIT / INIT_RESPONSE | ↔ | Store, user, locale, currency, apiBaseUrl | | TOKEN_REQUEST / TOKEN_RESPONSE | ↔ | Live access token + absolute expiry | | AUTH_EXPIRED | guest → host | Guest exhausted every token route | | ROUTE_CHANGED | guest → host | Host mirrors it into the address bar | | POPSTATE | host → guest | Browser back/forward moved the host URL | | NAVIGATE | guest → host | Leave the embedded app entirely | | RESIZE | guest → host | Content height changed | | FULLSCREEN | guest → host | Host portals the iframe to <body> | | TOAST | guest → host | Rendered by the host so it isn't clipped | | MEDIA_PICKER / _RESPONSE | ↔ | Host's picker; resolves when the user is done | | UNSAVED_CHANGES | guest → host | Arms the host's navigation guard | | THEME_CHANGED / LOCALE_CHANGED | host → guest | Keep the guest in sync |