sapixdb 0.1.0 → 0.3.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.
@@ -0,0 +1,88 @@
1
+ import type { ApiKeyPatch, ApiKeyUsage, ApiKeyView, CheckpointResponse, CreateApiKeyRequest, CreateApiKeyResponse, ListApiKeysResponse } from "./types.js";
2
+ type Requester = <T>(method: string, path: string, body?: unknown) => Promise<T>;
3
+ /**
4
+ * Programmatic API key management.
5
+ * Requires a root key or a key with ``admin:api-keys`` scope.
6
+ *
7
+ * Obtain via ``SapixClient.admin``.
8
+ *
9
+ * @example
10
+ * const db = new SapixClient({ baseUrl: "http://localhost:7475",
11
+ * apiKey: process.env.SAPIX_ROOT_KEY });
12
+ *
13
+ * // Create a scoped key for an orders service
14
+ * const result = await db.admin.createKey({
15
+ * label: "orders-service-prod",
16
+ * scopes: ["write:agents/orders/records", "read:agents/orders/query"],
17
+ * rate_limit_rps: 500,
18
+ * });
19
+ * console.log(result.key); // save immediately — shown once
20
+ *
21
+ * // List all keys
22
+ * const { keys } = await db.admin.listKeys();
23
+ *
24
+ * // Update expiry
25
+ * await db.admin.updateKey(result.key_id, { expires_at_ms: Date.now() + 90 * 86_400_000 });
26
+ *
27
+ * // Remove rate limit
28
+ * await db.admin.updateKey(result.key_id, { rate_limit_rps: null });
29
+ *
30
+ * // Check usage
31
+ * const usage = await db.admin.keyUsage(result.key_id);
32
+ * console.log(usage.request_count_since_restart);
33
+ *
34
+ * // Revoke
35
+ * await db.admin.revokeKey(result.key_id);
36
+ */
37
+ export declare class AdminClient {
38
+ private readonly req;
39
+ constructor(req: Requester);
40
+ /** Return all API keys. Secrets are never included. */
41
+ listKeys(): Promise<ListApiKeysResponse>;
42
+ /**
43
+ * Create a new scoped API key.
44
+ *
45
+ * ``result.key`` contains the full secret and is returned **exactly once**.
46
+ *
47
+ * **Scope examples**
48
+ * ```
49
+ * ["admin:*"] // full operator access
50
+ * ["admin:api-keys"] // can manage keys only
51
+ * ["write:agents/orders/records",
52
+ * "read:agents/orders/query"] // scoped to one agent
53
+ * ["write:*", "read:*"] // all reads + writes
54
+ * ```
55
+ */
56
+ createKey(req: CreateApiKeyRequest): Promise<CreateApiKeyResponse>;
57
+ /** Fetch a single key by ID. Throws ``SapixError`` with status 404 if missing. */
58
+ getKey(keyId: string): Promise<ApiKeyView>;
59
+ /**
60
+ * Partially update a key. Only provided fields are changed.
61
+ *
62
+ * Set a nullable field to ``null`` to remove it:
63
+ * ```ts
64
+ * // Make key permanent (remove expiry)
65
+ * await db.admin.updateKey(id, { expires_at_ms: null });
66
+ *
67
+ * // Remove rate limit
68
+ * await db.admin.updateKey(id, { rate_limit_rps: null });
69
+ * ```
70
+ */
71
+ updateKey(keyId: string, patch: ApiKeyPatch): Promise<ApiKeyView>;
72
+ /** Revoke a key permanently. Immediately blocks all requests from it. */
73
+ revokeKey(keyId: string): Promise<void>;
74
+ /** Request count and last-used timestamp since the last agent restart. */
75
+ keyUsage(keyId: string): Promise<ApiKeyUsage>;
76
+ /**
77
+ * Seal and delete all agent WAL files so no plaintext remains on disk.
78
+ * Returns the number of agents checkpointed.
79
+ * Requires root key or `admin:*` scope.
80
+ *
81
+ * @example
82
+ * const result = await db.admin.checkpoint();
83
+ * console.log(`Sealed ${result.agents_checkpointed} agents`);
84
+ */
85
+ checkpoint(): Promise<CheckpointResponse>;
86
+ }
87
+ export {};
88
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,KAAK,SAAS,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAE3C,uDAAuD;IACvD,QAAQ,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIxC;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAIlE,kFAAkF;IAClF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI1C;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAIjE,yEAAyE;IACzE,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI7C;;;;;;;;OAQG;IACH,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;CAG1C"}
package/dist/admin.js ADDED
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Programmatic API key management.
3
+ * Requires a root key or a key with ``admin:api-keys`` scope.
4
+ *
5
+ * Obtain via ``SapixClient.admin``.
6
+ *
7
+ * @example
8
+ * const db = new SapixClient({ baseUrl: "http://localhost:7475",
9
+ * apiKey: process.env.SAPIX_ROOT_KEY });
10
+ *
11
+ * // Create a scoped key for an orders service
12
+ * const result = await db.admin.createKey({
13
+ * label: "orders-service-prod",
14
+ * scopes: ["write:agents/orders/records", "read:agents/orders/query"],
15
+ * rate_limit_rps: 500,
16
+ * });
17
+ * console.log(result.key); // save immediately — shown once
18
+ *
19
+ * // List all keys
20
+ * const { keys } = await db.admin.listKeys();
21
+ *
22
+ * // Update expiry
23
+ * await db.admin.updateKey(result.key_id, { expires_at_ms: Date.now() + 90 * 86_400_000 });
24
+ *
25
+ * // Remove rate limit
26
+ * await db.admin.updateKey(result.key_id, { rate_limit_rps: null });
27
+ *
28
+ * // Check usage
29
+ * const usage = await db.admin.keyUsage(result.key_id);
30
+ * console.log(usage.request_count_since_restart);
31
+ *
32
+ * // Revoke
33
+ * await db.admin.revokeKey(result.key_id);
34
+ */
35
+ export class AdminClient {
36
+ req;
37
+ constructor(req) {
38
+ this.req = req;
39
+ }
40
+ /** Return all API keys. Secrets are never included. */
41
+ listKeys() {
42
+ return this.req("GET", "/v1/admin/api-keys");
43
+ }
44
+ /**
45
+ * Create a new scoped API key.
46
+ *
47
+ * ``result.key`` contains the full secret and is returned **exactly once**.
48
+ *
49
+ * **Scope examples**
50
+ * ```
51
+ * ["admin:*"] // full operator access
52
+ * ["admin:api-keys"] // can manage keys only
53
+ * ["write:agents/orders/records",
54
+ * "read:agents/orders/query"] // scoped to one agent
55
+ * ["write:*", "read:*"] // all reads + writes
56
+ * ```
57
+ */
58
+ createKey(req) {
59
+ return this.req("POST", "/v1/admin/api-keys", req);
60
+ }
61
+ /** Fetch a single key by ID. Throws ``SapixError`` with status 404 if missing. */
62
+ getKey(keyId) {
63
+ return this.req("GET", `/v1/admin/api-keys/${keyId}`);
64
+ }
65
+ /**
66
+ * Partially update a key. Only provided fields are changed.
67
+ *
68
+ * Set a nullable field to ``null`` to remove it:
69
+ * ```ts
70
+ * // Make key permanent (remove expiry)
71
+ * await db.admin.updateKey(id, { expires_at_ms: null });
72
+ *
73
+ * // Remove rate limit
74
+ * await db.admin.updateKey(id, { rate_limit_rps: null });
75
+ * ```
76
+ */
77
+ updateKey(keyId, patch) {
78
+ return this.req("PATCH", `/v1/admin/api-keys/${keyId}`, patch);
79
+ }
80
+ /** Revoke a key permanently. Immediately blocks all requests from it. */
81
+ revokeKey(keyId) {
82
+ return this.req("DELETE", `/v1/admin/api-keys/${keyId}`);
83
+ }
84
+ /** Request count and last-used timestamp since the last agent restart. */
85
+ keyUsage(keyId) {
86
+ return this.req("GET", `/v1/admin/api-keys/${keyId}/usage`);
87
+ }
88
+ /**
89
+ * Seal and delete all agent WAL files so no plaintext remains on disk.
90
+ * Returns the number of agents checkpointed.
91
+ * Requires root key or `admin:*` scope.
92
+ *
93
+ * @example
94
+ * const result = await db.admin.checkpoint();
95
+ * console.log(`Sealed ${result.agents_checkpointed} agents`);
96
+ */
97
+ checkpoint() {
98
+ return this.req("POST", "/v1/control/checkpoint");
99
+ }
100
+ }
101
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,WAAW;IACO;IAA7B,YAA6B,GAAc;QAAd,QAAG,GAAH,GAAG,CAAW;IAAG,CAAC;IAE/C,uDAAuD;IACvD,QAAQ;QACN,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,GAAwB;QAChC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,kFAAkF;IAClF,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,KAAa,EAAE,KAAkB;QACzC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAsB,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;IACjE,CAAC;IAED,yEAAyE;IACzE,SAAS,CAAC,KAAa;QACrB,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,sBAAsB,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,0EAA0E;IAC1E,QAAQ,CAAC,KAAa;QACpB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;;;;OAQG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;IACpD,CAAC;CACF"}
package/dist/client.d.ts CHANGED
@@ -1,43 +1,99 @@
1
+ import { AdminClient } from "./admin.js";
1
2
  import { CollectionClient } from "./collection.js";
