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

gbase-sdk

v1.0.1

Published

TypeScript SDK for GBase JSON-over-TCP database engine

Readme

GBase Node.js TypeScript SDK

A high-performance, strongly-typed TypeScript SDK for GBase — an in-memory JSON-over-TCP database engine supporting Key-Value, List, Set, Sorted Set (ZSet), atomic Transactions, and real-time Pub/Sub.

  • For in-depth technical architecture, TCP wire protocol framing, request pipeline design, and decision rationales, see TECH.md.
  • For complete method-by-method JSON wire request/response payload mapping, see API_CONTRACT.md.

Table of Contents


Features

  • Async/Await Native: Promise-based API mapping TCP socket communication into standard async/await control flow.
  • Light OOP Paradigm: Clean data-holder classes (KVStorage, ListStorage, SetStorage, ZSetStorage) encapsulating instance UUIDs.
  • Type-Safe: Full TypeScript type definitions supporting generic payload types (<T>).
  • Full GBase Feature Support: Supports all server engines, pattern matching operations (PREFIX, SUFFIX, REGEX), TTL expirations, multi-key operations, and set algebra.
  • Atomic Transactions: Full support for MULTI, EXEC, and DISCARD across multiple data structures.
  • Real-Time Pub/Sub: Event-driven subscriber client (PubSubClient) operating on dedicated sockets to isolate subscriber mode.
  • Custom Error Hierarchy: Explicit error classes for network timeouts, connection drops, and server-side command errors.

Architecture Overview

flowchart TD
    App["Application Code"]
    
    subgraph SDK ["GBase Node.js SDK"]
        GBaseClient["GBase Client Connection"]
        
        subgraph StorageEngines ["Light OOP Storage Engines"]
            KV["KVStorage"]
            List["ListStorage"]
            SetEngine["SetStorage"]
            ZSet["ZSetStorage"]
        end
        
        Tx["Transaction Manager"]
        PubSub["PubSubClient (Dedicated Socket)"]
    end
    
    subgraph Server ["GBase Server (:6380)"]
        TCPListener["TCP Line-Delimited JSON Listener"]
        Mux["Multiplexer Engine Router"]
        DBInstances["Sub-Database Instances (UUIDs)"]
        PubSubHub["Pub/Sub Hub"]
    end

    App -->|invoke methods| StorageEngines
    App -->|multi / exec| Tx
    App -->|subscribe / listen| PubSub
    
    StorageEngines -->|queue request| GBaseClient
    Tx -->|queue commands| GBaseClient
    
    GBaseClient <-->|TCP \n JSON Frames| TCPListener
    PubSub <-->|Dedicated TCP Push Socket| PubSubHub
    
    TCPListener --> Mux
    Mux --> DBInstances

Installation

Ensure you have Node.js (v16+) installed. Add the SDK to your project:

npm install gbase-sdk

Ensure a GBase TCP server is running on port 6380 (or your configured port).


Getting Started

import { GBase } from 'gbase-sdk';

async function main() {
  // Connect to local GBase server
  const gbase = await GBase.connect('127.0.0.1:6380');

  // Create a new KV storage sub-instance on server
  const kv = await gbase.createKvStorage();

  // Store and retrieve typed JSON data
  await kv.set('user:101', { name: 'Alice', score: 95 });
  const user = await kv.get<{ name: string; score: number }>('user:101');

  console.log('User:', user); // { name: 'Alice', score: 95 }

  await gbase.disconnect(); // or gbase.close()
}

main();

Usage and Examples

Connecting to GBase

GBase.connect() and new GBase() support full connection strings, host/port strings, or options objects:

// Full Connection String (with owner UUID & port)
const gbase1 = await GBase.connect('gbase://[email protected]:6381');

// Simple Connection String
const gbase2 = await GBase.connect('gbase://127.0.0.1:6380');

// Constructor Instantiation
const gbase3 = new GBase('gbase://[email protected]:6381');

// Host and Port String
const gbase4 = await GBase.connect('127.0.0.1:6380');

// Options Object
const gbase5 = await GBase.connect({
  host: '127.0.0.1',
  port: 6380,
  timeoutMs: 5000,
  userId: 'b4b1d3ab-71a7-4f4c-a25a-ec2cbe4276c8'
});

System Telemetry and Instance Management

GBase supports dynamic creation and deletion of isolated sub-database instances:

// Get server diagnostics & memory allocation
const info = await gbase.info();
console.log('Go Version:', info.server.go_version);
console.log('Total Instances:', info.server.total_instances);

// Get total count of active instances across all engines
const count = await gbase.totalInstances();

// Create raw sub-instance UUID
const uuid = await gbase.createInstance('kv');

// Delete sub-instance by UUID
await gbase.deleteInstance('kv', uuid);

Key-Value (KV) Storage

Supports primitives, complex objects, TTL expiration, atomic counters, bulk operations, and pattern matching.

// Factory: Create new KV instance or attach to existing UUID
const kv = await gbase.createKvStorage();
// or attach: const existingKv = gbase.useKvStorage("uuid-string");

// Basic SET & GET
await kv.set('config', { theme: 'dark', notifications: true });
const config = await kv.get<{ theme: string }>('config');

