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

@panomapp/hsm

v1.0.1

Published

Universal hierarchical app state runtime for route, query, policy, backend, browser, and host-aware navigation.

Readme

@panomapp/hsm

Universal hierarchical app state runtime for route, query, policy, backend, browser, and host-aware navigation.

@panomapp/hsm lets you define a complex web app as a state tree instead of scattering routing, query-state, permissions, layout, async loaders, backend authorization, browser URL sync, and subdomain canonicalization across unrelated systems.

npm install @panomapp/hsm

Optional integrations:

npm install @panomapp/subdomain-policy
npm install vue

Why it exists

Traditional applications usually split the same decision across many layers:

  • router decides which screen matches a URL
  • stores hold local state
  • query parsing is hand-written per page
  • auth and permission checks are duplicated in frontend and backend
  • layouts are selected outside the route model
  • subdomain and canonical redirect rules live in separate config

@panomapp/hsm uses one hierarchical state model as the application contract. The same model can drive frontend navigation, backend request authorization, URL state projection, host-aware canonical navigation, and policy decisions.

Quick start

import { createHsm, query } from "@panomapp/hsm";

const hsm = createHsm({
  id: "app",
  context: {
    user: { username: "yusuf" },
    profile: { tab: "posts", page: 1, onlyMine: false }
  },
  query: {
    tab: query.string("posts", { source: "profile.tab" }),
    page: query.number(1, { source: "profile.page" }),
    mine: query.boolean(false, { source: "profile.onlyMine" })
  },
  guards: {
    "profile.isOwner": ({ context, params }) => context.user?.username === params.username
  },
  states: {
    landing: {
      path: "/",
      layout: "marketing"
    },
    app: {
      path: "/app",
      url: { hide: true },
      layout: "social",
      permissions: ["app.access"],
      states: {
        profile: {
          path: "/profile/:username",
          permissions: ["profile.view"],
          resolve: [
            { target: "owner", guard: "profile.isOwner" },
            { target: "viewer" }
          ],
          states: {
            owner: { permissions: ["profile.edit", "media.delete"] },
            viewer: { permissions: ["note.create"] }
          }
        }
      }
    }
  }
});

const snapshot = await hsm.resolveUrl("/profile/yusuf?tab=media&page=3&mine=true");

snapshot.stateId;             // "app.profile.owner"
snapshot.context.profile.tab; // "media"
snapshot.route?.pathname;     // "/profile/yusuf"
snapshot.policy?.layout;      // "social"

app is a semantic parent, but url.hide keeps it out of the public URL. The visible URL can be /profile/yusuf while the internal state remains app.profile.owner.

Core concepts

Hierarchical state tree

State IDs are semantic paths such as app.profile.owner or cloud.media.detail. Parent state configuration is inherited by children where appropriate.

states: {
  cloud: {
    path: "/cloud",
    layout: "cloud",
    permissions: ["cloud.view"],
    states: {
      media: {
        path: "/media",
        permissions: ["media.view"]
      }
    }
  }
}

URL-projected state

Query parameters can be bound to context. HSM owns serialization, decoding, defaults, validation, and URL generation.

query: {
  tab: query.string("posts", { source: "profile.tab" }),
  page: query.number(1, { source: "profile.page" }),
  tags: query.stringArray([], { source: "media.tags" })
}
hsm.href("app.profile", { username: "yusuf" }, {
  context: { profile: { tab: "media", page: 3 } }
});
// /profile/yusuf?tab=media&page=3

Default-equivalent values are pruned by default, so URLs remain clean.

Hidden and virtual routes

Semantic structure does not have to leak into public URLs.

states: {
  app: {
    path: "/app",
    url: { hide: true },
    states: {
      profile: { path: "/profile/:username" }
    }
  }
}
hsm.href("app.profile", { username: "yusuf" });
// /profile/yusuf

Use url.mode: "virtual" for grouping nodes that should not participate in route matching.

Transitions, lifecycle, loaders, and events

states: {
  profile: {
    path: "/profile/:username",
    beforeEnter: "auth.required",
    loader: "loadProfile",
    onEnter: "trackProfileView",
    onLeave: "cancelProfileRequests",
    on: {
      OPEN_SETTINGS: "app.settings"
    }
  }
}
const result = await hsm.transitionUrl("/profile/yusuf");

if (!result.ok) {
  console.error(result.reason, result.error);
}

Loaders receive an AbortSignal, so superseded navigations can cancel pending async work.

Policy engine

Permissions, capabilities, features, denials, and layouts are resolved from the active state path.

