Node.js engine · Apache 2.0 · @gozwire/core

Messaging you host. Truth you keep.

GozWire is an open-source messaging engine for Node.js. It gives your product durable conversations, messages, receipts, media, expiration, nested threads, reactions, configurable moderation, and optional Web Push, FCM, and APNs alerts. It does not lock you into Express, Svelte, or someone else's chat UI.

createGozWire
import { createGozWire, defaultConfig } from "@gozwire/core";

const gozwire = await createGozWire({ config: defaultConfig() });
await gozwire.start();

const conversation = await gozwire.conversations.createDirect({
  creatorId: "user-a",
  userIds: ["user-a", "user-b"],
});

await gozwire.messages.send({
  conversationId: conversation.id,
  senderId: "user-a",
  clientMessageId: crypto.randomUUID(),
  type: "text",
  body: "Hello",
});
PostgreSQL firstSend succeeds when the transaction commits.
One engine package@gozwire/core is the only required npm dependency.
Replaceable adaptersRealtime, object storage, moderation, metrics, and push.
Your product stays yoursAuth, discovery, ranking, and UI remain host concerns.

Why GozWire

An engine, not a chat product you have to white-label.

Most teams either rent a hosted chat API or rebuild receipts, retries, and media from scratch. GozWire sits in the middle: primitives you call from Node.js, with a local playground to see them work.

GozWire supplies

  • Identities, conversations, membership, and roles
  • Messages, receipts, attachments, and expiration
  • Nested threads and reactions
  • Idempotent send with clientMessageId
  • Outbox events after PostgreSQL commit
  • Configurable text and image moderation policy
  • Optional Web Push, FCM HTTP v1, and APNs HTTP/2
  • Profile-picture variants in object storage

Your application still owns

  • Account signup, SSO, and sessions
  • Workspace directories and channel browsers
  • Feeds, votes, ranking, and discovery
  • Product chrome and consumer UI
  • Choosing Express, another HTTP host, or none
  • Production object storage (R2, S3, or compatible)
  • Whether push is enabled (default is off)
  • Policy thresholds in engine config, not in a UI

Use cases

Four conversation types. One message model.

Direct, group, channel, and forum share membership, history, and moderation. What changes is how you present them. See the recipes.

Direct and group chats

createDirect is idempotent for a pair. Groups get an owner and members. Receipts are monotonic. Disappearing modes exist when conversation policy allows them.

direct
await gozwire.conversations.createDirect({
  creatorId: "ada",
  userIds: ["ada", "bob"],
});

Slack-style or Discord-style channels

createChannel is membership-based. Outsiders cannot send, list history, or subscribe. Channel directories stay in your app.

channel
await gozwire.conversations.createChannel({
  creatorId: "ada",
  title: "engineering",
  userIds: ["bob"],
});

Forum posts and nested threads

Forums load roots with history rootsOnly. Replies stay in one tree via threadRootId. Upvotes and ranking are not engine features.

forum
await gozwire.messages.history({
  conversationId: forum.id,
  actorId: "bob",
  rootsOnly: true,
});

How a send works

Commit first. Fan out later.

Realtime delivery is not the source of truth. If Centrifugo or a push provider is down, the message is still in PostgreSQL and workers retry.

Validate and authorize

Type, size, MIME, membership, and rate limits run before any write.

Write one transaction

Message, outbox row, and optional push intents commit together.

Return the row

messages.send returns after commit. Sockets are not required.

Publish and wake

Outbox and push workers retry independently. Clients still sync from Postgres.

Documentation

Guides that match the engine, not a sales deck.

Public docs for install, the API, realtime, push, storage, moderation, and operations.

FAQ

Straight answers for developers and search engines.

What is GozWire?

GozWire is an open-source Node.js messaging engine. Applications call @gozwire/core to persist conversations, messages, receipts, attachments, threads, reactions, and optional push. It is not a consumer chat app and it is not a hosted chat vendor.

What npm package do I install?

The engine is @gozwire/core. That is the only package required to use the engine. The Express and Svelte demo and the Python moderation sidecar live in the repository as applications, not as engine dependencies.

Is PostgreSQL required?

Yes. PostgreSQL is the durable source of truth. A successful messages.send is a committed PostgreSQL transaction. Centrifugo, sockets, and push-provider HTTP acceptance are not the definition of success.

Can I build Slack-style channels or Reddit-style forums?

Yes, as conversation types. createChannel and createForum use membership and the same message model. Channel directories, upvotes, ranking, and discovery stay in your application.

Does GozWire include user accounts?

No. Identities are referenced users, not a full account system. Signup, SSO, and sessions are host-application concerns. The local demo simulates identity with an x-user-id header.

Is push on by default?

No. push.enabled defaults to false. Direct adapters cover Web Push with VAPID, FCM HTTP v1, and APNs HTTP/2. Provider 2xx means the provider accepted the request, not that a device displayed a notification.

Get started

Read the engine guide, then run the playground if you want a UI.

The demo at localhost:3000 is a developer playground. It refuses to start when engine.environment is production. Ship with @gozwire/core and your own host.