@debros/network-ts-sdk - TypeScript SDK for DeBros Network

A modern, isomorphic TypeScript SDK for the DeBros Network gateway. Works seamlessly in both Node.js and browser environments with support for database operations, pub/sub messaging, and network management.

Features

  • Isomorphic: Works in Node.js and browsers (uses fetch and isomorphic-ws)
  • Database ORM-like API: QueryBuilder, Repository pattern, transactions
  • Pub/Sub Messaging: WebSocket subscriptions with automatic reconnection
  • Authentication: API key and JWT support with automatic token management
  • TypeScript First: Full type safety and IntelliSense
  • Error Handling: Unified SDKError with HTTP status and code

Installation

npm install @debros/network-ts-sdk

Quick Start

Initialize the Client

import { createClient } from "@debros/network-ts-sdk";

const client = createClient({
  baseURL: "http://localhost:6001",
  apiKey: "ak_your_api_key:namespace",
});

// Or with JWT
const client = createClient({
  baseURL: "http://localhost:6001",
  jwt: "your_jwt_token",
});

Database Operations

Create a Table

await client.db.createTable(
  "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"
);

Insert Data

const result = await client.db.exec(
  "INSERT INTO users (name, email) VALUES (?, ?)",
  ["Alice", "alice@example.com"]
);
console.log(result.last_insert_id);

Query Data

const users = await client.db.query("SELECT * FROM users WHERE email = ?", [
  "alice@example.com",
]);

Using QueryBuilder

const activeUsers = await client.db
  .createQueryBuilder("users")
  .where("active = ?", [1])
  .orderBy("name DESC")
  .limit(10)
  .getMany();

const firstUser = await client.db
  .createQueryBuilder("users")
  .where("id = ?", [1])
  .getOne();

Using Repository Pattern

interface User {
  id?: number;
  name: string;
  email: string;
}

const repo = client.db.repository<User>("users");

// Find
const users = await repo.find({ active: 1 });
const user = await repo.findOne({ email: "alice@example.com" });

// Save (INSERT or UPDATE)
const newUser: User = { name: "Bob", email: "bob@example.com" };
await repo.save(newUser);

// Remove
await repo.remove(newUser);

Transactions

const results = await client.db.transaction([
  {
    kind: "exec",
    sql: "INSERT INTO users (name, email) VALUES (?, ?)",
    args: ["Charlie", "charlie@example.com"],
  },
  {
    kind: "query",
    sql: "SELECT COUNT(*) as count FROM users",
    args: [],
  },
]);

Pub/Sub Messaging

The SDK provides a robust pub/sub client with:

  • Multi-subscriber support: Multiple connections can subscribe to the same topic
  • Namespace isolation: Topics are scoped to your authenticated namespace
  • Server timestamps: Messages preserve server-side timestamps
  • Binary-safe: Supports both string and binary (Uint8Array) payloads
  • Strict envelope validation: Type-safe message parsing with error handling

Publish a Message

// Publish a string message
await client.pubsub.publish("notifications", "Hello, Network!");

// Publish binary data
const binaryData = new Uint8Array([1, 2, 3, 4]);
await client.pubsub.publish("binary-topic", binaryData);

Subscribe to Topics

const subscription = await client.pubsub.subscribe("notifications", {
  onMessage: (msg) => {
    console.log("Topic:", msg.topic);
    console.log("Data:", msg.data);
    console.log("Server timestamp:", new Date(msg.timestamp));
  },
  onError: (err) => {
    console.error("Subscription error:", err);
  },
  onClose: () => {
    console.log("Subscription closed");
  },
});

// Later, close the subscription
subscription.close();

Message Interface:

interface Message {
  data: string; // Decoded message payload (string)
  topic: string; // Topic name
  timestamp: number; // Server timestamp in milliseconds
}

Debug Raw Envelopes

For debugging, you can inspect raw message envelopes before decoding:

const subscription = await client.pubsub.subscribe("notifications", {
  onMessage: (msg) => {
    console.log("Decoded message:", msg.data);
  },
  onRaw: (envelope) => {
    console.log("Raw envelope:", envelope);
    // { data: "base64...", timestamp: 1234567890, topic: "notifications" }
  },
});

Multi-Subscriber Support

Multiple subscriptions to the same topic are supported. Each receives its own copy of messages:

// First subscriber
const sub1 = await client.pubsub.subscribe("events", {
  onMessage: (msg) => console.log("Sub1:", msg.data),
});

