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

@vustudio/fabric

v0.5.0

Published

TypeScript SDK for Vū Protocol — the real-time communication fabric that connects Vū Intelligence, the Recommendation Engine, and the physical systems they coordinate. Built on MQTT.

Readme

@vustudio/fabric

The TypeScript SDK for Vū Protocol — the real-time communication fabric that connects Vū Intelligence, the Recommendation Engine, and the physical systems they coordinate.

Vū Fabric gives every room, display, light, camera, microphone, sensor, media asset, service, application, and AI agent a shared way to communicate. Each participant can publish state, receive commands, emit events, expose presence, and react to the environment in real time.

At the platform level, Fabric is the nervous system of the Vū Intelligence Stack. The Recommendation Engine senses context and surfaces what the next moment may need. Vū Intelligence routes that context through specialized AI agents. Fabric connects those decisions to the real world — displays, lights, audio, sensors, media players, control systems, and applications.

Built on MQTT, an industry-standard publish/subscribe protocol used across IoT, industrial automation, and complex real-time orchestration environments, Fabric brings proven Industry 4.0 communication patterns into media, entertainment, enterprise experience, and Physical AI.

Where most real-time systems hand developers raw messages and leave the conventions to them, Fabric ships with the conventions built in: a typed unified namespace, automatic delivery semantics, optional schema validation, and one consistent wire format across apps, services, devices, and agents.

MQTT moves the messages. Vū Protocol defines what they mean. Fabric makes the protocol easy to use.

Fabric is designed for Vū deployments and is compatible with MQTT 3.1.1 or 5.0 brokers supported by mqtt.js.

🧭 Why MQTT

Vū deployments are not simple one-application-to-one-device systems.

They are live environments where displays, lighting, audio, cameras, microphones, control surfaces, media players, sensors, cloud services, and AI agents all need to publish state, receive commands, emit events, and react to each other in real time.

MQTT is well suited to this model because it uses a lightweight publish/subscribe architecture, supports many producers and consumers, and is already standardized and widely deployed in connected-device and industrial automation environments.

Vū brings that same pattern into media and entertainment.

Instead of brittle point-to-point integrations, every entity in a Vū deployment participates in a shared namespace:

vu/{site}/{entity}/{id}/{class}/{name}

This is the foundation of Vū Protocol: every room, sensor, display, lighting fixture, media asset, service, and AI agent becomes addressable through the same real-time fabric.

✨ Highlights

Industry-standard foundation

Built on MQTT, Fabric gives Vū projects a proven real-time transport layer without locking the platform into a proprietary message bus.

Vū-native unified namespace

Fabric turns MQTT topics into a Vū-specific communication contract. Rooms, walls, devices, sensors, media assets, services, and AI agents all communicate through the same structured namespace.

Delivery semantics by message class

The first segment of every sub-path determines how the message behaves.

| Class | QoS | Retained | Use for | | ---------------- | --- | -------- | ------------------------- | | state/... | 1 | yes | Last-known values | | cmd/... | 1 | no | Imperative actions | | event/... | 1 | no | Ephemeral occurrences | | dt/... | 0 | no | High-frequency telemetry | | telemetry/... | 0 | no | High-frequency telemetry | | presence/... | 1 | yes | Online / offline state | | config/... | 1 | yes | Capability / version info |

Application code does not need to remember MQTT options for each message type. The protocol contract applies them automatically.

Typed payload contracts

Optional Zod schemas provide typed .send() calls and typed .on() handlers.

Invalid outgoing payloads are rejected before publish. Invalid incoming payloads are logged and skipped before they reach application code.

Built for real-time orchestration

Fabric handles lazy connection, reconnect behavior, auth failure handling, wildcard subscription pacing, JSON parsing, retained-message clearing, and status events.

One protocol across Vū systems

The same topic contract can be used by browser apps, Node services, device adapters, control systems, and future runtime ports. Every system speaks the same wire format.

