@voltmem/client 0.1.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 +87 -0
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -0
- package/dist/client.test.js +110 -0
- package/dist/client.test.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
- package/src/client.test.ts +131 -0
- package/src/index.ts +205 -0
- package/src/types.ts +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# `@voltmem/client`
|
|
2
|
+
|
|
3
|
+
Workers-safe TypeScript client for the [VoltMem HTTP sidecar](../../sidecar/README.md).
|
|
4
|
+
Zero runtime dependencies — uses global `fetch`.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
From this repo (path / file dependency):
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# in your TS app
|
|
12
|
+
npm install ../path/to/voltmem/clients/typescript
|
|
13
|
+
# or after build:
|
|
14
|
+
# "dependencies": { "@voltmem/client": "file:../voltmem/clients/typescript" }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd clients/typescript && npm install && npm run build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Not published to npm yet — use a local `file:` / workspace path.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { VoltMemClient } from "@voltmem/client";
|
|
27
|
+
|
|
28
|
+
const mem = new VoltMemClient({
|
|
29
|
+
baseUrl: env.VOLTMEM_URL, // e.g. https://voltmem.example.com
|
|
30
|
+
apiKey: env.VOLTMEM_API_KEY,
|
|
31
|
+
userId: user.id,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await mem.add("I prefer darker colors and minimal fits");
|
|
35
|
+
const hits = await mem.search("what colors does this user like?", { limit: 5 });
|
|
36
|
+
const stats = await mem.domainStats(); // prior calibration telemetry
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Cloudflare Worker
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { VoltMemClient } from "@voltmem/client";
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
46
|
+
const mem = new VoltMemClient({
|
|
47
|
+
baseUrl: env.VOLTMEM_URL,
|
|
48
|
+
apiKey: env.VOLTMEM_API_KEY,
|
|
49
|
+
userId: "alice",
|
|
50
|
+
});
|
|
51
|
+
const hits = await mem.search("style preferences");
|
|
52
|
+
return Response.json(hits);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Keep `VOLTMEM_API_KEY` in Worker secrets — never ship it to the browser.
|
|
58
|
+
|
|
59
|
+
### Multi-tenant
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const bob = mem.forUser("bob");
|
|
63
|
+
await bob.add("I prefer neon colors");
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
| Method | Sidecar |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `health()` | `GET /health` |
|
|
71
|
+
| `add(data, opts?)` | `POST /v1/users/{userId}/memories` |
|
|
72
|
+
| `search(q, opts?)` | `GET .../memories/search` |
|
|
73
|
+
| `getAll()` | `GET .../memories` |
|
|
74
|
+
| `get(id)` | `GET .../memories/{id}` |
|
|
75
|
+
| `delete(id)` | `DELETE .../memories/{id}` |
|
|
76
|
+
| `clear()` | `DELETE .../memories` |
|
|
77
|
+
| `summary()` | `GET .../summary` |
|
|
78
|
+
| `domainStats()` | `GET .../domain_stats` |
|
|
79
|
+
|
|
80
|
+
Errors throw `VoltMemError` with `.status` and `.body`.
|
|
81
|
+
|
|
82
|
+
## Develop
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install
|
|
86
|
+
npm test # tsc + node:test against mocked fetch
|
|
87
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mock, test } from "node:test";
|
|
3
|
+
import { VoltMemClient, VoltMemError } from "./index.js";
|
|
4
|
+
function jsonResponse(status, body) {
|
|
5
|
+
return new Response(JSON.stringify(body), {
|
|
6
|
+
status,
|
|
7
|
+
headers: { "Content-Type": "application/json" },
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
test("add / search / domainStats hit expected paths and headers", async () => {
|
|
11
|
+
const calls = [];
|
|
12
|
+
const fetchMock = mock.fn(async (input, init) => {
|
|
13
|
+
const url = String(input);
|
|
14
|
+
calls.push({ url, init });
|
|
15
|
+
if (url.endsWith("/memories") && init?.method === "POST") {
|
|
16
|
+
return jsonResponse(200, {
|
|
17
|
+
id: "m1",
|
|
18
|
+
memory: "I prefer darker colors",
|
|
19
|
+
action: "inserted",
|
|
20
|
+
domain: "style_preference",
|
|
21
|
+
detail: "",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (url.includes("/memories/search")) {
|
|
25
|
+
return jsonResponse(200, [
|
|
26
|
+
{
|
|
27
|
+
id: "m1",
|
|
28
|
+
memory: "I prefer darker colors",
|
|
29
|
+
domain: "style_preference",
|
|
30
|
+
source: "explicit_statement",
|
|
31
|
+
created_at: 1,
|
|
32
|
+
last_confirmed_at: 1,
|
|
33
|
+
score: 0.9,
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
if (url.endsWith("/domain_stats")) {
|
|
38
|
+
return jsonResponse(200, {
|
|
39
|
+
style_preference: { prior: 0.08, inserted: 1, audit_rate: 0 },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return jsonResponse(404, { detail: "unexpected" });
|
|
43
|
+
});
|
|
44
|
+
const client = new VoltMemClient({
|
|
45
|
+
baseUrl: "https://voltmem.example.com/",
|
|
46
|
+
apiKey: "secret",
|
|
47
|
+
userId: "alice",
|
|
48
|
+
fetch: fetchMock,
|
|
49
|
+
});
|
|
50
|
+
const added = await client.add("I prefer darker colors");
|
|
51
|
+
assert.equal(added.id, "m1");
|
|
52
|
+
const hits = await client.search("style preferences", { limit: 3 });
|
|
53
|
+
assert.equal(hits[0]?.domain, "style_preference");
|
|
54
|
+
const stats = await client.domainStats();
|
|
55
|
+
assert.equal(stats.style_preference?.prior, 0.08);
|
|
56
|
+
assert.equal(calls.length, 3);
|
|
57
|
+
assert.match(calls[0].url, /\/v1\/users\/alice\/memories$/);
|
|
58
|
+
assert.equal(calls[0].init?.method, "POST");
|
|
59
|
+
assert.equal((calls[0].init?.headers)["X-API-Key"], "secret");
|
|
60
|
+
assert.match(calls[1].url, /q=style\+preferences/);
|
|
61
|
+
assert.match(calls[1].url, /limit=3/);
|
|
62
|
+
assert.match(calls[2].url, /\/domain_stats$/);
|
|
63
|
+
});
|
|
64
|
+
test("health skips API key", async () => {
|
|
65
|
+
const fetchMock = mock.fn(async (_input, init) => {
|
|
66
|
+
const headers = init?.headers;
|
|
67
|
+
assert.equal(headers["X-API-Key"], undefined);
|
|
68
|
+
return jsonResponse(200, { status: "ok" });
|
|
69
|
+
});
|
|
70
|
+
const client = new VoltMemClient({
|
|
71
|
+
baseUrl: "https://voltmem.example.com",
|
|
72
|
+
apiKey: "secret",
|
|
73
|
+
fetch: fetchMock,
|
|
74
|
+
});
|
|
75
|
+
const health = await client.health();
|
|
76
|
+
assert.deepEqual(health, { status: "ok" });
|
|
77
|
+
});
|
|
78
|
+
test("throws VoltMemError on non-2xx", async () => {
|
|
79
|
+
const client = new VoltMemClient({
|
|
80
|
+
baseUrl: "https://voltmem.example.com",
|
|
81
|
+
userId: "alice",
|
|
82
|
+
fetch: (async () => jsonResponse(401, { detail: "invalid or missing X-API-Key" })),
|
|
83
|
+
});
|
|
84
|
+
await assert.rejects(() => client.getAll(), (err) => {
|
|
85
|
+
assert.ok(err instanceof VoltMemError);
|
|
86
|
+
assert.equal(err.status, 401);
|
|
87
|
+
return true;
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
test("forUser overrides tenant", async () => {
|
|
91
|
+
let seen = "";
|
|
92
|
+
const client = new VoltMemClient({
|
|
93
|
+
baseUrl: "https://voltmem.example.com",
|
|
94
|
+
userId: "alice",
|
|
95
|
+
fetch: (async (input) => {
|
|
96
|
+
seen = String(input);
|
|
97
|
+
return jsonResponse(200, []);
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
await client.forUser("bob").getAll();
|
|
101
|
+
assert.match(seen, /\/v1\/users\/bob\/memories$/);
|
|
102
|
+
});
|
|
103
|
+
test("requires userId", async () => {
|
|
104
|
+
const client = new VoltMemClient({
|
|
105
|
+
baseUrl: "https://voltmem.example.com",
|
|
106
|
+
fetch: (async () => jsonResponse(200, [])),
|
|
107
|
+
});
|
|
108
|
+
await assert.rejects(() => client.getAll(), /userId is required/);
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,SAAS,YAAY,CAAC,MAAc,EAAE,IAAa;IACjD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM;QACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAC;AACL,CAAC;AAED,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;IAC3E,MAAM,KAAK,GAA0D,EAAE,CAAC;IACxE,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,KAAwB,EAAE,IAAkB,EAAE,EAAE;QAC/E,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1B,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;YACzD,OAAO,YAAY,CAAC,GAAG,EAAE;gBACvB,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,wBAAwB;gBAChC,MAAM,EAAE,UAAU;gBAClB,MAAM,EAAE,kBAAkB;gBAC1B,MAAM,EAAE,EAAE;aACX,CAAC,CAAC;QACL,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACrC,OAAO,YAAY,CAAC,GAAG,EAAE;gBACvB;oBACE,EAAE,EAAE,IAAI;oBACR,MAAM,EAAE,wBAAwB;oBAChC,MAAM,EAAE,kBAAkB;oBAC1B,MAAM,EAAE,oBAAoB;oBAC5B,UAAU,EAAE,CAAC;oBACb,iBAAiB,EAAE,CAAC;oBACpB,KAAK,EAAE,GAAG;iBACX;aACF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAClC,OAAO,YAAY,CAAC,GAAG,EAAE;gBACvB,gBAAgB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;aAC9D,CAAC,CAAC;QACL,CAAC;QACD,OAAO,YAAY,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,OAAO,EAAE,8BAA8B;QACvC,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,SAAoC;KAC5C,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,CAAE,KAAwB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAEjD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAElD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IACzC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAElD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,EAAE,+BAA+B,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CACV,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,OAAkC,CAAA,CAAC,WAAW,CAAC,EAChE,QAAQ,CACT,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IACpD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAyB,EAAE,IAAkB,EAAE,EAAE;QAChF,MAAM,OAAO,GAAG,IAAI,EAAE,OAAiC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,CAAC;QAC9C,OAAO,YAAY,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,OAAO,EAAE,6BAA6B;QACtC,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,SAAoC;KAC5C,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACrC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;IAChD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,OAAO,EAAE,6BAA6B;QACtC,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CACjB,YAAY,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC,CAAiB;KACjF,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAClB,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EACrB,CAAC,GAAY,EAAE,EAAE;QACf,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAE,GAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC,CACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;IAC1C,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,OAAO,EAAE,6BAA6B;QACtC,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO,YAAY,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAiB;KACnB,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,6BAA6B,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;IACjC,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,OAAO,EAAE,6BAA6B;QACtC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,CAAC,CAAiB;KAC3D,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AddData, AddOptions, DomainStats, MemoryHit, MemoryItem, SearchOptions, UserOptions, VoltMemClientOptions, WriteResult } from "./types.js";
|
|
2
|
+
export type { AddData, AddOptions, DomainStat, DomainStats, MemoryHit, MemoryItem, Message, SearchOptions, UserOptions, VoltMemClientOptions, WriteResult, } from "./types.js";
|
|
3
|
+
export declare class VoltMemError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
readonly body: unknown;
|
|
6
|
+
constructor(message: string, status: number, body: unknown);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Thin fetch client for the VoltMem HTTP sidecar.
|
|
10
|
+
* Safe for Cloudflare Workers, Node 18+, Bun, and browsers (server-side preferred for API keys).
|
|
11
|
+
*/
|
|
12
|
+
export declare class VoltMemClient {
|
|
13
|
+
readonly baseUrl: string;
|
|
14
|
+
readonly apiKey: string | undefined;
|
|
15
|
+
readonly userId: string | undefined;
|
|
16
|
+
private readonly fetchImpl;
|
|
17
|
+
constructor(options: VoltMemClientOptions);
|
|
18
|
+
/** Bound client for another tenant (shares baseUrl / apiKey / fetch). */
|
|
19
|
+
forUser(userId: string): VoltMemClient;
|
|
20
|
+
health(): Promise<{
|
|
21
|
+
status: string;
|
|
22
|
+
}>;
|
|
23
|
+
add(data: AddData, options?: AddOptions): Promise<WriteResult | WriteResult[]>;
|
|
24
|
+
search(query: string, options?: SearchOptions): Promise<MemoryHit[]>;
|
|
25
|
+
getAll(options?: UserOptions): Promise<MemoryItem[]>;
|
|
26
|
+
get(memoryId: string, options?: UserOptions): Promise<MemoryItem>;
|
|
27
|
+
delete(memoryId: string, options?: UserOptions): Promise<{
|
|
28
|
+
deleted: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
clear(options?: UserOptions): Promise<{
|
|
31
|
+
cleared: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
summary(options?: UserOptions): Promise<Record<string, unknown>>;
|
|
34
|
+
domainStats(options?: UserOptions): Promise<DomainStats>;
|
|
35
|
+
private requireUserId;
|
|
36
|
+
private request;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,OAAO,EACP,UAAU,EACV,UAAU,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,OAAO,EACP,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,OAAO,EAAE,oBAAoB;IAOzC,yEAAyE;IACzE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAUhC,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAIrC,GAAG,CACP,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,WAAW,GAAG,WAAW,EAAE,CAAC;IAYjC,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,SAAS,EAAE,CAAC;IAajB,MAAM,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAQxD,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAQhB,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAQ1B,KAAK,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAQ/D,OAAO,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAQpE,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAQlE,OAAO,CAAC,aAAa;YAUP,OAAO;CAuCtB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export class VoltMemError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
body;
|
|
4
|
+
constructor(message, status, body) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "VoltMemError";
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.body = body;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Thin fetch client for the VoltMem HTTP sidecar.
|
|
13
|
+
* Safe for Cloudflare Workers, Node 18+, Bun, and browsers (server-side preferred for API keys).
|
|
14
|
+
*/
|
|
15
|
+
export class VoltMemClient {
|
|
16
|
+
baseUrl;
|
|
17
|
+
apiKey;
|
|
18
|
+
userId;
|
|
19
|
+
fetchImpl;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
22
|
+
this.apiKey = options.apiKey;
|
|
23
|
+
this.userId = options.userId;
|
|
24
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
25
|
+
}
|
|
26
|
+
/** Bound client for another tenant (shares baseUrl / apiKey / fetch). */
|
|
27
|
+
forUser(userId) {
|
|
28
|
+
const options = {
|
|
29
|
+
baseUrl: this.baseUrl,
|
|
30
|
+
userId,
|
|
31
|
+
fetch: this.fetchImpl,
|
|
32
|
+
};
|
|
33
|
+
if (this.apiKey !== undefined)
|
|
34
|
+
options.apiKey = this.apiKey;
|
|
35
|
+
return new VoltMemClient(options);
|
|
36
|
+
}
|
|
37
|
+
async health() {
|
|
38
|
+
return this.request("GET", "/health", { auth: false });
|
|
39
|
+
}
|
|
40
|
+
async add(data, options = {}) {
|
|
41
|
+
const userId = this.requireUserId(options.userId);
|
|
42
|
+
const body = { data };
|
|
43
|
+
if (options.source !== undefined)
|
|
44
|
+
body.source = options.source;
|
|
45
|
+
if (options.extract !== undefined)
|
|
46
|
+
body.extract = options.extract;
|
|
47
|
+
return this.request("POST", `/v1/users/${encodeURIComponent(userId)}/memories`, { body });
|
|
48
|
+
}
|
|
49
|
+
async search(query, options = {}) {
|
|
50
|
+
const userId = this.requireUserId(options.userId);
|
|
51
|
+
const params = new URLSearchParams({ q: query });
|
|
52
|
+
if (options.limit !== undefined)
|
|
53
|
+
params.set("limit", String(options.limit));
|
|
54
|
+
if (options.minScore !== undefined) {
|
|
55
|
+
params.set("min_score", String(options.minScore));
|
|
56
|
+
}
|
|
57
|
+
return this.request("GET", `/v1/users/${encodeURIComponent(userId)}/memories/search?${params}`);
|
|
58
|
+
}
|
|
59
|
+
async getAll(options = {}) {
|
|
60
|
+
const userId = this.requireUserId(options.userId);
|
|
61
|
+
return this.request("GET", `/v1/users/${encodeURIComponent(userId)}/memories`);
|
|
62
|
+
}
|
|
63
|
+
async get(memoryId, options = {}) {
|
|
64
|
+
const userId = this.requireUserId(options.userId);
|
|
65
|
+
return this.request("GET", `/v1/users/${encodeURIComponent(userId)}/memories/${encodeURIComponent(memoryId)}`);
|
|
66
|
+
}
|
|
67
|
+
async delete(memoryId, options = {}) {
|
|
68
|
+
const userId = this.requireUserId(options.userId);
|
|
69
|
+
return this.request("DELETE", `/v1/users/${encodeURIComponent(userId)}/memories/${encodeURIComponent(memoryId)}`);
|
|
70
|
+
}
|
|
71
|
+
async clear(options = {}) {
|
|
72
|
+
const userId = this.requireUserId(options.userId);
|
|
73
|
+
return this.request("DELETE", `/v1/users/${encodeURIComponent(userId)}/memories`);
|
|
74
|
+
}
|
|
75
|
+
async summary(options = {}) {
|
|
76
|
+
const userId = this.requireUserId(options.userId);
|
|
77
|
+
return this.request("GET", `/v1/users/${encodeURIComponent(userId)}/summary`);
|
|
78
|
+
}
|
|
79
|
+
async domainStats(options = {}) {
|
|
80
|
+
const userId = this.requireUserId(options.userId);
|
|
81
|
+
return this.request("GET", `/v1/users/${encodeURIComponent(userId)}/domain_stats`);
|
|
82
|
+
}
|
|
83
|
+
requireUserId(override) {
|
|
84
|
+
const userId = override ?? this.userId;
|
|
85
|
+
if (!userId) {
|
|
86
|
+
throw new Error("userId is required (pass VoltMemClientOptions.userId or per-call userId)");
|
|
87
|
+
}
|
|
88
|
+
return userId;
|
|
89
|
+
}
|
|
90
|
+
async request(method, path, opts = {}) {
|
|
91
|
+
const headers = {
|
|
92
|
+
Accept: "application/json",
|
|
93
|
+
};
|
|
94
|
+
if (opts.auth !== false && this.apiKey) {
|
|
95
|
+
headers["X-API-Key"] = this.apiKey;
|
|
96
|
+
}
|
|
97
|
+
const init = { method, headers };
|
|
98
|
+
if (opts.body !== undefined) {
|
|
99
|
+
headers["Content-Type"] = "application/json";
|
|
100
|
+
init.body = JSON.stringify(opts.body);
|
|
101
|
+
}
|
|
102
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
103
|
+
const text = await res.text();
|
|
104
|
+
let parsed = undefined;
|
|
105
|
+
if (text) {
|
|
106
|
+
try {
|
|
107
|
+
parsed = JSON.parse(text);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
parsed = text;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
throw new VoltMemError(`VoltMem ${method} ${path} failed (${res.status})`, res.status, parsed);
|
|
115
|
+
}
|
|
116
|
+
return parsed;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Types mirrored from the VoltMem Python sidecar JSON responses. */
|
|
2
|
+
export type Message = {
|
|
3
|
+
role: string;
|
|
4
|
+
content: string;
|
|
5
|
+
};
|
|
6
|
+
/** String fact, one chat message, or a list of messages (extractable). */
|
|
7
|
+
export type AddData = string | Message | Message[];
|
|
8
|
+
export type WriteResult = {
|
|
9
|
+
id: string;
|
|
10
|
+
memory: string;
|
|
11
|
+
action: string;
|
|
12
|
+
domain: string;
|
|
13
|
+
detail: string;
|
|
14
|
+
};
|
|
15
|
+
export type MemoryItem = {
|
|
16
|
+
id: string;
|
|
17
|
+
memory: string;
|
|
18
|
+
domain: string;
|
|
19
|
+
source: string;
|
|
20
|
+
created_at: number;
|
|
21
|
+
last_confirmed_at: number;
|
|
22
|
+
};
|
|
23
|
+
export type MemoryHit = MemoryItem & {
|
|
24
|
+
score: number;
|
|
25
|
+
};
|
|
26
|
+
export type DomainStat = {
|
|
27
|
+
prior?: number;
|
|
28
|
+
inserted?: number;
|
|
29
|
+
confirmed?: number;
|
|
30
|
+
logged_mismatch?: number;
|
|
31
|
+
audited?: number;
|
|
32
|
+
audit_rate?: number;
|
|
33
|
+
mismatch_rate?: number;
|
|
34
|
+
[key: string]: number | undefined;
|
|
35
|
+
};
|
|
36
|
+
export type DomainStats = Record<string, DomainStat>;
|
|
37
|
+
export type VoltMemClientOptions = {
|
|
38
|
+
/** Sidecar base URL, e.g. `https://voltmem.example.com` (no trailing slash required). */
|
|
39
|
+
baseUrl: string;
|
|
40
|
+
/** Sent as `X-API-Key` when the sidecar has `VOLTMEM_API_KEY` set. */
|
|
41
|
+
apiKey?: string;
|
|
42
|
+
/** Default tenant for convenience methods. */
|
|
43
|
+
userId?: string;
|
|
44
|
+
/** Override `globalThis.fetch` (tests / custom runtimes). */
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
};
|
|
47
|
+
export type AddOptions = {
|
|
48
|
+
source?: string;
|
|
49
|
+
extract?: boolean;
|
|
50
|
+
userId?: string;
|
|
51
|
+
};
|
|
52
|
+
export type SearchOptions = {
|
|
53
|
+
limit?: number;
|
|
54
|
+
minScore?: number;
|
|
55
|
+
userId?: string;
|
|
56
|
+
};
|
|
57
|
+
export type UserOptions = {
|
|
58
|
+
userId?: string;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qEAAqE;AAErE,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAAG;IACjC,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qEAAqE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voltmem/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Workers-safe TypeScript client for the VoltMem HTTP sidecar",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"test": "tsc -p tsconfig.json && node --test dist/client.test.js",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.15.0",
|
|
31
|
+
"typescript": "^5.9.3"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"voltmem",
|
|
35
|
+
"memory",
|
|
36
|
+
"llm",
|
|
37
|
+
"cloudflare-workers",
|
|
38
|
+
"typescript"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mock, test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import { VoltMemClient, VoltMemError } from "./index.js";
|
|
5
|
+
|
|
6
|
+
function jsonResponse(status: number, body: unknown): Response {
|
|
7
|
+
return new Response(JSON.stringify(body), {
|
|
8
|
+
status,
|
|
9
|
+
headers: { "Content-Type": "application/json" },
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
test("add / search / domainStats hit expected paths and headers", async () => {
|
|
14
|
+
const calls: Array<{ url: string; init: RequestInit | undefined }> = [];
|
|
15
|
+
const fetchMock = mock.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
16
|
+
const url = String(input);
|
|
17
|
+
calls.push({ url, init });
|
|
18
|
+
if (url.endsWith("/memories") && init?.method === "POST") {
|
|
19
|
+
return jsonResponse(200, {
|
|
20
|
+
id: "m1",
|
|
21
|
+
memory: "I prefer darker colors",
|
|
22
|
+
action: "inserted",
|
|
23
|
+
domain: "style_preference",
|
|
24
|
+
detail: "",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (url.includes("/memories/search")) {
|
|
28
|
+
return jsonResponse(200, [
|
|
29
|
+
{
|
|
30
|
+
id: "m1",
|
|
31
|
+
memory: "I prefer darker colors",
|
|
32
|
+
domain: "style_preference",
|
|
33
|
+
source: "explicit_statement",
|
|
34
|
+
created_at: 1,
|
|
35
|
+
last_confirmed_at: 1,
|
|
36
|
+
score: 0.9,
|
|
37
|
+
},
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
if (url.endsWith("/domain_stats")) {
|
|
41
|
+
return jsonResponse(200, {
|
|
42
|
+
style_preference: { prior: 0.08, inserted: 1, audit_rate: 0 },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return jsonResponse(404, { detail: "unexpected" });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const client = new VoltMemClient({
|
|
49
|
+
baseUrl: "https://voltmem.example.com/",
|
|
50
|
+
apiKey: "secret",
|
|
51
|
+
userId: "alice",
|
|
52
|
+
fetch: fetchMock as unknown as typeof fetch,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const added = await client.add("I prefer darker colors");
|
|
56
|
+
assert.equal((added as { id: string }).id, "m1");
|
|
57
|
+
|
|
58
|
+
const hits = await client.search("style preferences", { limit: 3 });
|
|
59
|
+
assert.equal(hits[0]?.domain, "style_preference");
|
|
60
|
+
|
|
61
|
+
const stats = await client.domainStats();
|
|
62
|
+
assert.equal(stats.style_preference?.prior, 0.08);
|
|
63
|
+
|
|
64
|
+
assert.equal(calls.length, 3);
|
|
65
|
+
assert.match(calls[0]!.url, /\/v1\/users\/alice\/memories$/);
|
|
66
|
+
assert.equal(calls[0]!.init?.method, "POST");
|
|
67
|
+
assert.equal(
|
|
68
|
+
(calls[0]!.init?.headers as Record<string, string>)["X-API-Key"],
|
|
69
|
+
"secret",
|
|
70
|
+
);
|
|
71
|
+
assert.match(calls[1]!.url, /q=style\+preferences/);
|
|
72
|
+
assert.match(calls[1]!.url, /limit=3/);
|
|
73
|
+
assert.match(calls[2]!.url, /\/domain_stats$/);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("health skips API key", async () => {
|
|
77
|
+
const fetchMock = mock.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
|
78
|
+
const headers = init?.headers as Record<string, string>;
|
|
79
|
+
assert.equal(headers["X-API-Key"], undefined);
|
|
80
|
+
return jsonResponse(200, { status: "ok" });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const client = new VoltMemClient({
|
|
84
|
+
baseUrl: "https://voltmem.example.com",
|
|
85
|
+
apiKey: "secret",
|
|
86
|
+
fetch: fetchMock as unknown as typeof fetch,
|
|
87
|
+
});
|
|
88
|
+
const health = await client.health();
|
|
89
|
+
assert.deepEqual(health, { status: "ok" });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("throws VoltMemError on non-2xx", async () => {
|
|
93
|
+
const client = new VoltMemClient({
|
|
94
|
+
baseUrl: "https://voltmem.example.com",
|
|
95
|
+
userId: "alice",
|
|
96
|
+
fetch: (async () =>
|
|
97
|
+
jsonResponse(401, { detail: "invalid or missing X-API-Key" })) as typeof fetch,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await assert.rejects(
|
|
101
|
+
() => client.getAll(),
|
|
102
|
+
(err: unknown) => {
|
|
103
|
+
assert.ok(err instanceof VoltMemError);
|
|
104
|
+
assert.equal((err as VoltMemError).status, 401);
|
|
105
|
+
return true;
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("forUser overrides tenant", async () => {
|
|
111
|
+
let seen = "";
|
|
112
|
+
const client = new VoltMemClient({
|
|
113
|
+
baseUrl: "https://voltmem.example.com",
|
|
114
|
+
userId: "alice",
|
|
115
|
+
fetch: (async (input) => {
|
|
116
|
+
seen = String(input);
|
|
117
|
+
return jsonResponse(200, []);
|
|
118
|
+
}) as typeof fetch,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await client.forUser("bob").getAll();
|
|
122
|
+
assert.match(seen, /\/v1\/users\/bob\/memories$/);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("requires userId", async () => {
|
|
126
|
+
const client = new VoltMemClient({
|
|
127
|
+
baseUrl: "https://voltmem.example.com",
|
|
128
|
+
fetch: (async () => jsonResponse(200, [])) as typeof fetch,
|
|
129
|
+
});
|
|
130
|
+
await assert.rejects(() => client.getAll(), /userId is required/);
|
|
131
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AddData,
|
|
3
|
+
AddOptions,
|
|
4
|
+
DomainStats,
|
|
5
|
+
MemoryHit,
|
|
6
|
+
MemoryItem,
|
|
7
|
+
SearchOptions,
|
|
8
|
+
UserOptions,
|
|
9
|
+
VoltMemClientOptions,
|
|
10
|
+
WriteResult,
|
|
11
|
+
} from "./types.js";
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
AddData,
|
|
15
|
+
AddOptions,
|
|
16
|
+
DomainStat,
|
|
17
|
+
DomainStats,
|
|
18
|
+
MemoryHit,
|
|
19
|
+
MemoryItem,
|
|
20
|
+
Message,
|
|
21
|
+
SearchOptions,
|
|
22
|
+
UserOptions,
|
|
23
|
+
VoltMemClientOptions,
|
|
24
|
+
WriteResult,
|
|
25
|
+
} from "./types.js";
|
|
26
|
+
|
|
27
|
+
export class VoltMemError extends Error {
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly body: unknown;
|
|
30
|
+
|
|
31
|
+
constructor(message: string, status: number, body: unknown) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "VoltMemError";
|
|
34
|
+
this.status = status;
|
|
35
|
+
this.body = body;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Thin fetch client for the VoltMem HTTP sidecar.
|
|
41
|
+
* Safe for Cloudflare Workers, Node 18+, Bun, and browsers (server-side preferred for API keys).
|
|
42
|
+
*/
|
|
43
|
+
export class VoltMemClient {
|
|
44
|
+
readonly baseUrl: string;
|
|
45
|
+
readonly apiKey: string | undefined;
|
|
46
|
+
readonly userId: string | undefined;
|
|
47
|
+
private readonly fetchImpl: typeof fetch;
|
|
48
|
+
|
|
49
|
+
constructor(options: VoltMemClientOptions) {
|
|
50
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
51
|
+
this.apiKey = options.apiKey;
|
|
52
|
+
this.userId = options.userId;
|
|
53
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Bound client for another tenant (shares baseUrl / apiKey / fetch). */
|
|
57
|
+
forUser(userId: string): VoltMemClient {
|
|
58
|
+
const options: VoltMemClientOptions = {
|
|
59
|
+
baseUrl: this.baseUrl,
|
|
60
|
+
userId,
|
|
61
|
+
fetch: this.fetchImpl,
|
|
62
|
+
};
|
|
63
|
+
if (this.apiKey !== undefined) options.apiKey = this.apiKey;
|
|
64
|
+
return new VoltMemClient(options);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async health(): Promise<{ status: string }> {
|
|
68
|
+
return this.request<{ status: string }>("GET", "/health", { auth: false });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async add(
|
|
72
|
+
data: AddData,
|
|
73
|
+
options: AddOptions = {},
|
|
74
|
+
): Promise<WriteResult | WriteResult[]> {
|
|
75
|
+
const userId = this.requireUserId(options.userId);
|
|
76
|
+
const body: Record<string, unknown> = { data };
|
|
77
|
+
if (options.source !== undefined) body.source = options.source;
|
|
78
|
+
if (options.extract !== undefined) body.extract = options.extract;
|
|
79
|
+
return this.request<WriteResult | WriteResult[]>(
|
|
80
|
+
"POST",
|
|
81
|
+
`/v1/users/${encodeURIComponent(userId)}/memories`,
|
|
82
|
+
{ body },
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async search(
|
|
87
|
+
query: string,
|
|
88
|
+
options: SearchOptions = {},
|
|
89
|
+
): Promise<MemoryHit[]> {
|
|
90
|
+
const userId = this.requireUserId(options.userId);
|
|
91
|
+
const params = new URLSearchParams({ q: query });
|
|
92
|
+
if (options.limit !== undefined) params.set("limit", String(options.limit));
|
|
93
|
+
if (options.minScore !== undefined) {
|
|
94
|
+
params.set("min_score", String(options.minScore));
|
|
95
|
+
}
|
|
96
|
+
return this.request<MemoryHit[]>(
|
|
97
|
+
"GET",
|
|
98
|
+
`/v1/users/${encodeURIComponent(userId)}/memories/search?${params}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async getAll(options: UserOptions = {}): Promise<MemoryItem[]> {
|
|
103
|
+
const userId = this.requireUserId(options.userId);
|
|
104
|
+
return this.request<MemoryItem[]>(
|
|
105
|
+
"GET",
|
|
106
|
+
`/v1/users/${encodeURIComponent(userId)}/memories`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async get(
|
|
111
|
+
memoryId: string,
|
|
112
|
+
options: UserOptions = {},
|
|
113
|
+
): Promise<MemoryItem> {
|
|
114
|
+
const userId = this.requireUserId(options.userId);
|
|
115
|
+
return this.request<MemoryItem>(
|
|
116
|
+
"GET",
|
|
117
|
+
`/v1/users/${encodeURIComponent(userId)}/memories/${encodeURIComponent(memoryId)}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async delete(
|
|
122
|
+
memoryId: string,
|
|
123
|
+
options: UserOptions = {},
|
|
124
|
+
): Promise<{ deleted: boolean }> {
|
|
125
|
+
const userId = this.requireUserId(options.userId);
|
|
126
|
+
return this.request<{ deleted: boolean }>(
|
|
127
|
+
"DELETE",
|
|
128
|
+
`/v1/users/${encodeURIComponent(userId)}/memories/${encodeURIComponent(memoryId)}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async clear(options: UserOptions = {}): Promise<{ cleared: boolean }> {
|
|
133
|
+
const userId = this.requireUserId(options.userId);
|
|
134
|
+
return this.request<{ cleared: boolean }>(
|
|
135
|
+
"DELETE",
|
|
136
|
+
`/v1/users/${encodeURIComponent(userId)}/memories`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async summary(options: UserOptions = {}): Promise<Record<string, unknown>> {
|
|
141
|
+
const userId = this.requireUserId(options.userId);
|
|
142
|
+
return this.request<Record<string, unknown>>(
|
|
143
|
+
"GET",
|
|
144
|
+
`/v1/users/${encodeURIComponent(userId)}/summary`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async domainStats(options: UserOptions = {}): Promise<DomainStats> {
|
|
149
|
+
const userId = this.requireUserId(options.userId);
|
|
150
|
+
return this.request<DomainStats>(
|
|
151
|
+
"GET",
|
|
152
|
+
`/v1/users/${encodeURIComponent(userId)}/domain_stats`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private requireUserId(override?: string): string {
|
|
157
|
+
const userId = override ?? this.userId;
|
|
158
|
+
if (!userId) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
"userId is required (pass VoltMemClientOptions.userId or per-call userId)",
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
return userId;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private async request<T>(
|
|
167
|
+
method: string,
|
|
168
|
+
path: string,
|
|
169
|
+
opts: { body?: unknown; auth?: boolean } = {},
|
|
170
|
+
): Promise<T> {
|
|
171
|
+
const headers: Record<string, string> = {
|
|
172
|
+
Accept: "application/json",
|
|
173
|
+
};
|
|
174
|
+
if (opts.auth !== false && this.apiKey) {
|
|
175
|
+
headers["X-API-Key"] = this.apiKey;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const init: RequestInit = { method, headers };
|
|
179
|
+
if (opts.body !== undefined) {
|
|
180
|
+
headers["Content-Type"] = "application/json";
|
|
181
|
+
init.body = JSON.stringify(opts.body);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
185
|
+
|
|
186
|
+
const text = await res.text();
|
|
187
|
+
let parsed: unknown = undefined;
|
|
188
|
+
if (text) {
|
|
189
|
+
try {
|
|
190
|
+
parsed = JSON.parse(text) as unknown;
|
|
191
|
+
} catch {
|
|
192
|
+
parsed = text;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!res.ok) {
|
|
197
|
+
throw new VoltMemError(
|
|
198
|
+
`VoltMem ${method} ${path} failed (${res.status})`,
|
|
199
|
+
res.status,
|
|
200
|
+
parsed,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return parsed as T;
|
|
204
|
+
}
|
|
205
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** Types mirrored from the VoltMem Python sidecar JSON responses. */
|
|
2
|
+
|
|
3
|
+
export type Message = {
|
|
4
|
+
role: string;
|
|
5
|
+
content: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/** String fact, one chat message, or a list of messages (extractable). */
|
|
9
|
+
export type AddData = string | Message | Message[];
|
|
10
|
+
|
|
11
|
+
export type WriteResult = {
|
|
12
|
+
id: string;
|
|
13
|
+
memory: string;
|
|
14
|
+
action: string;
|
|
15
|
+
domain: string;
|
|
16
|
+
detail: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type MemoryItem = {
|
|
20
|
+
id: string;
|
|
21
|
+
memory: string;
|
|
22
|
+
domain: string;
|
|
23
|
+
source: string;
|
|
24
|
+
created_at: number;
|
|
25
|
+
last_confirmed_at: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type MemoryHit = MemoryItem & {
|
|
29
|
+
score: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type DomainStat = {
|
|
33
|
+
prior?: number;
|
|
34
|
+
inserted?: number;
|
|
35
|
+
confirmed?: number;
|
|
36
|
+
logged_mismatch?: number;
|
|
37
|
+
audited?: number;
|
|
38
|
+
audit_rate?: number;
|
|
39
|
+
mismatch_rate?: number;
|
|
40
|
+
[key: string]: number | undefined;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type DomainStats = Record<string, DomainStat>;
|
|
44
|
+
|
|
45
|
+
export type VoltMemClientOptions = {
|
|
46
|
+
/** Sidecar base URL, e.g. `https://voltmem.example.com` (no trailing slash required). */
|
|
47
|
+
baseUrl: string;
|
|
48
|
+
/** Sent as `X-API-Key` when the sidecar has `VOLTMEM_API_KEY` set. */
|
|
49
|
+
apiKey?: string;
|
|
50
|
+
/** Default tenant for convenience methods. */
|
|
51
|
+
userId?: string;
|
|
52
|
+
/** Override `globalThis.fetch` (tests / custom runtimes). */
|
|
53
|
+
fetch?: typeof fetch;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type AddOptions = {
|
|
57
|
+
source?: string;
|
|
58
|
+
extract?: boolean;
|
|
59
|
+
userId?: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type SearchOptions = {
|
|
63
|
+
limit?: number;
|
|
64
|
+
minScore?: number;
|
|
65
|
+
userId?: string;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type UserOptions = {
|
|
69
|
+
userId?: string;
|
|
70
|
+
};
|