// Second subscriber (both receive messages)
const sub2 = await client.pubsub.subscribe("events", {
  onMessage: (msg) => console.log("Sub2:", msg.data),
});

// Unsubscribe independently
sub1.close(); // sub2 still active
sub2.close(); // fully unsubscribed

List Topics

const topics = await client.pubsub.topics();
console.log("Active topics:", topics);

Authentication

Switch API Key

client.auth.setApiKey("ak_new_key:namespace");

Switch JWT

client.auth.setJwt("new_jwt_token");

Get Current Token

const token = client.auth.getToken(); // Returns API key or JWT

Get Authentication Info

const info = await client.auth.whoami();
console.log(info.authenticated, info.namespace);

Logout

await client.auth.logout();

Network Operations

Check Health

const healthy = await client.network.health();

Get Network Status

const status = await client.network.status();
console.log(status.healthy, status.peers);

List Peers

const peers = await client.network.peers();
peers.forEach((peer) => {
  console.log(peer.id, peer.addresses);
});

Proxy Requests Through Anyone Network

Make anonymous HTTP requests through the Anyone network:

// Simple GET request
const response = await client.network.proxyAnon({
  url: "https://api.example.com/data",
  method: "GET",
  headers: {
    Accept: "application/json",
  },
});

console.log(response.status_code); // 200
console.log(response.body); // Response data as string
console.log(response.headers); // Response headers

// POST request with body
const postResponse = await client.network.proxyAnon({
  url: "https://api.example.com/submit",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ key: "value" }),
});

// Parse JSON response
const data = JSON.parse(postResponse.body);

Note: The proxy endpoint requires authentication (API key or JWT) and only works when the Anyone relay is running on the gateway server.

Configuration

ClientConfig

interface ClientConfig {
  baseURL: string; // Gateway URL
  apiKey?: string; // API key (optional, if using JWT instead)
  jwt?: string; // JWT token (optional, if using API key instead)
  timeout?: number; // Request timeout in ms (default: 30000)
  maxRetries?: number; // Max retry attempts (default: 3)
  retryDelayMs?: number; // Delay between retries (default: 1000)
  storage?: StorageAdapter; // For persisting JWT/API key (default: MemoryStorage)
  wsConfig?: Partial<WSClientConfig>; // WebSocket configuration
  fetch?: typeof fetch; // Custom fetch implementation
}

Storage Adapters

By default, credentials are stored in memory. For browser apps, use localStorage:

import { createClient, LocalStorageAdapter } from "@debros/network-ts-sdk";

const client = createClient({
  baseURL: "http://localhost:6001",
  storage: new LocalStorageAdapter(),
  apiKey: "ak_your_key:namespace",
});

Error Handling

The SDK throws SDKError for all errors:

import { SDKError } from "@debros/network-ts-sdk";

try {
  await client.db.query("SELECT * FROM nonexistent");
} catch (error) {
  if (error instanceof SDKError) {
    console.log(error.httpStatus); // e.g., 400
    console.log(error.code); // e.g., "HTTP_400"
    console.log(error.message); // Error message
    console.log(error.details); // Full error response
  }
}

Browser Usage

The SDK works in browsers with minimal setup:

// Browser example
import { createClient } from "@debros/network-ts-sdk";

const client = createClient({
  baseURL: "https://gateway.example.com",
  apiKey: "ak_browser_key:my-app",
});

// Use like any other API client
const data = await client.db.query("SELECT * FROM items");

Note: For WebSocket connections in browsers with authentication, ensure your gateway supports either header-based auth or query parameter auth.

Testing

Run E2E tests against a running gateway:

# Set environment variables
export GATEWAY_BASE_URL=http://localhost:6001
export GATEWAY_API_KEY=ak_test_key:default

# Run tests
npm run test:e2e

Examples

See the tests/e2e/ directory for complete examples of:

  • Authentication (auth.test.ts)
  • Database operations (db.test.ts)
  • Transactions (tx.test.ts)
  • Pub/Sub messaging (pubsub.test.ts)
  • Network operations (network.test.ts)

Building

npm run build

Output goes to dist/ with ESM and type declarations.

Development

npm run dev      # Watch mode
npm run typecheck # Type checking
npm run lint     # Linting (if configured)

License

MIT

Support

For issues, questions, or contributions, please open an issue on GitHub or visit DeBros Network Documentation.

Description
DeBros Network Typescript SDK
Readme MIT 256 KiB
Languages
TypeScript 100%