// SET with TTL (in milliseconds)
await kv.setTtl('session:abc', 'user_token', 5000); // expires in 5 seconds

// Non-existent key returns null
const missing = await kv.get('non_existent_key'); // null

// Atomic Counters
await kv.set('counter', 10);
await kv.incr('counter');       // 11
await kv.decr('counter');       // 10
await kv.incrBy('counter', 5);  // 15
await kv.decrBy('counter', 3);  // 12

// Bulk MSET and MGET
await kv.mset({ k1: 'val1', k2: 'val2', k3: 100 });
const batch = await kv.mget(['k1', 'k2', 'k3', 'missing']);
// { k1: 'val1', k2: 'val2', k3: 100, missing: null }

// Pattern Matching (PREFIX, SUFFIX, REGEX)
await kv.countPrefix('user:');
const userMap = await kv.findPrefix<string>('user:'); // { 'user:1': 'Alice', 'user:2': 'Bob' }
const deletedCount = await kv.delPrefix('user:');

List Storage

Doubly linked list storage supporting left/right pushes/pops, ranged slicing, index access, pivot insertion, and atomic moves.

const list = await gbase.createListStorage();

// Push items to head (left) or tail (right)
await list.rpush('tasks', { title: 'Task 1' }, { title: 'Task 2' });
await list.lpush('tasks', { title: 'Priority Task' });

// Length and Ranged Slices
const len = await list.llen('tasks'); // 3
const allTasks = await list.lrange('tasks', 0, -1);
const allTasksLGet = await list.lget('tasks'); // Full list fetch

// Pop items
const priority = await list.lpop('tasks'); // Left pop
const last = await list.rpop('tasks');     // Right pop

// Indexed Access & Updates
const itemAtIndex = await list.lindex('tasks', 0);
await list.lset('tasks', 0, { title: 'Updated Task' });

// Insert relative to pivot element (BEFORE or AFTER)
await list.linsert('tasks', 'BEFORE', { title: 'Task 2' }, { title: 'Middle Task' });

// Atomic RPOPLPUSH (pop tail of queue1, push to head of queue2)
const movedItem = await list.rpoplpush('queue1', 'queue2');

// Pattern Matching
const foundLists = await list.findPrefix('logs:');

Set Storage

Unordered collection of unique elements supporting set algebra (intersections, unions, differences), store variants, and random sampling.

const set = await gbase.createSetStorage();

// Add & Remove unique members
await set.sadd('tags', 'javascript', 'typescript', 'go');
await set.srem('tags', 'go');

// Cardinality & Membership
const count = await set.scard('tags'); // 2
const isMember = await set.sismember('tags', 'typescript'); // true
const memberFlags = await set.smismember('tags', 'javascript', 'python'); // [true, false]

// Random Popping & Sampling
const popped = await set.spop('tags', 1); // Pops 1 random element
const randomSample = await set.srandmember('tags', 2); // Samples without removing

// Move member between sets
await set.smove('setA', 'setB', 'member1');

// Set Algebra: SINTER, SUNION, SDIFF
await set.sadd('groupA', 'alice', 'bob', 'charlie');
await set.sadd('groupB', 'bob', 'charlie', 'dave');

const common = await set.sinter('groupA', 'groupB'); // ['bob', 'charlie']
const allUsers = await set.sunion('groupA', 'groupB'); // ['alice', 'bob', 'charlie', 'dave']
const uniqueToA = await set.sdiff('groupA', 'groupB'); // ['alice']

// Intersection Cardinality without fetching all members
const interCard = await set.sintercard(['groupA', 'groupB'], 10);

// Store algebra results into a new destination key
await set.sinterstore('destKey', 'groupA', 'groupB');

Sorted Set (ZSet) Storage

Elements sorted by floating-point scores, supporting rank lookups, score range queries, and min/max popping.

const zset = await gbase.createZSetStorage();

// Add members with scores
await zset.zadd(
  'leaderboard',
  { score: 100, member: 'player1' },
  { score: 250, member: 'player2' },
  { score: 180, member: 'player3' }
);

// Get score & rank
const score = await zset.zscore('leaderboard', 'player1'); // 100
const rank = await zset.zrank('leaderboard', 'player2');   // 2 (0-indexed, ascending)
const revRank = await zset.zrevrank('leaderboard', 'player2'); // 0 (descending)

// Increment score
await zset.zincrby('leaderboard', 50, 'player1'); // 150

// Pop Max / Min scored elements
const topPlayer = await zset.zpopmax('leaderboard', 1); // [{ member: 'player2', score: 250 }]
const lowestPlayer = await zset.zpopmin('leaderboard', 1);

// Range by Rank
const top3 = await zset.zrevrange('leaderboard', 0, 2);

// Range by Score with Offset & Limit
const scoredRange = await zset.zrangebyscore('leaderboard', 100, 200, 0, 10);

Atomic Transactions (MULTI / EXEC / DISCARD)

Executes multiple commands atomically across any storage engine in a single transaction block.