const canDelete = await hsm.can("media.delete");
const hasCamera = await hsm.canUse("camera.scan");
const music = await hsm.isFeatureEnabled("profile.music");
const layout = hsm.layout();

Rules can be declared globally:

policies: {
  permissions: {
    "media.delete": { guard: "media.isOwner" }
  },
  capabilities: {
    "camera.scan": { guard: "device.hasCamera" }
  },
  features: {
    "profile.music": { guard: "plan.isPro" }
  }
}

Debuggable explanations are available:

const decision = await hsm.explainPermission("media.delete");

Schema and backend runtime

HSM configs can be compiled into a function-free portable schema. The schema can be shared with backend code while guards/actions/loaders remain environment-specific registry entries.

import { compileSchema, defineHsm } from "@panomapp/hsm/schema";

const definition = defineHsm({
  id: "app",
  states: {
    app: {
      path: "/app",
      url: { hide: true },
      states: {
        profile: { path: "/profile/:username", permissions: ["profile.view"] }
      }
    }
  }
});

const schema = compileSchema(definition);

Backend usage:

import { createHsmBackend } from "@panomapp/hsm/backend";

const backend = createHsmBackend({
  schema,
  guards: {
    "auth.required": async ({ context }) => Boolean(context.user)
  },
  context: async ({ request }) => ({ user: request.user })
});

app.get("/api/profile/:username", backend.requirePermission("profile.view"), handler);

Frontend policy is UX. Backend policy enforcement is the security boundary.

Browser runtime

import { createHsmBrowserRuntime } from "@panomapp/hsm/browser";

const runtime = createHsmBrowserRuntime({
  hsm,
  window,
  autoCanonicalize: true
});

await runtime.start();
await runtime.navigate("app.profile", { username: "yusuf" });

The browser runtime integrates pushState, replaceState, popstate, query-state projection, canonical URLs, and redirect safety.

Subdomain policy integration

@panomapp/hsm integrates with @panomapp/subdomain-policy through the browser runtime.

import { createHostPolicyAdapter, createHsmBrowserRuntime } from "@panomapp/hsm/browser";

const hostPolicy = createHostPolicyAdapter({
  rootHostname: "example.com",
  rootRouteName: "landing.home",
  policies: [
    {
      subdomain: "app",
      rootRenderRoute: "app.feed",
      canonicalPathPrefix: "/app",
      requiresAuth: true,
      reachableDirectly: true,
      routeNames: ["app.feed", "app.profile"],
      landingStrategy: "root-for-landing",
      socketOriginStrategy: "root-origin"
    }
  ]
});

const runtime = createHsmBrowserRuntime({ hsm, window, hostPolicy });

Redirect safety rejects protocol-relative URLs, backslashes, encoded protocol-relative bypasses, unsupported protocols, and external origins outside the allowed host policy.

Vue adapter

import { createApp } from "vue";
import { createHsmVue } from "@panomapp/hsm/vue";

const app = createApp(App);
app.use(createHsmVue({ hsm }));
import { useHsm, useHsmState, useHsmPolicy } from "@panomapp/hsm/vue";

const hsm = useHsm();
const state = useHsmState();
const policy = useHsmPolicy();

await hsm.transition("app.profile", { params: { username: "yusuf" } });

state.stateId.value;        // app.profile.owner
policy.can("profile.edit");

Render by state ID:

<template>
  <MachineOutlet :components="screens" />
</template>

Devtools runtime

import { createHsmDevtools } from "@panomapp/hsm/devtools";

const devtools = createHsmDevtools(hsm, {
  logger: (event) => console.debug(event.type, event.payload)
});

await hsm.start();
await hsm.transitionUrl("/profile/yusuf");

devtools.events();
devtools.inspect();

The devtools runtime records transition starts, successes, failures, snapshots, and errors. It is framework-neutral and can be used in tests, internal debug panels, or browser integrations.

Exports

@panomapp/hsm
@panomapp/hsm/core
@panomapp/hsm/schema
@panomapp/hsm/backend
@panomapp/hsm/browser
@panomapp/hsm/runtime
@panomapp/hsm/vue
@panomapp/hsm/devtools

Security notes

  • Do not trust frontend-only policy checks for authorization.
  • Enforce sensitive permissions on the backend with createHsmBackend().
  • Keep portable schemas function-free; use named guards/actions/loaders and implement them per runtime.
  • Treat post-auth redirects as hostile input. Use RedirectSafety or browser runtime redirect helpers.
  • Prefer canonical URL generation over string concatenation.

License

MIT