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

@hypen-space/server

v0.4.980

Published

Hypen server runtime - Node.js WASM engine, component loader, discovery, and remote server

Downloads

510

Readme

@hypen-space/server

Server runtime for Hypen - Node.js/Bun WASM engine, component discovery, loader, and remote server for streaming UI over WebSocket.

Installation

npm install @hypen-space/core @hypen-space/server
# or
bun add @hypen-space/core @hypen-space/server

Quick Start

Most apps don't touch Engine directly — define modules on a HypenApp registry, then serve the whole app with RemoteServer:

import { HypenApp } from "@hypen-space/core";
import { RemoteServer } from "@hypen-space/server/remote";

const myApp = new HypenApp();

myApp.module("Counter")
  .defineState<{ count: number }>({ count: 0 })
  .onAction("increment", ({ state }) => { state.count += 1; })
  .onAction<{ amount: number }>("add", ({ action, state }) => {
    state.count += action.payload.amount;
  })
  .ui(`
    Column {
      Text("Count: @{state.count}")
      Button("@actions.increment") { Text("+") }
    }
  `)
  .build();

new RemoteServer().app(myApp).listen(3000);

State mutations are tracked via a Proxy — just assign fields; no reducers, no dispatchers. Every module defined on the HypenApp auto-registers under its name and is streamed over the same WebSocket.

Single-module demo? For a one-off counter with no routing or nesting, you can skip HypenApp and call .module(name, def).ui(template) directly on RemoteServer. Prefer HypenApp once you have more than one module or want the registry to drive routing/nesting.

Lifecycle & Session Hooks

const counter = app
  .defineState<{ count: number }>({ count: 0 })
  .onCreated(({ state }) => {
    console.log("counter created", state.count);
  })
  .onDestroyed(({ state }) => {
    console.log("counter destroyed", state.count);
  })
  .onDisconnect(({ state, session }) => {
    console.log(`session ${session.id} disconnected, count=${state.count}`);
  })
  .onReconnect(({ session, restore }) => {
    restore({ count: 42 });
  })
  .onExpire(({ session }) => {
    console.log(`session ${session.id} expired`);
  })
  .build();

Session hooks fire when a client drops, reconnects within the configured TTL, or lets the session expire. Configure TTL + concurrency policy via RemoteServer.session({ ttl, concurrent }).

Low-level engine

If you need direct engine access (custom transports, testing), import Engine from the package entry:

import { Engine } from "@hypen-space/server";

const engine = new Engine();
await engine.init();
engine.setRenderCallback((patches) => { /* ... */ });
engine.renderSource(`Column { Text("Hello") }`);

Component Discovery

Auto-discover .hypen components and their .ts modules from the filesystem:

import { discoverComponents, loadDiscoveredComponents, watchComponents } from "@hypen-space/server";

// Discover all components in a directory
const components = await discoverComponents("./src/components");
const loaded = await loadDiscoveredComponents(components);

// Watch for changes (hot reload)
const watcher = watchComponents("./src/components", {
  onUpdate: (c) => console.log("Updated:", c.name),
});

Supported file patterns:

Counter/
├── component.hypen    # Template
└── component.ts       # Module

Counter.hypen          # Sibling files
Counter.ts

Counter/
├── index.hypen        # Index-based
└── index.ts

Component Loader

Register and manage components programmatically:

import { ComponentLoader, componentLoader } from "@hypen-space/server";

// Global loader
componentLoader.register("Counter", counterModule, counterTemplate);
componentLoader.get("Counter");
componentLoader.has("Counter");

// Or create your own instance
const loader = new ComponentLoader();
await loader.loadFromComponentsDir("./src/components");

Remote Server

RemoteServer streams server-driven UI over WebSocket. The primary entry point is .app(hypenApp) — attach a HypenApp (one or many named modules), add session config, and call .listen(port):

import { HypenApp } from "@hypen-space/core";
import { RemoteServer } from "@hypen-space/server/remote";

const myApp = new HypenApp();

myApp.module("Counter")
  .defineState({ count: 0 })
  .onAction("increment", ({ state }) => state.count++)
  .ui(`Column { Text("Count: @{state.count}") Button("@actions.increment") { Text("+") } }`)
  .build();

const server = new RemoteServer()
  .app(myApp)
  .session({ ttl: 300, concurrent: "kick-old" })
  .onConnection((client) => console.log(`connected: ${client.id}`))
  .onDisconnection((client) => console.log(`disconnected: ${client.id}`))
  .listen(3000);

// server.stop();

Other entry points:

  • .module(name, def).ui(template) — single-module shortcut for demos (no HypenApp needed)
  • .source(dir) — auto-discover .hypen + .ts files under dir
  • .resources({ key: path }) — expose static resources over the same WebSocket
  • .syncActions() — turn on synchronous-action acknowledgements

Clients connect via RemoteEngine from @hypen-space/core:

import { RemoteEngine } from "@hypen-space/core";

const engine = new RemoteEngine("ws://localhost:3000/ws");
engine.connect();
engine.dispatchAction("increment");

Multi-Module Apps & Nested Modules

A single HypenApp can host many named modules. Each module owns its own state slice and handlers; they share a single engine instance and communicate through the global context. Bindings are namespaced: @{feed.items} / @actions.feed.refresh resolve from the parent template.

import { HypenApp } from "@hypen-space/core";

const myApp = new HypenApp();

myApp.module("Feed")
  .defineState({ items: [] as Item[] })
  .onAction("refresh", ({ state }) => { /* ... */ })
  .build();

myApp.module("Counter")
  .defineState({ count: 0 })
  .onAction("increment", ({ state }) => { state.count++; })
  .build();

new RemoteServer().app(myApp).listen(3000);

myApp.module("Name").defineState(...)...build() auto-registers under "Name"; access the definitions later via myApp.get("Counter") or myApp.components.

On the browser side, Hypen (from @hypen-space/web-engine) instantiates one HypenModuleInstance per registered module.

Bun Plugin

Import .hypen files directly in Bun:

import { registerHypenPlugin } from "@hypen-space/server";

registerHypenPlugin();

// Now you can import .hypen files
import template from "./Counter.hypen";

Exports

| Export | Description | |--------|-------------| | @hypen-space/server | Main - Engine, ComponentLoader, discoverComponents, RemoteServer | | @hypen-space/server/engine | Node.js WASM engine wrapper | | @hypen-space/server/loader | Component loader | | @hypen-space/server/discovery | Filesystem component discovery | | @hypen-space/server/plugin | Bun plugin for .hypen imports | | @hypen-space/server/remote | RemoteServer for WebSocket streaming |

Requirements

  • Node.js >= 18.0.0 or Bun 1.0+
  • @hypen-space/core peer dependency

License

MIT