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

@grest-ts/asyncapi

v0.0.50

Published

AsyncAPI 3.0 spec generation for grest-ts WebSocket APIs

Readme

Part of the grest-ts framework. Documentation | All packages

@grest-ts/asyncapi

Optional package — generates AsyncAPI 3.0 specs from your grest-ts WebSocket schemas and serves AsyncAPI Studio (the standard interactive viewer).

Features

  • toAsyncApi() — pure function, no side effects; safe in CI/build scripts for static spec export
  • GGAsyncApiDocs — serves GET /asyncapi.json and GET /asyncapi-docs (AsyncAPI Studio); schemas auto-collected from the server
  • All four message patterns covered — request/response, fire-and-forget, server push, and server-initiated request/response
  • Bearer / API-key handshake auth — middleware headers with format: "bearer" or format: "api-key" become AsyncAPI securitySchemes automatically
  • Named schemas — every .docs({title}) schema is extracted to components/schemas and reused via $ref across messages
  • Symmetric error reporting — every errors:[…] entry becomes its own typed reply message so the spec lists every possible response shape
  • Same .docs() passthrough as @grest-ts/openapi — title, description, example, examples, deprecated all flow into the spec

Installation

npm install @grest-ts/asyncapi

The package depends on @grest-ts/openapi for the schema converter, so you do not need to install both manually if you only want AsyncAPI — npm install @grest-ts/asyncapi brings everything.

Usage

Serve docs alongside your WebSocket APIs

GGAsyncApiDocs.register() mirrors the MyApi.register() pattern — pass http explicitly, or omit it to use the default GGHttpServer from the locator.

import {GGAsyncApiDocs} from "@grest-ts/asyncapi";
import {GGHttpServer} from "@grest-ts/http";
import {ChatApi, NotificationApi} from "@myapp/api";

const server = new GGHttpServer();
ChatApi.register(chatHandler);
NotificationApi.register(notificationHandler);

GGAsyncApiDocs.register({
    http: server,                   // optional — falls back to locator default
    title: "My WebSocket APIs",
    version: "1.0.0",
    description: "Chat and notification events",
    specPath: "/asyncapi.json",
    docsPath: "/asyncapi-docs"
});
// GET /asyncapi.json   → AsyncAPI 3.0 spec
// GET /asyncapi-docs   → AsyncAPI Studio (sidebar deep links via /asyncapi-docs/* are also handled)

Explicit schema list

When you want to document schemas that are not registered on this server (e.g. a docs-only build, or sharing a common bundle), pass them in directly:

GGAsyncApiDocs.register({
    http: server,
    schemas: [ChatApiSchema, NotificationApiSchema],
    title: "WebSocket Showcase",
    specPath: "/asyncapi.json",
    docsPath: "/asyncapi-docs",
    eager: true   // build spec at construction time (default: lazy on first request)
});

Export spec to a file (CI/scripts)

import {toAsyncApi} from "@grest-ts/asyncapi";
import {writeFileSync} from "fs";

const spec = toAsyncApi([ChatApiSchema, NotificationApiSchema], {
    title: "My WebSocket APIs",
    version: "2.0.0",
    servers: {
        production: {host: "api.example.com", protocol: "wss"}
    }
});
writeFileSync("asyncapi.json", JSON.stringify(spec, null, 2));

Multi-spec switcher (registerGroups)

When one service exposes WebSocket APIs that consumers want to browse separately, register them as named groups. The studio is rendered with a small custom dropdown above it; switching the dropdown re-renders the studio with the chosen spec.

GGAsyncApiDocs.registerGroups({
    groups: {
        "Chat":          [ChatApiSchema],
        "Notifications": [NotificationApiSchema],
    },
    title: "MyOrg Events",
    specPathPrefix: "/asyncapi",
    docsPath: "/asyncapi-docs",
    primary: "Chat",
})

Group names get kebab-cased into URL slugs. Because the AsyncAPI react-component does not have a native multi-spec switcher, the dropdown is rendered inside the page template (no public API around it).

For mixed HTTP + WebSocket setups, see @grest-ts/api-docs — it builds a unified shell that handles both protocols in one page.

Message patterns

@grest-ts/websocket contracts can describe four interaction patterns; toAsyncApi() emits each one with the right action / reply shape:

| Contract shape | AsyncAPI emission | |---|---| | clientToServer with success and/or errors | action: send + reply listing success and each error message | | clientToServer with no success and no errors | action: send (fire-and-forget; no reply block) | | serverToClient with input only | action: receive (server push; no reply block) | | serverToClient with success/errors | action: receive + reply (server-initiated request/response) |

Every message gets a stable id (<ChannelName>_<methodName>[_request|_response|_error_<TYPE>]) so spec consumers can deep-link to a particular interaction.

Auth

When a WebSocket schema uses a middleware whose header schema declares .docs({format: "bearer"}) (or "api-key"), the converter:

  1. Adds the corresponding entry to components.securitySchemes (using the header's .docs({title}) if you provided one — defaults to BearerAuth / ApiKeyAuth).
  2. Attaches a security requirement to every operation on that channel.
import {IsBearerToken} from "@grest-ts/schema";

export const ChatAuth = {
    headers: {
        "authorization": IsBearerToken.docs({description: "JWT access token for the chat channel"})
    }
};

export const ChatApiSchema = webSocketSchema(ChatContract)
    .path("ws/chat")
    .use(ChatAuth)
    .done();

Plain (non-security) handshake headers are emitted under the channel's bindings.ws.headers schema instead.

Schema → JSON Schema mapping

The schema converter is shared with @grest-ts/openapi — the same .docs({title, description, example, examples, deprecated}) annotations and .default(value) values flow into both specs. See the @grest-ts/openapi mapping table for the full list.

A handful of post-processing steps adapt the output to AsyncAPI 3.0 conventions: discriminator: {propertyName: "x"} collapses to the plain string "x", and additionalProperties: false is stripped from message payloads since it adds noise without value in documentation.