🧰 Technology Stack

| Layer | Technologies | | ------------ | ------------------------------------------------------------------------------------------------------------- | | Protocol | MQTT 3.1.1 / 5.0 via mqtt.js | | Vū Protocol | Unified namespace, class contracts, delivery semantics, and typed topic structure for Vū deployments | | Runtime | Node.js 18+ / Bun / Browser / Deno | | Language | TypeScript 5 | | Validation | Zod 3 peer dependency, optional per topic | | Build | tsup 8 | | Test | Vitest 2, EMQX service container | | Tooling | Biome, Changesets, pnpm, tsx |

🏗️ Architecture

@vustudio/fabric is the TypeScript implementation surface for Vū Protocol.

Vū Protocol is the communication fabric that makes every entity in a Vū deployment addressable: rooms, displays, lighting fixtures, sensors, microphones, media assets, AI agents, services, and control surfaces.

Fabric provides the developer API for that protocol. It maps Vū's unified namespace into typed topic handles, applies the correct delivery semantics for each message class, validates payloads when schemas are provided, and manages the MQTT connection lifecycle underneath.

The result is a real-time system where applications do not need to know about each other directly. They only need to publish and subscribe to the shared Vū namespace.

graph TD
  subgraph Apps["Vū applications, devices, and agents"]
    R["React / Vue / Svelte apps"]
    N["Node services"]
    W["Cloudflare Workers / edge runtimes (planned)"]
    E["ESP32 / device adapters (planned)"]
    A["AI agents"]
    P["Python sensors (planned)"]
  end

  subgraph Fabric["@vustudio/fabric"]
    L2["Planned Entity Layer<br/>Shadow · Room · Presence · Method"]
    L1["Layer 1 — Unified Namespace<br/>vu/{site}/{entity}/{id}/{class}/{name}"]
  end

  Broker(("MQTT Broker"))

  R --> L2
  L2 --> L1
  N --> L1
  W --> L1
  E --> L1
  A --> L1
  P --> L1
  L1 <--> Broker

The SDK is built on two layers.

Layer 1 is the protocol address: the shared wire format used across runtimes.

Layer 2 is an optional higher-level entity model for richer abstractions such as Shadow, Room, Presence, and Method. These entities resolve back to Layer 1 topics underneath.

Use Layer 1 when you need direct protocol control. Use Layer 2 when you want a higher-level developer experience.

📁 Project Structure

src/
├── index.ts           Public API surface
├── client.ts          MQTT connection lifecycle
├── topic.ts           Topic handle: .on / .send / .off / .close
├── classes.ts         Message class to QoS / retain contract
├── topic-match.ts     MQTT wildcard matcher
├── config.ts          Environment-based config loader
└── __tests__/         Unit tests

examples/
├── smoke.ts           Publish / subscribe round trip
├── retained.ts        Retained delivery example
└── clear-retained.ts  Retained cleanup example

docs/
├── getting-started.md
├── concepts.md
├── api.md
├── recipes.md
├── troubleshooting.md
└── faq.md

🧠 Core Concepts

Vū Protocol

The communication fabric and unified namespace that defines what messages mean inside a Vū deployment.

Fabric

The TypeScript SDK that implements Vū Protocol for JavaScript and TypeScript applications.

Topic

A scoped pub/sub surface for one entity, such as a room, wall, kiosk, light, camera, service, or agent.

const wall = fabric.topic("playlist/wall-1738");

Sub-path

The path beneath a topic.

state/queue
cmd/play
event/clipFinished
dt/fps
presence/status

The first segment is the message class.

Class

The message class determines delivery behavior.

For example, state/... is retained, event/... is ephemeral, and telemetry/... is optimized for high-frequency updates.

Schema

An optional Zod schema keyed by sub-path.

Schemas validate outgoing payloads before publish and incoming payloads before handler execution.

🚀 Quick Start

1. Install

pnpm add @vustudio/fabric mqtt zod