2
- import { GraphClient } from "./graph.js";
3
- import type { SapixClientConfig, HealthResponse, WriteResult } from "./types.js";
3
+ import type { StreamEvent, SubscribeOptions } from "./stream.js";
4
+ import type { AddEdgeRequest, AddRecordRefRequest, ChainHeadResponse, EdgeView, GenesisRequest, GenesisResponse, HealthResponse, QueryResult, RecordRefView, RecordView, SapixClientOptions, SaqlQuery, WriteResponse } from "./types.js";
4
5
  export declare class SapixClient {
5
- private readonly config;
6
- /** Graph traversal and edge management. */
7
- readonly graph: GraphClient;
8
- constructor(config: SapixClientConfig);
6
+ private readonly baseUrl;
7
+ private readonly timeoutMs;
8
+ private readonly _fetch;
9
+ private readonly authHeaders;
10
+ constructor(options: SapixClientOptions);
11
+ private request;
12
+ private toB64;
13
+ fromB64(b64: string): Uint8Array;
9
14
  /**
10
- * Access a collection. All reads and writes go through this.
15
+ * API key management create, list, update, revoke, and inspect usage.
16
+ * Requires a root key or a key with ``admin:api-keys`` scope.
11
17
  *
12
18
  * @example
13
- * const products = db.collection("products");
14
- * await products.write({ name: "T-Shirt", price: 29.99 });
15
- * const all = await products.latest();
19
+ * const result = await db.admin.createKey({
20
+ * label: "orders-service-prod",
21
+ * scopes: ["write:agents/orders/records", "read:agents/orders/query"],
22
+ * rate_limit_rps: 500,
23
+ * });
24
+ * console.log(result.key); // save immediately — shown once
25
+ */
26
+ get admin(): AdminClient;
27
+ /**
28
+ * Return a `CollectionClient` for a named SapixDB agent.
29
+ *
30
+ * Every named agent is an independent strand — a logical "table" scoped to
31
+ * its own keypair and access policy. Operations route to `/v1/agents/{name}/...`.
16
32
  *
17
- * // With TypeScript generics for full type safety:
18
- * const products = db.collection<Product>("products");
33
+ * @example
34
+ * const orders = db.collection("orders");
35
+ * const record = await orders.write({ total: 99.99 });
36
+ * const latest = await orders.latest({ limit: 20 });
37
+ * const one = await orders.findOne({ status: "pending" });
38
+ * const byHash = await orders.get(record.content_hash);
39
+ * const hist = await orders.history({ limit: 100 });
40
+ * const snap = await orders.asOf(record.timestamp_hlc).latest();
41
+ */
42
+ collection(name: string): CollectionClient;
43
+ /**
44
+ * Alias for `collection(name)` — preferred when thinking in SapixDB terms
45
+ * where each "table" is an agent.
19
46
  */
20
- collection<T = Record<string, unknown>>(name: string): CollectionClient<T>;
47
+ agent(name: string): CollectionClient;
48
+ health(): Promise<HealthResponse>;
49
+ genesis(req?: GenesisRequest): Promise<GenesisResponse>;
21
50
  /**
22
- * Ingest a record via the agent ingest endpoint.
23
- * Designed for AI agents, webhooks, and automated pipelines.
24
- * Supports optional dual-write to Supabase if configured on the server.
51
+ * Append a raw byte payload to the agent's strand.
52
+ * Encode your domain object before calling (e.g. with msgpackr or JSON.stringify).
53
+ */
54
+ write(payload: Uint8Array | string, flags?: number): Promise<WriteResponse>;
55
+ /**
56
+ * Convenience: JSON-encode `obj` and write it.
57
+ * Use `client.fromB64(record.payload_b64)` → `JSON.parse(...)` to decode on read.
58
+ */
59
+ writeJson(obj: unknown, flags?: number): Promise<WriteResponse>;
60
+ readByHash(contentHash: string): Promise<RecordView>;
61
+ chainHead(): Promise<ChainHeadResponse>;
62
+ query(q: SaqlQuery): Promise<QueryResult>;
63
+ queryLatest(limit?: number): Promise<QueryResult>;
64
+ queryTimeRange(fromTs: number, toTs: number): Promise<QueryResult>;
65
+ queryByHash(contentHash: string): Promise<QueryResult>;
66
+ queryChainHead(): Promise<QueryResult>;
67
+ addEdge(req: AddEdgeRequest): Promise<void>;
68
+ getEdges(agentId: string, opts?: {
69
+ direction?: "in" | "out";
70
+ edge_type?: string;
71
+ }): Promise<EdgeView[]>;
72
+ deleteEdge(src: string, edgeType: string, dst: string): Promise<void>;
73
+ addRecordRef(req: AddRecordRefRequest): Promise<void>;
74
+ getRecordRefs(agentId: string, contentHash: string): Promise<RecordRefView[]>;
75
+ /**
76
+ * Subscribe to realtime writes on a named agent via SSE.
77
+ * Returns an `EventSource` — call `.close()` to unsubscribe.
25
78
  *
26
79
  * @example
27
- * await db.ingest("ai_decisions", {
28
- * model: "gpt-4o",
29
- * action: "approve_loan",
30
- * confidence: 0.94,
31
- * reasoning: "Credit score 780, DTI 28%",
80
+ * const es = client.subscribeAgent("orders", (ev) => {
81
+ * console.log(ev.record_id, ev.payload);
32
82
  * });
83
+ * es.close();
33
84
  */
34
- ingest(collection: string, data: Record<string, unknown>): Promise<WriteResult>;
35
- /** Check that the SapixDB agent is reachable and running. */
36
- health(): Promise<HealthResponse>;
85
+ subscribeAgent(agentId: string, onEvent: (event: StreamEvent) => void, opts?: SubscribeOptions): EventSource;
37
86
  /**
38
- * Ping the agent. Returns true if healthy, false if unreachable.
39
- * Does not throw.
87
+ * Subscribe to realtime writes on all agents via SSE.
88
+ * Returns an `EventSource` — call `.close()` to unsubscribe.
89
+ *
90
+ * @example
91
+ * const es = client.subscribeGlobal((ev) => {
92
+ * console.log(ev.agent_id, ev.record_id);
93
+ * }, { agents: ["orders", "payments"] });
40
94
  */
41
- ping(): Promise<boolean>;
95
+ subscribeGlobal(onEvent: (event: StreamEvent) => void, opts?: SubscribeOptions & {
96
+ agents?: string[];
97
+ }): EventSource;
42
98
  }
