Joltsdk

jolt-sdk · TypeScript

Build apps that
borrow an identity.

Define typed application data with Schema Classes, compose it through App.create, then connect or test it through one generated interface. Jolt owns identity, signed storage, paths, compatibility, and scoped approval. The low-level client remains available when an application needs explicit protocol control.

01 / Install

One package. Five entry points.

yarn add jolt-sdk

The SDK also ships with every Jolt release as an installable tarball, if you prefer pinning to a release directly:

yarn add https://github.com/alexanderwanyoike/jolt/releases/latest/download/jolt-sdk.tgz
ImportWhat it is
jolt-sdk/dataBeginner-first Schema Classes and typed application data APIs
jolt-sdkTypes, typed errors, and createJoltClient: tolerant, domain-shaped operations
jolt-sdk/transport-httpfetch-based transport for browsers and Node.js 18+
jolt-sdk/transport-tauriTauri invoke-based transport for desktop shells
jolt-sdk/testingcreateFakeJolt: a deterministic in-memory fake for tests

02 / Beginner Chirp

Describe the app. Jolt handles the machinery.

A Schema Class is both your TypeScript type and runtime validation. App.create derives paths and access; Chirp.connect() handles compatibility, host selection, and approval.

import { App, Collection, Field, Read, Schema } from "jolt-sdk/data";

@Schema({ version: 1 })
class Post {
  @Field.string()
  text!: string;

  @Field.dateTime()
  postedAt!: Date;
}

const Posts = Collection.create(Post, {
  access: {
    read: Read.AnyIdentity,
    create: true,
    update: true,
    delete: true,
    restore: true,
  },
});

const Chirp = App.create({
  id: "chirp.example",
  name: "Chirp",
  namespace: "chirp",
  data: { posts: Posts },
});

const chirp = await Chirp.connect();
const post = await chirp.posts.create({
  text: "Hello, Jolt!",
  postedAt: new Date(),
});

Chirp.test() exposes the same typed API in memory. Follow the complete compile-checked Beginner Chirp guide.

03 / Advanced low-level client

Session in, signed content out.

This explicit session, transport, path, and decoder flow is for advanced applications. Most applications should begin with jolt-sdk/data.

An app declares who it is and exactly what it wants to do. The daemon holds the request until the user approves it in Jolt Console; the app polls until the approval carries a bearer token, then every call is checked against the granted capabilities.

import { createJoltClient } from "jolt-sdk";
import { HttpTransport } from "jolt-sdk/transport-http";

let token = "";
const jolt = createJoltClient({
  transport: new HttpTransport({ daemonUrl: "http://127.0.0.1:9862" }),
  getSessionToken: () => token,
});

// 1. Ask for a scoped session; the user approves it in Jolt Console.
const status = await jolt.getStatus();
const request = await jolt.requestSession({
  appId: "myapp.local",
  appName: "My App",
  appOrigin: window.location.origin,
  identity: status.identity_address,
  capabilities: ["publish:/myapp/*", "resolve:public", "fetch:public"],
});

// 2. Poll until approved.
for (;;) {
  const s = await jolt.getSessionRequestStatus(request.request_id);
  if (s.session_token) { token = s.session_token; break; }
  await new Promise((r) => setTimeout(r, 1000));
}

// 3. Publish signed content and read it back, versioned and decoded.
await jolt.publishJson("/myapp/profile", { name: "Alice" });
const profile = await jolt.read(
  { identity: status.identity_address, path: "/myapp/profile" },
  (v) => (typeof v === "object" && v && "name" in v ? (v as { name: string }) : null)
);

Reads are tolerant: missing, unreachable, or undecodable content returns null instead of throwing, so one bad record never poisons an app projection. Failures from publishes and sends throw JoltApiError (the daemon answered with an error) or JoltTransportError (the daemon was unreachable); every operation accepts { signal, timeoutMs }.

04 / Transports

Same client. Two ways to the daemon.

Everything above the transport (operations, client, domain types) is identical in the browser, Node.js, and Tauri. Only the last hop changes.

HTTP · browser and Node.js

HttpTransport talks to the daemon over fetch. Point it at the daemon directly, or use HttpTransport.viteProxy() behind a dev-server proxy to dodge CORS.

import { HttpTransport } from "jolt-sdk/transport-http";

const transport = new HttpTransport({
  daemonUrl: "http://127.0.0.1:9862",
});
Tauri · desktop shells

Daemon calls go through audited Rust proxy commands, so the webview never needs network access. The tauri-plugin-jolt plugin ships those commands; wiring it up is three lines:

  1. 01
    Add the crate and register it:
    .plugin(tauri_plugin_jolt::init())
  2. 02
    Grant the jolt:default capability in your Tauri capabilities file.
  3. 03
    Construct the transport:
    new TauriTransport({ plugin: true })

05 / Testing

A whole daemon, faked in memory.

createFakeJolt returns a fully working JoltClient with no daemon and no network: publishes land in an in-memory store, reads resolve against it, sends are recorded, and incoming envelopes can be injected. Your tests exercise your schemas and flows, not HPKE.

import { createFakeJolt } from "jolt-sdk/testing";

const { client, sent, deliverIngress } = createFakeJolt("alice.jolt");
// client satisfies JoltClient and all of its sub-interfaces; sends are
// recorded in `sent`, and deliverIngress() injects incoming envelopes.

06 / Documentation

Where to go next.

API

Generated from TSDoc · four modules

SDK reference

Every exported class, interface, function, and type: the client and its sub-interfaces, typed operations, wire DTOs, both transports, and the testing fake.

01

Beginner tutorial · Data SDK

Build Chirp

Define a typed social app with Schema Classes, connect it, mutate posts, and test Alice and Bob without a daemon.

02

Fundamentals · Data SDK

Understand the Data SDK

Learn Schema Classes, Resources, Apps, Items, access, testing, and where deterministic migrations fit.

03

Fundamentals · Data SDK

Migrate stored schemas

Upgrade historical values through small deterministic steps while application code keeps one current Schema Class.

04

Fundamentals · Data SDK

Change an Item

Update, replace, delete, and restore immutable Items while handling lifecycle states and expected errors by type.

05

Advanced · Data SDK

Resolve Manual conflicts

Opt into application-owned choices between concurrent alternatives only when the automatic defaults are not enough.

06

Fundamentals · Data SDK

Keep remote data current

Open a retained Data Subscription and receive local Change Stream events without writing a polling loop.

07

Fundamentals · Data SDK

Test without a daemon

Use the same typed App interface for isolated tests, Alice and Bob journeys, and deliberate concurrency cases.