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

@statewavedev/sdk

v1.5.0

Published

Official TypeScript SDK for Statewave — the open-source memory runtime for AI agents.

Readme

Statewave TypeScript SDK

CI npm License: Apache-2.0

Official TypeScript SDK for Statewave — memory runtime for AI agents and applications.

Current release: v1.5.0 — the typed surface matches the /v1 REST contract and is semver-stable from 1.0.0 forward.

Part of Statewave — the open-source memory runtime for AI agents.

📦 Core runtime · 🐍 Python SDK · 🟦 TypeScript SDK · 🔌 Connectors · 📘 Docs · 💡 Examples · 🖥️ Admin · 🌐 statewave.ai

📋 Issues & feature requests: statewave/issues (centralized tracker)

Upgrading from a pre-0.9 SDK? v0.9.0 renamed the entire surface — request params and response fields — to idiomatic camelCase (subjectId, maxTokens, createdAt, receiptId, …). The wire protocol is unchanged; the client maps to/from the server's snake_case transparently. payload, metadata, and provenance are passed through verbatim — their inner keys are never rewritten. See CHANGELOG for the full rename table and migration steps.

New to Statewave? This SDK is a thin client for a running Statewave server. The fastest way to get one running is npx @statewavedev/statewave (or curl -fsSL https://www.statewave.ai/install | sh, or on Windows powershell -Command "irm https://www.statewave.ai/install.ps1 | iex"); see the Getting Started guide for the manual Docker Compose path. Every example below assumes a server reachable at http://localhost:8100.

Install

npm install @statewavedev/sdk

Quick start

import { StatewaveClient } from "@statewavedev/sdk";

// Basic (no auth)
const sw = new StatewaveClient("http://localhost:8100");

// With authentication and tenant
const swAuth = new StatewaveClient({
  baseUrl: "http://localhost:8100",
  apiKey: "your-key",
  tenantId: "acme",
});

// Record an episode
await sw.createEpisode({
  subjectId: "user-42",
  source: "support-chat",
  type: "conversation",
  sessionId: "ticket-8842", // optional — attribute the episode to a session (v1.0+)
  payload: {
    messages: [
      { role: "user", content: "My name is Alice and I work at Globex." },
      { role: "assistant", content: "Welcome Alice!" },
    ],
  },
});

// Compile memories (idempotent)
const result = await sw.compileMemories("user-42");
console.log(`Created ${result.memoriesCreated} memories`);

// Retrieve ranked, token-bounded context
const ctx = await sw.getContext({
  subjectId: "user-42",
  task: "Help with billing",
  maxTokens: 300,
});
console.log(ctx.assembledContext);

// Batch ingestion (up to 100)
await sw.createEpisodesBatch([
  { subjectId: "user-42", source: "crm", type: "note", payload: { text: "Prefers email" } },
  { subjectId: "user-42", source: "crm", type: "note", payload: { text: "Enterprise plan" } },
]);

// Search memories
const facts = await sw.searchMemories({
  subjectId: "user-42",
  kind: "profile_fact",
});

// Semantic search (requires embeddings)
const results = await sw.searchMemories({
  subjectId: "user-42",
  query: "billing",
  semantic: true,
});

// List all known subjects
const subjects = await sw.listSubjects();
for (const s of subjects.subjects) {
  console.log(`${s.subjectId}: ${s.episodeCount} episodes, ${s.memoryCount} memories`);
}

// Get timeline — the server's default page is the OLDEST episodes
const timeline = await sw.getTimeline("user-42");
console.log(`${timeline.episodes.length} episodes, ${timeline.memories.length} memories`);

// A bounded window of RECENT history (ascending within the page)
const recent = await sw.getTimeline("user-42", { limit: 20, newestFirst: true });
if (recent.episodesHasMore) console.log("older episodes exist beyond this page");

// Delete all subject data
await sw.deleteSubject("user-42");

Governance & audit (v0.8+)

The SDK surfaces the state-assembly receipts and sensitivity-labels / policy layer added in server v0.8, plus the v0.9 HMAC signing and as-of replay surfaces.

import { StatewaveClient } from "@statewavedev/sdk";

const sw = new StatewaveClient({
  baseUrl: "http://localhost:8100",
  apiKey: "your-key",
  tenantId: "acme",
});

// Per-request opt-in for an immutable audit receipt of the assembly.
// callerId / callerType feed the sensitivity-label policy engine —
// when the tenant config sets require_caller_identity=true, missing
// values 401.
const bundle = await sw.getContext({
  subjectId: "user-42",
  task: "What plan is this customer on?",
  emitReceipt: true,
  callerId: "agent-7",
  callerType: "support_agent",
});

if (bundle.receiptId) {
  // Receipts are ULID-addressable, tenant-scoped, append-only.
  const receipt = await sw.getReceipt(bundle.receiptId);
  // output.contextHash is a SHA-256 of the bytes delivered to the
  // agent — recompute from bundle.assembledContext to verify integrity.
  console.log(receipt.output.contextHash);
  console.log(`${receipt.selectedEntries.length} entries influenced this bundle`);
}

// List receipts for a subject, cursor-paginated, newest-first.
const { receipts, nextCursor } = await sw.listReceipts({
  subjectId: "user-42",
  limit: 10,
});
for (const r of receipts) {
  console.log(r.receiptId, r.task);
}

// Verify the HMAC signature on a stored receipt (v0.9+).
// `valid` is true | false | null — see ReceiptVerifyResult for the
// full reason vocabulary (no_signature / key_unavailable / etc.).
if (bundle.receiptId) {
  const verdict = await sw.verifyReceipt(bundle.receiptId);
  if (verdict.valid === true) {
    console.log(`signature OK — signed by ${verdict.keyId}`);
  } else if (verdict.valid === false) {
    console.log("signature mismatch — body may have been tampered with");
  } else {
    console.log(`verdict undetermined: ${verdict.reason}`);
  }
}

// Replay the receipt against current memories using the original
// policy bundle captured on the receipt (v0.9+). Returns a diff
// envelope showing what changed since emission. Pre-v0.9 receipts
// throw StatewaveUnreplayableError with reason="missing_policy_snapshot".
import { StatewaveUnreplayableError } from "@statewavedev/sdk";
try {
  const replay = await sw.replayReceipt(bundle.receiptId!);
  if (replay.diff.contextHash.changed) {
    console.log(`replay differs from original: new id ${replay.replayReceiptId}`);
  }
} catch (err) {
  if (err instanceof StatewaveUnreplayableError) {
    // err.reason ∈ {"missing_policy_snapshot", "nested_replay", "invalid_snapshot"}
    console.log(`replay refused: ${err.reason}`);
  } else {
    throw err;
  }
}

// Set per-memory sensitivity labels (server normalizes — dedup, lowercase, trim).
// Memories with labels become subject to any active policy bundle for the tenant.
const updated = await sw.setMemoryLabels({
  memoryId: "mem-uuid",
  sensitivityLabels: ["pii", "financial"],
});
console.log(updated.sensitivityLabels); // → ["financial", "pii"]

Receipts and the policy engine cooperate: every assembly call records its policy decisions into receipt.policy.filtersApplied (one entry per memory the policy fired on) and receipt.policy.filtersSkipped (per-rule summary of what didn't fire). In log_only mode (the tenant default) the receipt is the full audit trail without filtering; under enforce denied memories are dropped before they reach the assembly and the deny is still recorded. See receipts.md and sensitivity-labels.md for the full schemas and policy YAML format.

Support-agent endpoints

Statewave's support wedge — customer health scoring, SLA tracking, resolution state, and structured escalation briefs — is exposed through ergonomic SDK methods (server v0.6+).

import { StatewaveClient } from "@statewavedev/sdk";

const sw = new StatewaveClient("http://localhost:8100");

// Customer health score (0–100) with the explainable factors behind it.
const health = await sw.getHealth("customer:globex");
console.log(`${health.score}/100 — ${health.state}`);
for (const f of health.factors) {
  console.log(`  ${f.signal}: ${f.impact >= 0 ? "+" : ""}${f.impact} (${f.detail})`);
}

// SLA metrics — first-response / resolution times and breach counts.
// Thresholds are optional; they default server-side to 5 min / 24 h.
const sla = await sw.getSLA({
  subjectId: "customer:globex",
  firstResponseThresholdMinutes: 10,
  resolutionThresholdHours: 48,
});
console.log(`${sla.resolvedSessions}/${sla.totalSessions} resolved, ${sla.resolutionBreachCount} SLA breaches`);

// Track resolution state for a session (upserts by subject + session).
await sw.createResolution({
  subjectId: "customer:globex",
  sessionId: "ticket-8842",
  status: "resolved",
  resolutionSummary: "Issued refund for the duplicate charge",
});

// List resolutions, optionally filtered by status.
const openItems = await sw.listResolutions({
  subjectId: "customer:globex",
  status: "open",
});

// Generate a handoff context pack for escalation or shift change.
// `handoffNotes` is a pre-rendered markdown brief for human or LLM use.
const handoff = await sw.createHandoff({
  subjectId: "customer:globex",
  sessionId: "ticket-8842",
  reason: "escalation",
  callerId: "agent-7",
  callerType: "support_agent",
});
console.log(handoff.handoffNotes);

getHealth, getSLA, createResolution, listResolutions, and createHandoff respect the same auth, tenant-scoping, and retry behaviour as the rest of the client. createHandoff shares getContext's caller-identity gate — when the tenant config sets require_caller_identity: true, both callerId and callerType are mandatory.

Error handling

import { StatewaveClient, StatewaveAPIError, StatewaveConnectionError } from "@statewavedev/sdk";

const sw = new StatewaveClient();

try {
  await sw.compileMemories("user-42");
} catch (e) {
  if (e instanceof StatewaveAPIError) {
    console.error(`API error [${e.statusCode}]: ${e.code} — ${e.message}`);
    console.error(`Request ID: ${e.requestId}`);
  } else if (e instanceof StatewaveConnectionError) {
    console.error("Cannot connect to Statewave server");
  }
}

Where does data go?

The SDK is a thin client over the Statewave HTTP API. What leaves the network is determined by the server's compiler and embedding configuration, not by the SDK:

  • Default deployment (heuristic compiler, no embeddings) — nothing leaves your infrastructure.
  • LLM compiler or hosted embeddings — the server sends content to the provider you configure.

See Privacy & Data Flow for the full breakdown.

Types

All response types are fully typed:

  • Episode — raw interaction record
  • Memory — compiled memory with provenance + optional sensitivityLabels
  • CompileResult — compilation response
  • SearchResult — search response
  • ContextBundle — assembled context with facts, episodes, provenance, optional receiptId / receiptEmitted
  • Timeline — chronological subject history
  • DeleteResult — deletion confirmation
  • BatchCreateResult — batch ingestion response
  • SubjectSummary — subject with episode/memory counts
  • ListSubjectsResult — paginated subject listing
  • Receipt + ReceiptSelectedEntry + ReceiptPolicy + ReceiptOutput — state-assembly audit artifact (v0.8+) and its nested shapes; v0.9 added HMAC signature fields (receiptSignatureKeyId, receiptSignatureAlgorithm), policySnapshot for replay, and region for residency
  • ReceiptVerifyResultvalid (true | false | null) + keyId + algorithm + reason for the v0.9 HMAC verify endpoint
  • ReceiptReplayResult / ReceiptReplayDiff — original + replay receipt ids plus the structural diff envelope from POST /v1/receipts/{id}/replay (v0.9)
  • StatewaveUnreplayableError — thrown by replayReceipt(...) on HTTP 422; .reason is a discriminated union of "missing_policy_snapshot" | "nested_replay" | "invalid_snapshot"
  • ReceiptList — cursor-paginated receipt listing
  • Health + HealthFactor — customer health score and its explainable factors
  • SLASummary + SessionSLA — SLA metrics, aggregate and per-session
  • Handoff + ResolutionSummaryItem — handoff context pack and its prior-resolution items
  • Resolution — resolution tracking record
  • HealthState / ResolutionStatus — string-literal status unions

Param types: CreateEpisodeParams, SearchMemoriesParams, GetContextParams, ListReceiptsParams, SetMemoryLabelsParams, GetSLAParams, CreateHandoffParams, CreateResolutionParams, ListResolutionsParams

CreateEpisodeParams accepts an optional sessionId (v1.0+) to attribute an episode to a session; it is forwarded on both createEpisode and createEpisodesBatch.

Running tests

npm install
npm test

License

Apache-2.0