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/router

v0.7.0

Published

Router for SignalX with SSR support and hooks

Downloads

2,054

Readme

@sigx/router

Type-safe router for SignalX — SSR support, reactive hooks, and a plugin architecture.

npm license ci types

🚧 SignalX is in early public release (0.7.x). The API surface is small and stabilising — feedback is very welcome.

@sigx/router is the official router for SignalX apps. It brings path-based and named routes, nested layouts, navigation guards, reactive hooks (useRoute, useRouter, …), scroll restoration, and Web/Hash/Memory history modes — installed as a plugin with a single app.use(router). Memory history makes the same routes render on the server, so SSR works out of the box.

📚 Documentation

Full guides, API reference and live examples → https://sigx.dev/router/

Install

npm install @sigx/router sigx

@sigx/router requires sigx 0.7.x as a peer dependency, along with the core packages @sigx/reactivity, @sigx/runtime-core, and @sigx/runtime-dom (>=0.7.0 <0.8.0), so your app controls a single copy of the reactivity engine. With a package manager that auto-installs peers — npm 7+, or pnpm with auto-install-peers enabled (the default since pnpm 8) — the command above is all you need. If your setup does not auto-install peers, add the core packages explicitly:

npm install @sigx/router sigx @sigx/reactivity @sigx/runtime-core @sigx/runtime-dom

Quick start

/** @jsxImportSource sigx */
import { component, defineApp } from 'sigx';
import { createRouter, createWebHistory, RouterView, Link } from '@sigx/router';

const Home = component(() => () => <h1>Home</h1>);
const About = component(() => () => <h1>About</h1>);

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'home', component: Home },
    { path: '/about', name: 'about', component: About },
  ],
});

const App = component(() => () => (
  <div>
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
    </nav>
    <RouterView />
  </div>
));

const app = defineApp(<App />);
app.use(router);
app.mount('#app');

Navigation guards

Guards run for every route resolution — including the very first one on a direct load / refresh (client) or the initialLocation on the server. The initial guard run is kicked off by app.use(router); router.isReady() resolves once it has completed.

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/login', name: 'login', component: Login },
    { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } },
  ],
});

router.beforeEach((to, from) => {
  // from is null on the initial navigation
  if (to.meta.requiresAuth && !isAuthenticated()) return '/login';
});

A guard redirect on the initial navigation uses replace semantics, so the Back button cannot return to the guarded URL. Returning false on the initial navigation keeps the initially matched route (there is no previous route to stay on) — redirect instead to protect content on direct loads.

Guards and dependency injection

When the router is installed into an app (defineApp(...).use(router)), guards and afterEach hooks run inside that app's DI context (via app.runWithContext, requires @sigx/runtime-core >= 0.6.1). A defineFactory / defineInjectable use-function called from a guard resolves the same app-scoped instance that components receive:

const useAuthStore = defineFactory(() => createAuthStore(), 'scoped');

router.beforeEach((to) => {
  // Same store instance the app's components see
  const auth = useAuthStore();
  if (to.meta.requiresAuth && !auth.isAuthenticated) return '/login';
});

Async guards: the app context covers only the synchronous portion of a guard — it does not survive an await. Each guard is wrapped individually, so resolve your dependencies at the top of the guard, before the first await:

router.beforeEach(async (to) => {
  const auth = useAuthStore();        // ✅ before the first await — in context
  await auth.refreshSession();
  const other = useOtherStore();      // ❌ after an await — realm fallback
});

If you must resolve a dependency after an await, capture the app and re-enter the context explicitly: app.runWithContext(() => useOtherStore()).

When the router is used standalone (no app installed), guards are invoked directly and DI resolutions fall back to the realm-level instances.

On the server, await router.isReady() before rendering and observe an initial-load redirect via currentRoute.redirectedFrom to emit a real HTTP redirect:

const history = createMemoryHistory({ initialLocation: req.url });
const router = createRouter({ history, routes });
router.beforeEach(authGuard);
app.use(router);

await router.isReady();
if (router.currentRoute.redirectedFrom) {
  // the guard redirected the requested URL — don't render, redirect
  res.redirect(302, router.currentRoute.fullPath);
} else {
  res.send(render(app));
}

See the full documentation for history modes, guards, hooks, pattern matching, scroll restoration, SSR, and the complete API reference.

Part of SignalX

License

MIT © Andreas Ekdahl