sequenceDiagram
    autonumber
    actor App as Application Code
    participant Client as GBase Client
    participant Server as GBase Server

    App->>Client: gbase.multi()
    Client->>Server: {"method": "MULTI"}
    Server-->>Client: {"ok": true}
    
    App->>Client: kv.set("k1", "v1")
    Client->>Server: {"ds": "kv", "uuid": "...", "method": "SET", "args": [...]}
    Server-->>Client: {"ok": true, "queued": true}
    
    App->>Client: list.rpush("l1", "item1")
    Client->>Server: {"ds": "list", "uuid": "...", "method": "RPUSH", "args": [...]}
    Server-->>Client: {"ok": true, "queued": true}

    alt Commit Transaction
        App->>Client: tx.exec()
        Client->>Server: {"method": "EXEC"}
        Server-->>Client: {"ok": true, "responses": [res1, res2]}
        Client-->>App: returns [res1, res2]
    else Rollback Transaction
        App->>Client: tx.discard()
        Client->>Server: {"method": "DISCARD"}
        Server-->>Client: {"ok": true}
        Client-->>App: transaction cleared
    end
// Initiate transaction on connection
const tx = await gbase.multi();

// Queue commands across your storage engines
await kv.set('acc:1', 100);
await kv.set('acc:2', 200);
await list.rpush('tx_log', 'Transferred funds');

// Commit and execute all queued commands atomically
const responses = await tx.exec();
console.log('Atomic execution results:', responses);

// Discard transaction (roll back queued commands)
const tx2 = await gbase.multi();
await kv.set('temp', 'value');
await tx2.discard(); // Cancels queued operations

Real-Time Pub/Sub Messaging

Subscriber mode operates on a dedicated TCP connection (PubSubClient) to prevent blocking normal database commands:

sequenceDiagram
    autonumber
    actor SubscriberApp as Subscriber App
    participant SubClient as PubSubClient (Dedicated Socket)
    participant Server as GBase Server (:6380)
    participant PubClient as GBase Client (Command Socket)
    actor PublisherApp as Publisher App

    SubscriberApp->>SubClient: createPubSubClient()
    SubClient->>Server: TCP Connect
    SubscriberApp->>SubClient: subscribe("news.sports")
    SubClient->>Server: {"method": "SUBSCRIBE", "args": ["news.sports"]}
    Server-->>SubClient: {"ok": true, "pubsub": {"action": "subscribe", ...}}

    PublisherApp->>PubClient: gbase.publish("news.sports", "Goal!")
    PubClient->>Server: {"method": "PUBLISH", "args": ["news.sports", "Goal!"]}
    Server-->>PubClient: {"ok": true, "integer": 1}

    Note over Server,SubClient: Asynchronous Push Frame
    Server-->>SubClient: {"type": "message", "channel": "news.sports", "data": "Goal!"}
    SubClient-->>SubscriberApp: emit("message", "news.sports", "Goal!")
import { GBase } from 'gbase-sdk';

async function main() {
  const gbase = await GBase.connect('127.0.0.1:6380');

  // Dedicated subscriber socket connection
  const subscriber = await gbase.createPubSubClient();

  // Listen to exact channel messages
  subscriber.on('message', (channel: string, data: any) => {
    console.log(`[${channel}]:`, data);
  });

  // Listen to glob pattern messages
  subscriber.on('pmessage', (pattern: string, channel: string, data: any) => {
    console.log(`[Pattern ${pattern} on ${channel}]:`, data);
  });

  // Subscribe
  await subscriber.subscribe('news.sports', 'news.tech');
  await subscriber.psubscribe('orders.*');

  // Publish from main client (returns subscriber recipient count)
  const recipients = await gbase.publish('news.sports', { event: 'Goal!', minute: 90 });
  console.log(`Recipients reached: ${recipients}`);

  // Unsubscribe & Close
  await subscriber.unsubscribe('news.sports');
  await subscriber.close();
  await gbase.close();
}

main();

Error Handling

The SDK provides an explicit error hierarchy extending standard JavaScript Error:

import {
  GBaseError,
  GBaseConnectionError,
  GBaseCommandError,
  GBaseTimeoutError
} from 'gbase-sdk';

try {
  const data = await kv.get('key');
} catch (err) {
  if (err instanceof GBaseConnectionError) {
    console.error('Network drop or TCP socket error:', err.message);
  } else if (err instanceof GBaseCommandError) {
    console.error('Server rejected command:', err.serverError);
  } else if (err instanceof GBaseTimeoutError) {
    console.error('Request timed out:', err.message);
  } else if (err instanceof GBaseError) {
    console.error('General GBase error:', err.message);
  }
}

API Contract & Wire Mapping

For complete details on exact JSON request payloads (ds, method, args) and response payload fields unwrapped by each SDK function, see API_CONTRACT.md.


Running Tests

Run the complete Jest integration & unit test suite:

npm test

The test suite runs 62+ tests covering connection pipeline telemetry, KV, List, Set, ZSet engines, pattern matching, atomic transactions, real-time Pub/Sub, and edge cases.


Technical Architecture Documentation

For detailed information on the architectural design, wire protocol framing, light OOP data holders, request pipeline queue, and socket management, refer to TECH.md.