sapixdb 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md DELETED
@@ -1,295 +0,0 @@
1
- # SapixDB JavaScript / TypeScript SDK
2
-
3
- Official SDK for [SapixDB](https://sapixdb.com) — the agent-native living database.
4
-
5
- Zero dependencies. Works in Node.js 18+, Bun, Deno, and modern browsers.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install sapixdb
11
- # or
12
- bun add sapixdb
13
- ```
14
-
15
- ## Quick Start
16
-
17
- ```typescript
18
- import { SapixClient } from "sapixdb";
19
-
20
- const db = new SapixClient({
21
- url: "http://localhost:7475",
22
- agent: "my-app",
23
- });
24
-
25
- // Write a record
26
- const record = await db.collection("products").write({
27
- name: "T-Shirt",
28
- price: 29.99,
29
- stock: 100,
30
- });
31
- console.log(record.id); // "nuc_abc123"
32
- console.log(record.hash); // "sha3:e7f2a1..."
33
-
34
- // Read latest records
35
- const products = await db.collection("products").latest();
36
-
37
- // Filter
38
- const shirts = await db.collection("products").find({ category: "apparel" });
39
-
40
- // Time travel — what did the DB look like yesterday?
41
- const yesterday = await db
42
- .collection("orders")
43
- .asOf("2026-05-11T00:00:00Z")
44
- .latest();
45
- ```
46
-
47
- ## API Reference
48
-
49
- ### `new SapixClient(config)`
50
-
51
- | Option | Type | Default | Description |
52
- |--------|------|---------|-------------|
53
- | `url` | `string` | — | SapixDB agent URL |
54
- | `agent` | `string` | — | Agent ID (matches `SAPIX_AGENT_ID`) |
55
- | `headers` | `Record<string,string>` | `{}` | Extra HTTP headers |
56
- | `timeout` | `number` | `10000` | Request timeout (ms) |
57
-
58
- ---
59
-
60
- ### `db.collection(name)`
61
-
62
- Returns a `CollectionClient` for the given collection name.
63
-
64
- #### `.write(data)` → `WriteResult`
65
-
66
- Append a new record. Nothing is ever overwritten.
67
-
68
- ```typescript
69
- const result = await db.collection("orders").write({
70
- customer_id: "cust_001",
71
- total: 149.99,
72
- status: "placed",
73
- });
74
- // result.id — nucleotide ID
75
- // result.hash — cryptographic fingerprint
76
- // result.timestamp — ISO 8601 timestamp
77
- ```
78
-
79
- #### `.writeBatch(records[])` → `WriteResult[]`
80
-
81
- Write multiple records in parallel.
82
-
83
- ```typescript
84
- await db.collection("products").writeBatch([
85
- { name: "T-Shirt", price: 29.99 },
86
- { name: "Sneakers", price: 89.99 },
87
- ]);
88
- ```
89
-
90
- #### `.get(id)` → `NucleotideRecord`
91
-
92
- Fetch a single record by its nucleotide ID.
93
-
94
- ```typescript
95
- const record = await db.collection("orders").get("nuc_abc123");
96
- console.log(record.data.status); // "placed"
97
- ```
98
-
99
- #### `.latest(options?)` → `NucleotideRecord[]`
100
-
101
- Fetch the latest version of every record in the collection.
102
-
103
- #### `.history(options?)` → `NucleotideRecord[]`
104
-
105
- Fetch ALL versions — the full append-only history.
106
-
107
- #### `.find(filter, options?)` → `NucleotideRecord[]`
108
-
109
- Find records matching a filter (latest version only).
110
-
111
- ```typescript
112
- const pending = await db.collection("orders").find({ status: "pending" });
113
- ```
114
-
115
- #### `.findOne(filter)` → `NucleotideRecord | null`
116
-
117
- Find the first matching record, or `null`.
118
-
119
- #### `.asOf(timestamp)` → `CollectionQuery`
120
-
121
- Scope all subsequent reads to a specific point in time.
122
-
123
- ```typescript
124
- // What did Alice's record look like 2 hours ago?
125
- const snapshot = await db
126
- .collection("users")
127
- .asOf("2026-05-12T08:00:00Z")
128
- .find({ name: "Alice" });
129
- ```
130
-
131
- ---
132
-
133
- ### `db.graph`
134
-
135
- #### `.relate(src, dst, type, weight?)` → `void`
136
-
137
- Create a typed directed edge between two records.
138
-
139
- ```typescript
140
- await db.graph.relate(orderId, customerId, "placed_by");
141
- await db.graph.relate(productId, categoryId, "belongs_to");
142
- await db.graph.relate(managerId, reportId, "manages", 1.0);
143
- ```
144
-
145
- #### `.addEdge(edge)` → `void`
146
-
147
- Full edge creation with all options.
148
-
149
- ```typescript
150
- await db.graph.addEdge({
151
- src: "nuc_abc123",
152
- dst: "nuc_def456",
153
- edge_type: "manages",
154
- weight: 1.0,
155
- });
156
- ```
157
-
158
- #### `.traverse(fromId, options?)` → `TraverseResult`
159
-
160
- Walk the graph from a starting node.
161
-
162
- ```typescript
163
- const { nodes, edges } = await db.graph.traverse("nuc_abc123", {
164
- depth: 3,
165
- direction: "outbound", // "outbound" | "inbound" | "both"
166
- });
167
- ```
168
-
169
- #### `.neighbors(id, direction?)` → `NucleotideRecord[]`
170
-
171
- Get direct neighbours of a node.
172
-
173
- ---
174
-
175
- ### `db.ingest(collection, data)` → `WriteResult`
176
-
177
- Write via the ingest endpoint — designed for AI agents, webhooks, and automated pipelines.
178
-
179
- ```typescript
180
- await db.ingest("ai_decisions", {
181
- model: "gpt-4o",
182
- action: "approve_loan",
183
- confidence: 0.94,
184
- reasoning: "Credit score 780, DTI 28%",
185
- });
186
- ```
187
-
188
- ---
189
-
190
- ### `db.health()` / `db.ping()`
191
-
192
- ```typescript
193
- const { status, agent } = await db.health(); // throws on failure
194
- const alive = await db.ping(); // returns true/false, never throws
195
- ```
196
-
197
- ---
198
-
199
- ## TypeScript Generics
200
-
201
- Pass your type as a generic to get full autocomplete and type checking:
202
-
203
- ```typescript
204
- interface Product {
205
- name: string;
206
- price: number;
207
- stock: number;
208
- category?: string;
209
- }
210
-
211
- const products = db.collection<Product>("products");
212
-
213
- const result = await products.write({ name: "T-Shirt", price: 29.99, stock: 100 });
214
- const items = await products.latest();
215
- // items[0].data.price is typed as number ✓
216
- ```
217
-
218
- ---
219
-
220
- ## Error Handling
221
-
222
- ```typescript
223
- import { SapixError, SapixNetworkError, SapixNotFoundError } from "sapixdb";
224
-
225
- try {
226
- const record = await db.collection("orders").get("nuc_missing");
227
- } catch (err) {
228
- if (err instanceof SapixNotFoundError) {
229
- console.log("Record does not exist");
230
- } else if (err instanceof SapixNetworkError) {
231
- console.log("Cannot reach SapixDB — is it running?");
232
- } else if (err instanceof SapixError) {
233
- console.log(`SapixDB error ${err.status}: ${err.message}`);
234
- }
235
- }
236
- ```
237
-
238
- ---
239
-
240
- ## Full Example: Online Store
241
-
242
- ```typescript
243
- import { SapixClient } from "sapixdb";
244
-
245
- const db = new SapixClient({ url: "http://localhost:7475", agent: "store" });
246
-
247
- // ── 1. Add products ───────────────────────────────────────────────
248
- const shirt = await db.collection("products").write({
249
- sku: "SHIRT-001", name: "Classic T-Shirt", price: 29.99, stock: 200,
250
- });
251
- const shoes = await db.collection("products").write({
252
- sku: "SHOE-042", name: "Running Sneakers", price: 89.99, stock: 50,
253
- });
254
-
255
- // ── 2. Register a customer ────────────────────────────────────────
256
- const customer = await db.collection("customers").write({
257
- name: "Alice Johnson", email: "alice@example.com", tier: "standard",
258
- });
259
-
260
- // ── 3. Place an order ─────────────────────────────────────────────
261
- const order = await db.collection("orders").write({
262
- customer_id: customer.id,
263
- items: [
264
- { product_id: shirt.id, qty: 2, unit_price: 29.99 },
265
- { product_id: shoes.id, qty: 1, unit_price: 89.99 },
266
- ],
267
- total: 149.97,
268
- status: "placed",
269
- });
270
-
271
- // Link order → customer in the graph
272
- await db.graph.relate(order.id, customer.id, "placed_by");
273
-
274
- // ── 4. Ship the order (append, never overwrite) ───────────────────
275
- await db.collection("orders").write({
276
- ...order, // same logical entity
277
- status: "shipped",
278
- tracking: "UPS-1Z999AA10123456784",
279
- shipped_at: new Date().toISOString(),
280
- });
281
-
282
- // ── 5. Audit: what was the order status 10 minutes ago? ───────────
283
- const tenMinutesAgo = new Date(Date.now() - 10 * 60_000).toISOString();
284
- const snapshot = await db
285
- .collection("orders")
286
- .asOf(tenMinutesAgo)
287
- .find({ customer_id: customer.id });
288
- // → returns the "placed" version, before it was shipped
289
-
290
- // ── 6. Graph: find everything this customer is connected to ───────
291
- const { nodes } = await db.graph.traverse(customer.id, {
292
- depth: 2, direction: "inbound",
293
- });
294
- // → returns the order records linked to this customer
295
- ```
package/dist/graph.d.ts DELETED
@@ -1,28 +0,0 @@
1
- import type { SapixClientConfig, GraphEdgeInput, GraphEdge, TraverseOptions, TraverseResult, NucleotideRecord } from "./types.js";
2
- export declare class GraphClient {
3
- private readonly config;
4
- constructor(config: SapixClientConfig);
5
- /** Create a directed edge between two records. */
6
- addEdge(edge: GraphEdgeInput): Promise<void>;
7
- /** Remove an edge between two records. */
8
- removeEdge(src: string, dst: string, edge_type: string): Promise<void>;
9
- /**
10
- * Traverse the graph from a starting node.
11
- * Returns all reachable nodes and the edges connecting them.
12
- */
13
- traverse(fromId: string, options?: TraverseOptions): Promise<TraverseResult>;
14
- /** Get all direct neighbours of a node. */
15
- neighbors(id: string, direction?: "outbound" | "inbound" | "both"): Promise<NucleotideRecord[]>;
16
- /** Get all outbound edges from a node. */
17
- edges(id: string): Promise<GraphEdge[]>;
18
- /**
19
- * Connect two records with a typed relationship.
20
- * Convenience wrapper around addEdge.
21
- *
22
- * @example
23
- * await db.graph.relate(orderId, customerId, "placed_by");
24
- * await db.graph.relate(productId, categoryId, "belongs_to");
25
- */
26
- relate(src: string, dst: string, type: string, weight?: number): Promise<void>;
27
- }
28
- //# sourceMappingURL=graph.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,eAAe,EACf,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAEtD,kDAAkD;IAC5C,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IASlD,0CAA0C;IACpC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E;;;OAGG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC;IAS1B,2CAA2C;IACrC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,UAAU,GAAG,SAAS,GAAG,MAAmB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAKjH,0CAA0C;IACpC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAK7C;;;;;;;OAOG;IACG,MAAM,CACV,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,SAAM,GACX,OAAO,CAAC,IAAI,CAAC;CAGjB"}
package/dist/graph.js DELETED
@@ -1,44 +0,0 @@
1
- import { request } from "./http.js";
2
- export class GraphClient {
3
- constructor(config) {
4
- this.config = config;
5
- }
6
- /** Create a directed edge between two records. */
7
- async addEdge(edge) {
8
- await request(this.config, "POST", `/v1/${this.config.agent}/graph/edge`, { ...edge, weight: edge.weight ?? 1.0 });
9
- }
10
- /** Remove an edge between two records. */
11
- async removeEdge(src, dst, edge_type) {
12
- await request(this.config, "DELETE", `/v1/${this.config.agent}/graph/edge`, { src, dst, edge_type });
13
- }
14
- /**
15
- * Traverse the graph from a starting node.
16
- * Returns all reachable nodes and the edges connecting them.
17
- */
18
- async traverse(fromId, options = {}) {
19
- const { depth = 1, direction = "outbound" } = options;
20
- return request(this.config, "GET", `/v1/${this.config.agent}/graph/traverse/${fromId}?depth=${depth}&direction=${direction}`);
21
- }
22
- /** Get all direct neighbours of a node. */
23
- async neighbors(id, direction = "outbound") {
24
- const result = await this.traverse(id, { depth: 1, direction });
25
- return result.nodes;
26
- }
27
- /** Get all outbound edges from a node. */
28
- async edges(id) {
29
- const result = await this.traverse(id, { depth: 1 });
30
- return result.edges;
31
- }
32
- /**
33
- * Connect two records with a typed relationship.
34
- * Convenience wrapper around addEdge.
35
- *
36
- * @example
37
- * await db.graph.relate(orderId, customerId, "placed_by");
38
- * await db.graph.relate(productId, categoryId, "belongs_to");
39
- */
40
- async relate(src, dst, type, weight = 1.0) {
41
- return this.addEdge({ src, dst, edge_type: type, weight });
42
- }
43
- }
44
- //# sourceMappingURL=graph.js.map
package/dist/graph.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,MAAM,OAAO,WAAW;IACtB,YAA6B,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;IAAG,CAAC;IAE1D,kDAAkD;IAClD,KAAK,CAAC,OAAO,CAAC,IAAoB;QAChC,MAAM,OAAO,CACX,IAAI,CAAC,MAAM,EACX,MAAM,EACN,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,aAAa,EACrC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE,CACxC,CAAC;IACJ,CAAC;IAED,0CAA0C;IAC1C,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,GAAW,EAAE,SAAiB;QAC1D,MAAM,OAAO,CACX,IAAI,CAAC,MAAM,EACX,QAAQ,EACR,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,aAAa,EACrC,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,CACxB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ,CACZ,MAAc,EACd,UAA2B,EAAE;QAE7B,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,SAAS,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC;QACtD,OAAO,OAAO,CACZ,IAAI,CAAC,MAAM,EACX,KAAK,EACL,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,mBAAmB,MAAM,UAAU,KAAK,cAAc,SAAS,EAAE,CAC1F,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,YAA6C,UAAU;QACjF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,0CAA0C;IAC1C,KAAK,CAAC,KAAK,CAAC,EAAU;QACpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CACV,GAAW,EACX,GAAW,EACX,IAAY,EACZ,MAAM,GAAG,GAAG;QAEZ,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF"}
package/dist/http.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { SapixClientConfig } from "./types.js";
2
- export declare function request<T>(config: SapixClientConfig, method: string, path: string, body?: unknown): Promise<T>;
3
- //# sourceMappingURL=http.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,wBAAsB,OAAO,CAAC,CAAC,EAC7B,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,CAAC,CAAC,CAqCZ"}
package/dist/http.js DELETED
@@ -1,42 +0,0 @@
1
- import { SapixError, SapixNetworkError } from "./errors.js";
2
- export async function request(config, method, path, body) {
3
- const url = `${config.url}${path}`;
4
- const headers = {
5
- "Content-Type": "application/json",
6
- ...config.headers,
7
- };
8
- let res;
9
- try {
10
- const opts = { method, headers };
11
- if (body !== undefined)
12
- opts.body = JSON.stringify(body);
13
- if (config.timeout) {
14
- const ac = new AbortController();
15
- const timer = setTimeout(() => ac.abort(), config.timeout);
16
- opts.signal = ac.signal;
17
- res = await fetch(url, opts);
18
- clearTimeout(timer);
19
- }
20
- else {
21
- res = await fetch(url, opts);
22
- }
23
- }
24
- catch (err) {
25
- throw new SapixNetworkError(err);
26
- }
27
- if (!res.ok) {
28
- let message = `HTTP ${res.status}`;
29
- let code;
30
- try {
31
- const body = await res.json();
32
- if (body.error)
33
- message = body.error;
34
- if (body.code)
35
- code = body.code;
36
- }
37
- catch { /* ignore parse error */ }
38
- throw new SapixError(message, res.status, code);
39
- }
40
- return res.json();
41
- }
42
- //# sourceMappingURL=http.js.map
package/dist/http.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG5D,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAyB,EACzB,MAAc,EACd,IAAY,EACZ,IAAc;IAEd,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;IACnC,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,GAAG,MAAM,CAAC,OAAO;KAClB,CAAC;IAEF,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC9C,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEzD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;YACxB,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,OAAO,GAAG,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QACnC,IAAI,IAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAuC,CAAC;YACnE,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;YACrC,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;QACpC,MAAM,IAAI,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;AAClC,CAAC"}