nats

NATS client for Kit using native Zig FFI

Files

FileDescription
.editorconfigEditor formatting configuration
.gitignoreGit ignore rules for build artifacts and dependencies
.tool-versionsasdf tool versions (Zig, Kit)
LICENSEMIT license file
README.mdThis file
docs/api.mdAPI reference notes
examples/basic.kitBasic connection, ping, publish, subscribe, and flush example
examples/pubsub.kitPublish/subscribe example
examples/queue-groups.kitQueue group worker and producer example
examples/request-reply.kitRequest/reply responder and requester example
kit.tomlPackage manifest with metadata, capabilities, and tasks
src/nats.kitPublic Kit API and typed error definitions
tests/nats.test.kitTests for exported error types and module import behavior
zig/kit_ffi.zigKit FFI helper definitions used by the Zig implementation
zig/nats.zigNative Zig implementation of the NATS protocol client

Dependencies

No Kit package dependencies.

This package requires Kit capabilities for FFI and networking:

[capabilities]
requires = ["ffi", "net"]

Live examples require a NATS server listening on localhost:4222.

brew install nats-server
nats-server

Installation

kit add gitlab.com/kit-lang/packages/kit-nats.git

Usage

import Kit.Nats as NATS

print-error = fn(prefix: String, e: NatsError) =>
  match e
    | NatsConnectionError {message} -> println "${prefix}: ${message}"
    | NatsCommandError {message} -> println "${prefix}: ${message}"

main = fn() =>
  match NATS.connect "localhost" 4222
    | Ok conn ->
        defer NATS.close conn

        match NATS.ping conn
          | Ok response -> println "Ping: ${response}"
          | Err e -> print-error "Ping failed" e

        match NATS.publish conn "greet.joe" "Hello Joe!"
          | Ok _ -> println "Published message"
          | Err e -> print-error "Publish failed" e

        match NATS.subscribe conn "greet.*"
          | Ok sid ->
              println "Subscribed with sid: ${Int.to-string sid}"
              NATS.unsubscribe conn sid
          | Err e -> print-error "Subscribe failed" e

        NATS.flush conn

    | Err e ->
        print-error "Connection failed" e

main

Request/Reply

import Kit.Nats as NATS

match NATS.connect "localhost" 4222
  | Ok conn ->
      defer NATS.close conn

      match NATS.request conn "echo" "Hello NATS!" 5000
        | Ok response -> println "Received response: ${response}"
        | Err e -> println "Request failed: ${NatsError.show e}"

  | Err e -> println "Connection failed: ${NatsError.show e}"

Queue Groups

import Kit.Nats as NATS

match NATS.connect "localhost" 4222
  | Ok conn ->
      defer NATS.close conn

      match NATS.subscribe-queue conn "jobs" "workers"
        | Ok sid ->
            println "Worker subscribed with sid: ${Int.to-string sid}"
            match NATS.next-msg conn
              | Ok msg -> println "Job payload: ${msg.payload}"
              | Err e -> println "Receive failed: ${NatsError.show e}"
        | Err e -> println "Subscribe failed: ${NatsError.show e}"

  | Err e -> println "Connection failed: ${NatsError.show e}"

API Overview

FunctionDescription
NATS.connect host portConnect to a NATS server by host and port
NATS.connect-url urlConnect using a nats://host:port style URL
NATS.close connClose a connection and release native resources
NATS.ping connSend PING and wait for PONG
NATS.flush connEnsure previously sent commands have reached the server
NATS.publish conn subject payloadPublish a payload to a subject
NATS.publish-reply conn subject reply-to payloadPublish with an explicit reply subject
NATS.subscribe conn subjectSubscribe to a subject or wildcard subject
NATS.subscribe-queue conn subject queueSubscribe as part of a queue group
NATS.unsubscribe conn sidUnsubscribe by subscription id
NATS.unsubscribe-after conn sid max-msgsAuto-unsubscribe after max-msgs messages
NATS.next-msg connBlock until the next subscribed message is received
NATS.request conn subject payload timeoutSend a request and wait for a reply

All operations return Result values using NatsError:

export type NatsError =
  | NatsConnectionError {message: String}
  | NatsCommandError {message: String}

Connections are native resources. Use defer NATS.close conn immediately after a successful connection.

Architecture

Pub/Sub Pattern

sequenceDiagram participant Publisher participant NATS Server participant Subscriber1 participant Subscriber2 Subscriber1->>NATS Server: Subscribe "events.*" Subscriber2->>NATS Server: Subscribe "events.*" Publisher->>NATS Server: Publish "events.user" NATS Server->>Subscriber1: Message NATS Server->>Subscriber2: Message

Request/Reply Pattern

sequenceDiagram participant Requester participant NATS Server participant Responder Responder->>NATS Server: Subscribe "service.api" Requester->>NATS Server: Request "service.api" NATS Server->>Responder: Message + Reply Subject Responder->>NATS Server: Publish to Reply Subject NATS Server->>Requester: Response

FFI Structure

graph TD A[Kit Code] -->|import Kit.Nats| B[src/nats.kit] B -->|extern-zig| C[zig/nats.zig] C --> D[zig/kit_ffi.zig] C --> E[NATS Protocol] E --> F[NATS Server]

Development

Running Examples

Run the basic example with the interpreter:

kit run examples/basic.kit

Compile the basic example to a native binary:

kit build examples/basic.kit -o basic && ./basic

Run the pub/sub example:

kit run examples/pubsub.kit

The examples import ../src/nats.kit so they exercise the local working tree during package development.

Running Tests

Run the test suite:

kit test

Run the test suite with coverage:

kit test --coverage

Running kit dev

Run the standard development workflow (format, check, and test):

kit dev

This will:

  1. Format and check source files
  2. Type check examples
  3. Run tests in tests/ with coverage

Running Parity

Run interpreter/compiler parity checks for all examples:

kit parity --no-spinner --failures-only

Parity builds and runs each example through both execution paths, then compares outputs. A local NATS server is optional for examples/basic.kit, but recommended for exercising the successful connection paths in the other examples.

Generating Documentation

Generate API documentation from doc comments:

kit doc

Note: Kit sources with doc comments (##) will generate HTML documents in docs/*.html.

Cleaning Build Artifacts

Remove generated files, caches, coverage data, parity results, and build artifacts:

kit task clean

Note: Defined in kit.toml.

Local Installation

To install this package locally for development:

kit install

This installs the package to ~/.kit/packages/@kit/nats/, making it available for import as Kit.Nats in other projects.

Implementation Notes

  • zig/nats.zig implements the NATS text protocol directly over TCP sockets.
  • @defer-required("NATS.close") on connection functions helps Kit warn when a connection is not closed in scope.
  • connect-url supports nats://host:port, user:pass@host:port, and bare host:port forms.
  • TLS URLs (tls://) are rejected because TLS transport is not implemented yet.
  • next-msg blocks until a message arrives on any subscription for the connection.
  • request creates an inbox subscription, publishes with reply-to, waits for one response, and resets the receive timeout.

License

This package is released under the MIT License - see LICENSE for details.

Exported Functions & Types

NatsError

NATS error type for typed error handling. Variants distinguish between connection and command errors.

Variants

NatsConnectionError {message}
NatsCommandError {message}