Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/michael-tiger-2010/dragonjson/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through every essential dragonJSON operation using the bundled demo server. By the end you will have a running client that reads lazily-loaded nested data from the server, writes back mutations, and listens for live change events — all with no package manager or build step required.
1

Import dragonJSON

dragonJSON ships as a single ES module file with no external dependencies. Import it directly into your script:
import dragonJSON from './client/web-client.js';
2

Start the Node.js demo server

The repository includes a zero-dependency reference server built on Node.js built-ins. Start it with:
node server/nodejs/server.js
The server starts on port 3000 by default. No npm install is needed — it relies only on the built-in http and url modules.
3

Initialize the client

Call dragonJSON with your server’s base URL and any options. The function returns a two-element array: the server proxy you read and write through, and a control object for runtime configuration.
const [server, control] = dragonJSON("http://localhost:3000", {
  auth: "Bearer admin-secret",
  enableBatching: true,
});
OptionTypeDescription
authstringSent as the Authorization header on every request.
enableBatchingbooleanCoalesces rapid concurrent requests into one round trip. Defaults to true.
debugbooleanLogs internal proxy activity to the console.
liveInvalidationobjectRelay hooks for real-time cross-client sync. See Live Sync.
4

Read data

Accessing any property on server builds a path. Awaiting it triggers a fetch for only that path. Once a parent is fetched, its children are cached and resolve instantly.
// Fetches only posts.page1 from the server
const title = await server.posts.page1.title;
console.log(title); // "Hello World"

// posts.page1 is cached — body resolves instantly
const body = await server.posts.page1.body;
console.log(body); // "First post body."
To pre-warm multiple paths in parallel, pass them to Promise.all:
// Both paths are fetched in a single batched round trip
await Promise.all([server.posts.page1, server.posts.page2]);
5

Write data

Use $set to update an existing value and $add to append a new entry. Both POST to the server and automatically invalidate the affected cache paths on success.
// Update an existing post
await server.posts.page1.$set({ title: "Updated Title", body: "New content" });

// Add a new post (server assigns the key)
await server.posts.$add({ title: "New Post", body: "Hello!" });
To delete a path, use $remove:
// Remove a specific post
await server.posts.page1.$remove();
6

Listen for changes

Subscribe to mutations at any path with $on. The callback receives an event object containing the affected key, the originating path, and a lazy proxy to the new data.
server.posts.$on("add", "*", (e) => {
  console.log("New post added at key:", e.key);
});
The four event types are "add", "remove", "set", and "*" (any). Pass "*" as the key to match any child. To stop listening, call $off with the same four arguments:
const handler = (e) => console.log("New post added at key:", e.key);

server.posts.$on("add", "*", handler);
// ...later...
server.posts.$off("add", "*", handler);
The demo server uses an in-memory store. Restart it to reset all data to its initial state.
Ready to go deeper? See the Mutations guide for the full $set / $add / $remove API, and the Events guide for bubbling listeners, the $on event object shape, and live cross-client sync.

Build docs developers (and LLMs) love