43
99
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;gBAEhB,MAAM,EAAE,iBAAiB;IASrC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAI1E;;;;;;;;;;;;OAYG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IASrF,6DAA6D;IACvD,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAIvC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAQ/B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,61 +1,210 @@
1
- import { request } from "./http.js";
1
+ import { SapixError } from "./errors.js";
2
+ import { AdminClient } from "./admin.js";
2
3
  import { CollectionClient } from "./collection.js";
3
- import { GraphClient } from "./graph.js";
4
+ import { openAgentStream, openGlobalStream } from "./stream.js";
5
+ const DEFAULT_TIMEOUT_MS = 10_000;
4
6
  export class SapixClient {
5
- constructor(config) {
6
- this.config = {
7
- timeout: 10000,
8
- ...config,
9
- url: config.url.replace(/\/$/, ""),
10
- };
11
- this.graph = new GraphClient(this.config);
7
+ baseUrl;
8
+ timeoutMs;
9
+ _fetch;
10
+ authHeaders;
11
+ constructor(options) {
12
+ this.baseUrl = options.baseUrl.replace(/\/$/, "");
13
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
14
+ this._fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
15
+ this.authHeaders = {};
16
+ if (options.apiKey) {
17
+ this.authHeaders["Authorization"] = `Bearer ${options.apiKey}`;
18
+ }
19
+ if (options.callerId) {
20
+ this.authHeaders["X-Sapix-Caller"] = options.callerId;
21
+ }
22
+ }
23
+ // ── Internal helpers ──────────────────────────────────────────────────────
24
+ async request(method, path, body) {
25
+ const controller = new AbortController();
26
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
27
+ let resp;
28
+ try {
29
+ const baseHeaders = { ...this.authHeaders };
30
+ if (body !== undefined)
31
+ baseHeaders["content-type"] = "application/json";
32
+ const init = {
33
+ method,
34
+ headers: baseHeaders,
35
+ signal: controller.signal,
36
+ };
37
+ if (body !== undefined)
38
+ init.body = JSON.stringify(body);
39
+ resp = await this._fetch(`${this.baseUrl}${path}`, init);
40
+ }
41
+ finally {
42
+ clearTimeout(timer);
43
+ }
44
+ if (!resp.ok) {
45
+ throw await SapixError.fromResponse(resp);
46
+ }
47
+ if (resp.status === 204 || resp.headers.get("content-length") === "0") {
48
+ return undefined;
49
+ }
50
+ return resp.json();
51
+ }
52
+ toB64(payload) {
53
+ if (typeof payload === "string") {
54
+ return btoa(payload);
55
+ }
56
+ let binary = "";
57
+ for (let i = 0; i < payload.length; i++) {
58
+ binary += String.fromCharCode(payload[i]);
59
+ }
60
+ return btoa(binary);
61
+ }
62
+ fromB64(b64) {
63
+ const binary = atob(b64);
64
+ const bytes = new Uint8Array(binary.length);
65
+ for (let i = 0; i < binary.length; i++) {
66
+ bytes[i] = binary.charCodeAt(i);
67
+ }
68
+ return bytes;
12
69
  }
70
+ // ── Admin ─────────────────────────────────────────────────────────────────
13
71
  /**
14
- * Access a collection. All reads and writes go through this.
72
+ * API key management create, list, update, revoke, and inspect usage.
73
+ * Requires a root key or a key with ``admin:api-keys`` scope.
15
74
  *
16
75
  * @example
17
- * const products = db.collection("products");
18
- * await products.write({ name: "T-Shirt", price: 29.99 });
19
- * const all = await products.latest();
76
+ * const result = await db.admin.createKey({
77
+ * label: "orders-service-prod",
78
+ * scopes: ["write:agents/orders/records", "read:agents/orders/query"],
79
+ * rate_limit_rps: 500,
80
+ * });
81
+ * console.log(result.key); // save immediately — shown once
82
+ */
83
+ get admin() {
84
+ return new AdminClient(this.request.bind(this));
85
+ }
86
+ // ── Named agents (collections) ────────────────────────────────────────────
87
+ /**
88
+ * Return a `CollectionClient` for a named SapixDB agent.
89
+ *
90
+ * Every named agent is an independent strand — a logical "table" scoped to
91
+ * its own keypair and access policy. Operations route to `/v1/agents/{name}/...`.
20
92
  *
21
- * // With TypeScript generics for full type safety:
22
- * const products = db.collection<Product>("products");
93
+ * @example
94
+ * const orders = db.collection("orders");
95
+ * const record = await orders.write({ total: 99.99 });
96
+ * const latest = await orders.latest({ limit: 20 });
97
+ * const one = await orders.findOne({ status: "pending" });
98
+ * const byHash = await orders.get(record.content_hash);
99
+ * const hist = await orders.history({ limit: 100 });
100
+ * const snap = await orders.asOf(record.timestamp_hlc).latest();
23
101
  */
24
102
  collection(name) {
25
- return new CollectionClient(this.config, name);
103
+ return new CollectionClient(name, this.request.bind(this));
104
+ }
105
+ /**
106
+ * Alias for `collection(name)` — preferred when thinking in SapixDB terms
107
+ * where each "table" is an agent.
108
+ */
109
+ agent(name) {
110
+ return this.collection(name);
111
+ }
112
+ // ── Health ────────────────────────────────────────────────────────────────
113
+ health() {
114
+ return this.request("GET", "/v1/health");
115
+ }
116
+ // ── Genesis ───────────────────────────────────────────────────────────────
117
+ genesis(req = {}) {
118
+ return this.request("POST", "/v1/genesis", { zone: req.zone ?? "governed" });
26
119
  }
120
+ // ── Records ───────────────────────────────────────────────────────────────
27
121
  /**
28
- * Ingest a record via the agent ingest endpoint.
29
- * Designed for AI agents, webhooks, and automated pipelines.
30
- * Supports optional dual-write to Supabase if configured on the server.
122
+ * Append a raw byte payload to the agent's strand.
123
+ * Encode your domain object before calling (e.g. with msgpackr or JSON.stringify).
124
+ */
125
+ write(payload, flags = 0) {
126
+ return this.request("POST", "/v1/records", {
127
+ payload_b64: this.toB64(payload),
128
+ flags,
129
+ });
130
+ }
131
+ /**
132
+ * Convenience: JSON-encode `obj` and write it.
133
+ * Use `client.fromB64(record.payload_b64)` → `JSON.parse(...)` to decode on read.
134
+ */
135
+ writeJson(obj, flags = 0) {
136
+ return this.write(new TextEncoder().encode(JSON.stringify(obj)), flags);
137
+ }
138
+ readByHash(contentHash) {
139
+ return this.request("GET", `/v1/records/${contentHash}`);
140
+ }
141
+ chainHead() {
142
+ return this.request("GET", "/v1/strand/head");
143
+ }
144
+ // ── SaQL ─────────────────────────────────────────────────────────────────
145
+ query(q) {
146
+ return this.request("POST", "/v1/query", q);
147
+ }
148
+ queryLatest(limit = 10) {
149
+ return this.query({ type: "latest", limit });
150
+ }
151
+ queryTimeRange(fromTs, toTs) {
152
+ return this.query({ type: "time_range", from_ts: fromTs, to_ts: toTs });
153
+ }
154
+ queryByHash(contentHash) {
155
+ return this.query({ type: "hash", content_hash: contentHash });
156
+ }
157
+ queryChainHead() {
158
+ return this.query({ type: "chain_head" });
159
+ }
160
+ // ── Graph — edges ─────────────────────────────────────────────────────────
161
+ addEdge(req) {
162
+ return this.request("POST", "/v1/graph/edges", req);
163
+ }
164
+ getEdges(agentId, opts = {}) {
165
+ const params = new URLSearchParams();
166
+ if (opts.direction)
167
+ params.set("direction", opts.direction);
168
+ if (opts.edge_type)
169
+ params.set("edge_type", opts.edge_type);
170
+ const qs = params.size > 0 ? `?${params}` : "";
171
+ return this.request("GET", `/v1/graph/edges/${agentId}${qs}`);
172
+ }
173
+ deleteEdge(src, edgeType, dst) {
174
+ return this.request("DELETE", `/v1/graph/edges/${src}/${edgeType}/${dst}`);
175
+ }
176
+ // ── Graph — record refs ───────────────────────────────────────────────────
177
+ addRecordRef(req) {
178
+ return this.request("POST", "/v1/graph/refs", req);
179
+ }
180
+ getRecordRefs(agentId, contentHash) {
181
+ return this.request("GET", `/v1/graph/refs/${agentId}/${contentHash}`);
182
+ }
183
+ // ── Realtime SSE ──────────────────────────────────────────────────────────
184
+ /**
185
+ * Subscribe to realtime writes on a named agent via SSE.
186
+ * Returns an `EventSource` — call `.close()` to unsubscribe.
31
187
  *
32
188
  * @example
33
- * await db.ingest("ai_decisions", {
34
- * model: "gpt-4o",
35
- * action: "approve_loan",
36
- * confidence: 0.94,
37
- * reasoning: "Credit score 780, DTI 28%",
189
+ * const es = client.subscribeAgent("orders", (ev) => {
190
+ * console.log(ev.record_id, ev.payload);
38
191
  * });
192
+ * es.close();
39
193
  */
40
- async ingest(collection, data) {
41
- return request(this.config, "POST", `/v1/${this.config.agent}/ingest`, { collection, data });
42
- }
43
- /** Check that the SapixDB agent is reachable and running. */
44
- async health() {
45
- return request(this.config, "GET", "/v1/health");
194
+ subscribeAgent(agentId, onEvent, opts) {
195
+ return openAgentStream(this.baseUrl, agentId, onEvent, opts);
46
196
  }
47
197
  /**
48
- * Ping the agent. Returns true if healthy, false if unreachable.
49
- * Does not throw.
198
+ * Subscribe to realtime writes on all agents via SSE.
199
+ * Returns an `EventSource` — call `.close()` to unsubscribe.
200
+ *
201
+ * @example
202
+ * const es = client.subscribeGlobal((ev) => {
203
+ * console.log(ev.agent_id, ev.record_id);
204
+ * }, { agents: ["orders", "payments"] });
50
205
  */
51
- async ping() {
52
- try {
53
- const res = await this.health();
54
- return res.status === "ok";
55
- }
56
- catch {
57
- return false;
58
- }
206
+ subscribeGlobal(onEvent, opts) {
207
+ return openGlobalStream(this.baseUrl, onEvent, opts);
59
208
  }
60
209
  }
61
210
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAOzC,MAAM,OAAO,WAAW;IAMtB,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG;YACZ,OAAO,EAAE,KAAM;YACf,GAAG,MAAM;YACT,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SACnC,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;OAUG;IACH,UAAU,CAA8B,IAAY;QAClD,OAAO,IAAI,gBAAgB,CAAI,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,IAA6B;QAC5D,OAAO,OAAO,CACZ,IAAI,CAAC,MAAM,EACX,MAAM,EACN,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,SAAS,EACjC,EAAE,UAAU,EAAE,IAAI,EAAE,CACrB,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,MAAM;QACV,OAAO,OAAO,CAAiB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IACnE,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}