JavaScript / TypeScript SDK

Zero-dependency ESM client for walkindb. Works in Node 18+, Bun, Deno, Cloudflare Workers, and modern browsers — anywhere globalThis.fetch exists.

Install: npm install walkindb · npm: npmjs.com/package/walkindb · Current version: 0.1.0 · License: Apache-2.0

Install

npm install walkindb
# or
pnpm add walkindb
# or
bun add walkindb
# or (Deno)
deno add npm:walkindb

The package is ESM only (no CommonJS build), ships TypeScript types inline (index.d.ts), and has zero runtime dependencies. It uses globalThis.fetch, so any runtime that implements the standard Fetch API is supported:

  • Node.js 18+
  • Bun 1.0+
  • Deno 1.35+
  • Cloudflare Workers
  • Modern browsers (Chrome 85+, Firefox 90+, Safari 14+)
  • Any environment where you can inject a custom fetch via the constructor option

60-second example

import { Client } from "walkindb";

const db = new Client();

// First call provisions a new walk-in; Client captures the session token
// and transparently reuses it on subsequent calls.
await db.execute("CREATE TABLE notes(id INTEGER PRIMARY KEY, body TEXT)");
await db.execute("INSERT INTO notes(body) VALUES('hello')");

const result = await db.execute("SELECT * FROM notes");
console.log(result.columns);      // ['id', 'body']
console.log(result.rows);         // [[1, 'hello']]
console.log(result.rowsAffected); // 0 on SELECT

console.log(db.session);          // 'wkn_AZ159u9PdmS97ks7FnSm...'
console.log(db.expiresAt);        // unix timestamp when the walk-in will be deleted

TypeScript

Types ship in the package; no @types/walkindb needed.

import { Client, WalkinDBError, type Result, type ClientOptions } from "walkindb";

const opts: ClientOptions = {
  baseUrl: "https://api.walkindb.com",
  timeoutMs: 5000,
};
const db = new Client(opts);

try {
  const result: Result = await db.execute("SELECT 1");
  console.log(result.rows);
} catch (e) {
  if (e instanceof WalkinDBError) {
    console.error(`walkindb ${e.status}: ${e.error}`);
  }
}

Client

Stateful client. Captures the X-Walkin-Session token returned on the first call and reuses it on subsequent calls. Each Client instance is one walk-in.

new Client(opts?: ClientOptions)

interface ClientOptions {
  baseUrl?: string;        // default: "https://api.walkindb.com"
  session?: string;        // pre-existing token to resume with
  timeoutMs?: number;      // default: 10_000
  userAgent?: string;      // default: "walkindb-js/0.1.0"
  fetch?: typeof fetch;   // inject a custom fetch (tests, proxies, alt runtimes)
}
OptionTypeDefaultDescription
baseUrlstring"https://api.walkindb.com"API base URL. Trailing slashes are stripped.
sessionstringundefinedPre-existing wkn_... token to resume. Useful for session handoff between processes.
timeoutMsnumber10_000Per-request timeout, implemented via AbortSignal.timeout().
userAgentstring"walkindb-js/0.1.0"User-Agent string the client sends.
fetchtypeof fetchglobalThis.fetchInject a custom fetch. Constructor throws if globalThis.fetch is missing and no override is provided.

Client.execute(sql: string, args?: unknown[]): Promise<Result>

Execute one SQL statement against the current walk-in instance.

// Simple query
const r = await db.execute("SELECT 1 AS hello");

// Multiple statements in one call
await db.execute(`
  CREATE TABLE kv(k TEXT PRIMARY KEY, v TEXT);
  INSERT INTO kv VALUES('greeting', 'hello');
  INSERT INTO kv VALUES('farewell', 'goodbye');
`);

// Bound parameters (reserved; serialized on the wire but ignored server-side)
await db.execute("INSERT INTO notes(body) VALUES(?)", ["hello"]);

Returns: Promise<Result>.

Throws: WalkinDBError on any non-2xx response or network error.

Client.healthz(): Promise<boolean>

Returns true if GET /healthz responds 2xx. Catches all exceptions and returns false on error. Does not consume rate-limit budget.

if (!await db.healthz()) {
  throw new Error("walkindb unreachable");
}

Client.resetSession(): void

Forget the current session. The next execute() provisions a fresh walk-in.

db.resetSession();
await db.execute("SELECT 1"); // fresh instance

Client.session: string | null (read-only)

The current wkn_-prefixed session token, or null if no instance has been provisioned.

Client.expiresAt: number | null (read-only)

Unix timestamp (seconds) at which the current instance will be deleted, or null.

Result

interface Result {
  columns: string[];      // column names; empty array for non-SELECT
  rows: unknown[][];       // row data in column order
  rowsAffected: number;   // 0 on SELECT, N on INSERT/UPDATE/DELETE
  truncated: boolean;     // true if capped at 10k rows / ~1 MB
}
Naming note: the REST API returns rows_affected and truncated as JSON fields. The Client converts them to rowsAffected / truncated to match JS conventions. If you need the raw snake_case shape, use the REST API directly.

WalkinDBError

class WalkinDBError extends Error {
  readonly status: number;         // HTTP status code; 0 for network errors
  readonly error: string;          // server-provided error message
  readonly retryAfter?: number;    // seconds to wait (from Retry-After header)
}

Error-handling recipe:

try {
  await db.execute("SELECT * FROM notes");
} catch (e) {
  if (!(e instanceof WalkinDBError)) throw e;
  switch (e.status) {
    case 400:
      console.error("bad sql:", e.error);
      break;
    case 404:
      db.resetSession(); // start a new walk-in
      break;
    case 408:
      console.error("query timed out");
      break;
    case 429:
      await new Promise(r => setTimeout(r, (e.retryAfter ?? 10) * 1000));
      break;
    case 507:
      db.resetSession(); // instance quota full; provision a new walk-in
      break;
    default:
      throw e;
  }
}

See the full Error codes reference for every status the server returns.

Cloudflare Workers

walkindb works out of the box in Workers — fetch is already global. Just import and go:

import { Client } from "walkindb";

export default {
  async fetch(request) {
    const db = new Client();
    const result = await db.execute("SELECT 1 AS hello");
    return new Response(JSON.stringify(result), {
      headers: { "content-type": "application/json" },
    });
  },
};

Deno

import { Client } from "npm:walkindb";

const db = new Client();
console.log(await db.execute("SELECT 1"));

Bun

import { Client } from "walkindb";
const db = new Client();
console.log(await db.execute("SELECT 1"));

Browsers

walkindb's CORS headers are open (*), and the session headers are exposed, so the client works directly from a browser tab:

import { Client } from "https://esm.sh/[email protected]";

const db = new Client();
const result = await db.execute("SELECT 'hello from the browser'");
console.log(result.rows);

Don't put PII in walk-ins from browser code either — see the AUP.

Also see