mqtt and zod are peer dependencies.

2. Configure

# .env
VU_MQTT_BROKER=wss://your-broker.example.com/mqtt
VU_MQTT_USERNAME=
VU_MQTT_PASSWORD=

Or pass config explicitly:

import { createFabric } from "@vustudio/fabric";

const fabric = createFabric({
  broker: process.env.VU_MQTT_BROKER!,
  username: process.env.VU_MQTT_USERNAME,
  password: process.env.VU_MQTT_PASSWORD,
});

3. Speak Vū Protocol

import { fabric } from "@vustudio/fabric";

const wall = fabric.topic("playlist/wall-1738");

await wall.on("state/queue", (queue) => {
  console.log("queue:", queue);
});

await wall.send("cmd/play", { clipId: 42 });

await wall.send("state/queue", [
  { id: 1, title: "Hero" },
]);

The SDK connects on first use, parses JSON payloads, and applies the correct delivery semantics for each message class.

4. Add types with Zod

import { z } from "zod";
import { fabric } from "@vustudio/fabric";

const wall = fabric.topic("playlist/wall-1738", {
  schema: {
    "state/queue": z.array(
      z.object({
        id: z.number(),
        title: z.string(),
      }),
    ),
    "cmd/play": z.object({
      clipId: z.number(),
    }),
  },
});

await wall.send("cmd/play", { clipId: 42 });

// Type error
await wall.send("cmd/play", { wrong: "thing" });

🎯 Scope a namespace once

Real deployments address things through a long, structured prefix — tenant, use case, entity, id. Repeating that prefix by hand invites drift: the same path gets re-typed slightly differently in three places, and now messages miss each other.

scope() fixes the prefix once and derives every topic, send, and subscribe from it. For the Experience namespace specifically, fabric.experience() builds that prefix for you:

import { fabric } from "@vustudio/fabric";

// Open your experience's scope. tenant defaults to "default" — a reserved
// single-tenant slot (mirrors Kubernetes' own `default` namespace). Pass a
// real tenant only once this experience needs multi-tenant isolation; it's
// a rename + a new ACL grant then, not a re-architecture.
const exp = fabric.experience("responsible-ai-simulation");
// → vu/default/experience/responsible-ai-simulation

// Nest for a specific entity — joins and trims slashes for you.
const session = exp.scope("session", sessionId);
// → vu/default/experience/responsible-ai-simulation/session/4f2a

// send / on / clear are relative to the scope. Sub-paths are class/name only.
await session.send("state/snapshot", snapshot);      // QoS 1 + retained, from the class
await session.on("event/rubric-hit", (hit, fullTopic) => { /* ... */ });
await session.clear("state/snapshot");               // remove the retained slot

Attach Zod schemas at topic() — one scope spans many class/name pairs:

const session = exp.scope("session", sessionId).topic({
  schema: {
    "state/snapshot": snapshotSchema,
    "event/rubric-hit": rubricHitSchema,
  },
});

await session.send("state/snapshot", snapshot); // typed and validated

For anything outside the Experience namespace, fabric.scope(base) still takes any prefix directly.

The scope prefix is also the isolation boundary: each use case is ACL-scoped to its own vu/{tenant}/experience/{usecase}/# subtree on the broker. One prefix, one home — see the recipe.

Connection safety

send() waits for the broker and rejects if it cannot connect within connectTimeoutMs (default 10s) — it never hangs. When you would rather not handle a rejection, use trySend(), which resolves false if the client is not connected:

if (!fabric.isConnected()) {
  // show an offline indicator, queue locally, etc.
}

const sent = await session.trySend("cmd/play", { clipId: 42 });
if (!sent) {
  // not connected — decide what to do (retry, drop, buffer)
}

trySend() never throws — if the payload fails class or schema validation, the error is routed to your onError hook and trySend() resolves false.

Sharing one connection with client injection

Some consumers already need a raw mqtt.js client of their own — e.g. one physical connection carrying both Fabric's class-contract JSON topics and a consumer's own binary (non-JSON) topics, with a single Last-Will. Pass that client to createFabric({ client }) instead of letting Fabric open its own socket:

import mqtt from "mqtt";
import { createFabric } from "@vustudio/fabric";

const mqttClient = mqtt.connect("wss://mqtt.vu.studio/mqtt", {
  username: "...",
  password: "...",
  will: { topic: "presence/voice-bridge", payload: "offline", qos: 1, retain: true },
});

// Fabric attaches its schema/class-contract layer on top of your socket. It
// never calls connect()/end() on it — you created it, you own its lifecycle.
const fab = createFabric({ client: mqttClient });

const room = fab.topic("room/1");
await room.send("state/snapshot", snapshot); // Fabric's class contract, same socket

// Your own binary topics ride the same connection, fully outside Fabric:
mqttClient.publish("room/1/audio/opus", opusFrame, { qos: 0 });

Rules:

  • broker is optional when client is provided.
  • username, password, and will are meaningless once a client already exists — passing any of them together with client throws at construction. Set them on your own mqtt.connect() call instead.
  • fab.close() on an injected client only detaches Fabric's listeners — it never calls .end(). You created the socket, you close it.
  • Reconnect and resubscription behavior follow your mqtt.js options (mqtt.js defaults resubscribe: true, so Fabric's on() subscriptions survive a reconnect by default — but resubscribe: false or clean: false are yours to own).
  • fab.getMqttClient() (and FabricClient.getMqttClient()) returns the underlying client — the one you injected, or the SDK-created one once a connect/publish/subscribe has triggered it.

For an SDK-created connection (no client injected), set a Last-Will via createFabric({ broker, will }) — it's passed straight through to mqtt.connect()'s IClientOptions.

🧪 Local Development

1. Install

git clone [email protected]:vustudio/vu-fabric.git
cd vu-fabric
pnpm install
cp .env.example .env

2. Run checks

pnpm check

This runs linting, typecheck, tests, and build.

| Task | Command | | :---------- | :--------------- | | Lint | pnpm lint | | Typecheck | pnpm typecheck | | Test | pnpm test | | Build | pnpm build | | Watch build | pnpm dev | | Smoke test | pnpm smoke |

3. Run a local broker

docker compose up -d

Point your local environment at the broker:

VU_MQTT_BROKER=ws://localhost:8083/mqtt
VU_MQTT_USERNAME=
VU_MQTT_PASSWORD=

Run the smoke test:

pnpm smoke

Local EMQX dashboard: http://localhost:18083

📦 Publishing

Releases are managed with Changesets.

1. Add a changeset

pnpm changeset

Choose patch, minor, or major, write a short summary, and commit the generated file with your PR.

2. Release

The release workflow consumes pending changesets, updates package versions, writes the changelog, builds the package, and publishes to npm.

Authors should not manually edit package versions unless repairing the release process.

📚 Documentation

🗺️ Roadmap

The current package delivers the core topic contract, namespace scoping (scope()), and connection-safe publishing (trySend() / isConnected()).

Planned areas include:

  • presence helpers for Last Will and Testament, birth, and death messages
  • React bindings for topic subscriptions and cleanup
  • CLI tools for watching, snapshotting, and auditing topics
  • wildcard publish protection
  • Cloudflare Worker support
  • framework adapters for Vue and Svelte
  • ESP32 and Python packages that follow the same topic shape
  • higher-level entities such as Shadow, Room, and Method
  • developer tools for inspecting traffic, retained snapshots, and presence state

The roadmap may change as Vū Protocol and the deployment model mature.

🚦 Status

This package is pre-1.0.

The topic contract is intended to be stable, but API changes may still occur before the first major release. For production deployments, pin versions and review release notes before upgrading.


Fabric is the SDK. Vū Protocol is the language. MQTT is the transport.