getmnemo 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/LICENSE +21 -0
- package/README.md +80 -0
- package/dist/index.cjs +192 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +114 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +187 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mnemo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @ledgermem/memory
|
|
2
|
+
|
|
3
|
+
Official TypeScript / JavaScript SDK for [LedgerMem Memory](https://proofly.dev) — long-term memory infrastructure for AI agents.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @ledgermem/memory
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Zero runtime dependencies. Works in Node 18+, Bun, Deno, browsers, Cloudflare Workers, and any other modern JS runtime with `fetch`.
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { LedgerMem } from '@ledgermem/memory'
|
|
15
|
+
|
|
16
|
+
const memory = new LedgerMem({
|
|
17
|
+
apiKey: process.env.LEDGERMEM_API_KEY!,
|
|
18
|
+
workspaceId: process.env.LEDGERMEM_WORKSPACE_ID!,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Store an atomic fact
|
|
22
|
+
await memory.add({ content: 'User prefers Japanese short-grain rice for onigiri.' })
|
|
23
|
+
|
|
24
|
+
// Retrieve relevant facts
|
|
25
|
+
const { hits } = await memory.search({ query: 'what kind of rice does the user like?' })
|
|
26
|
+
for (const hit of hits) {
|
|
27
|
+
console.log(hit.score.toFixed(2), hit.content)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API surface
|
|
32
|
+
|
|
33
|
+
| Method | Purpose |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `search({ query, limit?, actorId? })` | Hybrid 7-strategy retrieval. Returns `SearchResponse`. |
|
|
36
|
+
| `add({ content, metadata?, actorId? })` | Store an atomic fact. Returns `Memory`. |
|
|
37
|
+
| `update(id, { content?, metadata? })` | Patch existing memory. |
|
|
38
|
+
| `delete(id)` | Remove a memory. |
|
|
39
|
+
| `list({ limit?, cursor?, actorId? })` | Cursor-paginated list. |
|
|
40
|
+
|
|
41
|
+
## Errors
|
|
42
|
+
|
|
43
|
+
All HTTP failures throw `LedgerMemHTTPError` with `.status` and `.body`. Aborted requests throw `LedgerMemTimeoutError`. Both inherit from `LedgerMemError`.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { LedgerMem, LedgerMemHTTPError } from '@ledgermem/memory'
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await memory.search({ query: 'rice' })
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err instanceof LedgerMemHTTPError && err.status === 401) {
|
|
52
|
+
console.error('API key rejected:', err.body)
|
|
53
|
+
} else {
|
|
54
|
+
throw err
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
| Option | Default | Notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `apiKey` | (required) | from <https://app.proofly.dev/settings/api-keys> |
|
|
64
|
+
| `workspaceId` | (required) | from the dashboard URL |
|
|
65
|
+
| `actorId` | none | optional default actor scope |
|
|
66
|
+
| `baseUrl` | `https://api.proofly.dev` | override for self-hosted |
|
|
67
|
+
| `timeoutMs` | `30000` | per-request abort timeout |
|
|
68
|
+
| `fetch` | global `fetch` | inject for testing or proxying |
|
|
69
|
+
|
|
70
|
+
## Develop
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install
|
|
74
|
+
npm test
|
|
75
|
+
npm run build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var MnemoError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "MnemoError";
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var MnemoHTTPError = class extends MnemoError {
|
|
12
|
+
constructor(message, status, body) {
|
|
13
|
+
super(`[${status}] ${message}`);
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.body = body;
|
|
16
|
+
this.name = "MnemoHTTPError";
|
|
17
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
|
+
}
|
|
19
|
+
status;
|
|
20
|
+
body;
|
|
21
|
+
};
|
|
22
|
+
var MnemoTimeoutError = class extends MnemoError {
|
|
23
|
+
constructor(timeoutMs) {
|
|
24
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
25
|
+
this.name = "MnemoTimeoutError";
|
|
26
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// src/client.ts
|
|
31
|
+
var DEFAULT_BASE_URL = "https://api.getmnemo.xyz";
|
|
32
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
33
|
+
var SDK_VERSION = "0.1.0";
|
|
34
|
+
var USER_AGENT = `@mnemo/memory/${SDK_VERSION}`;
|
|
35
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
36
|
+
var RETRY_BASE_DELAY_MS = 200;
|
|
37
|
+
var RETRY_MAX_DELAY_MS = 5e3;
|
|
38
|
+
var IS_BROWSER_LIKE = typeof globalThis !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
typeof globalThis.window !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
typeof globalThis.document !== "undefined";
|
|
41
|
+
function retryDelayMs(attempt) {
|
|
42
|
+
const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);
|
|
43
|
+
return Math.floor(Math.random() * capped);
|
|
44
|
+
}
|
|
45
|
+
function isRetryableStatus(status) {
|
|
46
|
+
if (status === 501) return false;
|
|
47
|
+
return status === 429 || status >= 500 && status < 600;
|
|
48
|
+
}
|
|
49
|
+
function parseRetryAfterMs(headerValue) {
|
|
50
|
+
if (!headerValue) return null;
|
|
51
|
+
const trimmed = headerValue.trim();
|
|
52
|
+
const seconds = Number(trimmed);
|
|
53
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
54
|
+
return Math.min(seconds * 1e3, RETRY_MAX_DELAY_MS);
|
|
55
|
+
}
|
|
56
|
+
const epoch = Date.parse(trimmed);
|
|
57
|
+
if (!Number.isNaN(epoch)) {
|
|
58
|
+
const delta = epoch - Date.now();
|
|
59
|
+
return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS));
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function delayForResponse(res, attempt) {
|
|
64
|
+
const hint = parseRetryAfterMs(res.headers.get("retry-after"));
|
|
65
|
+
return hint !== null ? hint : retryDelayMs(attempt);
|
|
66
|
+
}
|
|
67
|
+
function sleep(ms) {
|
|
68
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
69
|
+
}
|
|
70
|
+
var Mnemo = class {
|
|
71
|
+
#baseUrl;
|
|
72
|
+
#headers;
|
|
73
|
+
#fetch;
|
|
74
|
+
#timeoutMs;
|
|
75
|
+
#maxRetries;
|
|
76
|
+
#defaultActorId;
|
|
77
|
+
constructor(cfg) {
|
|
78
|
+
if (!cfg.apiKey) throw new Error("Mnemo: apiKey is required");
|
|
79
|
+
if (!cfg.workspaceId) throw new Error("Mnemo: workspaceId is required");
|
|
80
|
+
this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
81
|
+
this.#headers = {
|
|
82
|
+
authorization: `Bearer ${cfg.apiKey}`,
|
|
83
|
+
"x-workspace-id": cfg.workspaceId,
|
|
84
|
+
"content-type": "application/json"
|
|
85
|
+
};
|
|
86
|
+
if (IS_BROWSER_LIKE) {
|
|
87
|
+
this.#headers["x-getmnemo-client"] = USER_AGENT;
|
|
88
|
+
} else {
|
|
89
|
+
this.#headers["user-agent"] = USER_AGENT;
|
|
90
|
+
}
|
|
91
|
+
if (cfg.actorId) this.#headers["x-actor-id"] = cfg.actorId;
|
|
92
|
+
this.#defaultActorId = cfg.actorId;
|
|
93
|
+
this.#fetch = cfg.fetch ?? fetch;
|
|
94
|
+
this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
95
|
+
this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
96
|
+
}
|
|
97
|
+
async search(input) {
|
|
98
|
+
return this.#request("POST", "/v1/search", {
|
|
99
|
+
query: input.query,
|
|
100
|
+
limit: input.limit ?? 8,
|
|
101
|
+
...input.actorId !== void 0 ? { actorId: input.actorId } : {}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async add(input) {
|
|
105
|
+
return this.#request("POST", "/v1/memories", {
|
|
106
|
+
content: input.content,
|
|
107
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {},
|
|
108
|
+
...input.actorId !== void 0 ? { actorId: input.actorId } : {}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async update(id, input) {
|
|
112
|
+
if (input.content === void 0 && input.metadata === void 0) {
|
|
113
|
+
throw new Error("Mnemo.update: at least one of content/metadata must be provided");
|
|
114
|
+
}
|
|
115
|
+
return this.#request("PATCH", `/v1/memories/${encodeURIComponent(id)}`, input);
|
|
116
|
+
}
|
|
117
|
+
async get(id) {
|
|
118
|
+
return this.#request("GET", `/v1/memories/${encodeURIComponent(id)}`);
|
|
119
|
+
}
|
|
120
|
+
async delete(id) {
|
|
121
|
+
await this.#request("DELETE", `/v1/memories/${encodeURIComponent(id)}`);
|
|
122
|
+
}
|
|
123
|
+
async list(input) {
|
|
124
|
+
const params = new URLSearchParams();
|
|
125
|
+
if (input?.limit !== void 0) params.set("limit", String(input.limit));
|
|
126
|
+
if (input?.cursor !== void 0) params.set("cursor", input.cursor);
|
|
127
|
+
if (input?.actorId !== void 0) params.set("actorId", input.actorId);
|
|
128
|
+
const qs = params.toString();
|
|
129
|
+
return this.#request("GET", `/v1/memories${qs ? `?${qs}` : ""}`);
|
|
130
|
+
}
|
|
131
|
+
/** Echoed back for debugging — never sent to the wire. */
|
|
132
|
+
get defaultActorId() {
|
|
133
|
+
return this.#defaultActorId;
|
|
134
|
+
}
|
|
135
|
+
async #request(method, path, body) {
|
|
136
|
+
const serializedBody = body === void 0 ? void 0 : JSON.stringify(body);
|
|
137
|
+
let lastErr;
|
|
138
|
+
for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {
|
|
139
|
+
const ctrl = new AbortController();
|
|
140
|
+
const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs);
|
|
141
|
+
try {
|
|
142
|
+
const res = await this.#fetch(`${this.#baseUrl}${path}`, {
|
|
143
|
+
method,
|
|
144
|
+
headers: { ...this.#headers },
|
|
145
|
+
body: serializedBody,
|
|
146
|
+
signal: ctrl.signal
|
|
147
|
+
});
|
|
148
|
+
if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {
|
|
149
|
+
const wait = delayForResponse(res, attempt);
|
|
150
|
+
await res.text().catch(() => void 0);
|
|
151
|
+
await sleep(wait);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const text = await res.text();
|
|
155
|
+
const parsed = text ? safeJson(text) : void 0;
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
const message = (parsed && typeof parsed === "object" && "message" in parsed ? String(parsed.message) : null) ?? `HTTP ${res.status} ${res.statusText}`;
|
|
158
|
+
throw new MnemoHTTPError(message, res.status, parsed);
|
|
159
|
+
}
|
|
160
|
+
return parsed;
|
|
161
|
+
} catch (err) {
|
|
162
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
163
|
+
throw new MnemoTimeoutError(this.#timeoutMs);
|
|
164
|
+
}
|
|
165
|
+
if (err instanceof MnemoHTTPError) throw err;
|
|
166
|
+
lastErr = err;
|
|
167
|
+
if (attempt < this.#maxRetries) {
|
|
168
|
+
await sleep(retryDelayMs(attempt));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
throw err;
|
|
172
|
+
} finally {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
throw lastErr ?? new Error("Mnemo: request failed");
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
function safeJson(s) {
|
|
180
|
+
try {
|
|
181
|
+
return JSON.parse(s);
|
|
182
|
+
} catch {
|
|
183
|
+
return s;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
exports.Mnemo = Mnemo;
|
|
188
|
+
exports.MnemoError = MnemoError;
|
|
189
|
+
exports.MnemoHTTPError = MnemoHTTPError;
|
|
190
|
+
exports.MnemoTimeoutError = MnemoTimeoutError;
|
|
191
|
+
//# sourceMappingURL=index.cjs.map
|
|
192
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from '@mnemo/memory'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.' })\n * const { hits } = await memory.search({ query: 'what rice does the user like?' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n ClientConfig,\n Memory,\n PaginatedMemories,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.getmnemo.xyz'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.0'\nconst USER_AGENT = `@mnemo/memory/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultActorId: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n if (cfg.actorId) this.#headers['x-actor-id'] = cfg.actorId\n this.#defaultActorId = cfg.actorId\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n async search(input: {\n query: string\n limit?: number\n actorId?: string\n }): Promise<SearchResponse> {\n return this.#request<SearchResponse>('POST', '/v1/search', {\n query: input.query,\n limit: input.limit ?? 8,\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async add(input: {\n content: string\n metadata?: Record<string, unknown>\n actorId?: string\n }): Promise<Memory> {\n return this.#request<Memory>('POST', '/v1/memories', {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async update(\n id: string,\n input: { content?: string; metadata?: Record<string, unknown> },\n ): Promise<Memory> {\n if (input.content === undefined && input.metadata === undefined) {\n throw new Error('Mnemo.update: at least one of content/metadata must be provided')\n }\n return this.#request<Memory>('PATCH', `/v1/memories/${encodeURIComponent(id)}`, input)\n }\n\n async get(id: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async delete(id: string): Promise<void> {\n await this.#request<unknown>('DELETE', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async list(input?: {\n limit?: number\n cursor?: string\n actorId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.actorId !== undefined) params.set('actorId', input.actorId)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultActorId(): string | undefined {\n return this.#defaultActorId\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the Mnemo SDK.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the REST API response shapes one-to-one. We deliberately keep
|
|
5
|
+
* them as plain interfaces (no zod runtime cost) — runtime validation is the
|
|
6
|
+
* caller's responsibility if they need it.
|
|
7
|
+
*/
|
|
8
|
+
type Memory = {
|
|
9
|
+
id: string;
|
|
10
|
+
content: string;
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
actorId?: string | null;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
};
|
|
17
|
+
type SearchSource = {
|
|
18
|
+
documentId?: string;
|
|
19
|
+
chunkId?: string;
|
|
20
|
+
};
|
|
21
|
+
type SearchHit = {
|
|
22
|
+
memoryId: string;
|
|
23
|
+
content: string;
|
|
24
|
+
score: number;
|
|
25
|
+
metadata?: Record<string, unknown>;
|
|
26
|
+
source?: SearchSource | null;
|
|
27
|
+
};
|
|
28
|
+
type SearchResponse = {
|
|
29
|
+
hits: SearchHit[];
|
|
30
|
+
query: string;
|
|
31
|
+
latencyMs: number;
|
|
32
|
+
};
|
|
33
|
+
type PaginatedMemories = {
|
|
34
|
+
items: Memory[];
|
|
35
|
+
nextCursor: string | null;
|
|
36
|
+
};
|
|
37
|
+
type ClientConfig = {
|
|
38
|
+
/** Required. Get one at https://app.getmnemo.xyz/settings/api-keys. */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
/** Required. Workspace ID from the dashboard URL. */
|
|
41
|
+
workspaceId: string;
|
|
42
|
+
/** Optional default actor scope for all calls (overridable per-method). */
|
|
43
|
+
actorId?: string;
|
|
44
|
+
/** Defaults to https://api.getmnemo.xyz. */
|
|
45
|
+
baseUrl?: string;
|
|
46
|
+
/** Per-request timeout in ms (default 30s). */
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
/** Inject a custom fetch — handy for testing or proxying. */
|
|
49
|
+
fetch?: typeof fetch;
|
|
50
|
+
/** Max retry attempts on 429/5xx and transient network errors (default 3). */
|
|
51
|
+
maxRetries?: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Mnemo Memory client.
|
|
56
|
+
*
|
|
57
|
+
* Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,
|
|
58
|
+
* Cloudflare Workers, Deno, etc).
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { Mnemo } from '@mnemo/memory'
|
|
63
|
+
*
|
|
64
|
+
* const memory = new Mnemo({
|
|
65
|
+
* apiKey: process.env.GETMNEMO_API_KEY!,
|
|
66
|
+
* workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
67
|
+
* })
|
|
68
|
+
*
|
|
69
|
+
* await memory.add({ content: 'User prefers Japanese rice.' })
|
|
70
|
+
* const { hits } = await memory.search({ query: 'what rice does the user like?' })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
declare class Mnemo {
|
|
75
|
+
#private;
|
|
76
|
+
constructor(cfg: ClientConfig);
|
|
77
|
+
search(input: {
|
|
78
|
+
query: string;
|
|
79
|
+
limit?: number;
|
|
80
|
+
actorId?: string;
|
|
81
|
+
}): Promise<SearchResponse>;
|
|
82
|
+
add(input: {
|
|
83
|
+
content: string;
|
|
84
|
+
metadata?: Record<string, unknown>;
|
|
85
|
+
actorId?: string;
|
|
86
|
+
}): Promise<Memory>;
|
|
87
|
+
update(id: string, input: {
|
|
88
|
+
content?: string;
|
|
89
|
+
metadata?: Record<string, unknown>;
|
|
90
|
+
}): Promise<Memory>;
|
|
91
|
+
get(id: string): Promise<Memory>;
|
|
92
|
+
delete(id: string): Promise<void>;
|
|
93
|
+
list(input?: {
|
|
94
|
+
limit?: number;
|
|
95
|
+
cursor?: string;
|
|
96
|
+
actorId?: string;
|
|
97
|
+
}): Promise<PaginatedMemories>;
|
|
98
|
+
/** Echoed back for debugging — never sent to the wire. */
|
|
99
|
+
get defaultActorId(): string | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare class MnemoError extends Error {
|
|
103
|
+
constructor(message: string);
|
|
104
|
+
}
|
|
105
|
+
declare class MnemoHTTPError extends MnemoError {
|
|
106
|
+
readonly status: number;
|
|
107
|
+
readonly body?: unknown | undefined;
|
|
108
|
+
constructor(message: string, status: number, body?: unknown | undefined);
|
|
109
|
+
}
|
|
110
|
+
declare class MnemoTimeoutError extends MnemoError {
|
|
111
|
+
constructor(timeoutMs: number);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { type ClientConfig, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type SearchHit, type SearchResponse, type SearchSource };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the Mnemo SDK.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the REST API response shapes one-to-one. We deliberately keep
|
|
5
|
+
* them as plain interfaces (no zod runtime cost) — runtime validation is the
|
|
6
|
+
* caller's responsibility if they need it.
|
|
7
|
+
*/
|
|
8
|
+
type Memory = {
|
|
9
|
+
id: string;
|
|
10
|
+
content: string;
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
actorId?: string | null;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
};
|
|
17
|
+
type SearchSource = {
|
|
18
|
+
documentId?: string;
|
|
19
|
+
chunkId?: string;
|
|
20
|
+
};
|
|
21
|
+
type SearchHit = {
|
|
22
|
+
memoryId: string;
|
|
23
|
+
content: string;
|
|
24
|
+
score: number;
|
|
25
|
+
metadata?: Record<string, unknown>;
|
|
26
|
+
source?: SearchSource | null;
|
|
27
|
+
};
|
|
28
|
+
type SearchResponse = {
|
|
29
|
+
hits: SearchHit[];
|
|
30
|
+
query: string;
|
|
31
|
+
latencyMs: number;
|
|
32
|
+
};
|
|
33
|
+
type PaginatedMemories = {
|
|
34
|
+
items: Memory[];
|
|
35
|
+
nextCursor: string | null;
|
|
36
|
+
};
|
|
37
|
+
type ClientConfig = {
|
|
38
|
+
/** Required. Get one at https://app.getmnemo.xyz/settings/api-keys. */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
/** Required. Workspace ID from the dashboard URL. */
|
|
41
|
+
workspaceId: string;
|
|
42
|
+
/** Optional default actor scope for all calls (overridable per-method). */
|
|
43
|
+
actorId?: string;
|
|
44
|
+
/** Defaults to https://api.getmnemo.xyz. */
|
|
45
|
+
baseUrl?: string;
|
|
46
|
+
/** Per-request timeout in ms (default 30s). */
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
/** Inject a custom fetch — handy for testing or proxying. */
|
|
49
|
+
fetch?: typeof fetch;
|
|
50
|
+
/** Max retry attempts on 429/5xx and transient network errors (default 3). */
|
|
51
|
+
maxRetries?: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Mnemo Memory client.
|
|
56
|
+
*
|
|
57
|
+
* Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,
|
|
58
|
+
* Cloudflare Workers, Deno, etc).
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { Mnemo } from '@mnemo/memory'
|
|
63
|
+
*
|
|
64
|
+
* const memory = new Mnemo({
|
|
65
|
+
* apiKey: process.env.GETMNEMO_API_KEY!,
|
|
66
|
+
* workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
67
|
+
* })
|
|
68
|
+
*
|
|
69
|
+
* await memory.add({ content: 'User prefers Japanese rice.' })
|
|
70
|
+
* const { hits } = await memory.search({ query: 'what rice does the user like?' })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
declare class Mnemo {
|
|
75
|
+
#private;
|
|
76
|
+
constructor(cfg: ClientConfig);
|
|
77
|
+
search(input: {
|
|
78
|
+
query: string;
|
|
79
|
+
limit?: number;
|
|
80
|
+
actorId?: string;
|
|
81
|
+
}): Promise<SearchResponse>;
|
|
82
|
+
add(input: {
|
|
83
|
+
content: string;
|
|
84
|
+
metadata?: Record<string, unknown>;
|
|
85
|
+
actorId?: string;
|
|
86
|
+
}): Promise<Memory>;
|
|
87
|
+
update(id: string, input: {
|
|
88
|
+
content?: string;
|
|
89
|
+
metadata?: Record<string, unknown>;
|
|
90
|
+
}): Promise<Memory>;
|
|
91
|
+
get(id: string): Promise<Memory>;
|
|
92
|
+
delete(id: string): Promise<void>;
|
|
93
|
+
list(input?: {
|
|
94
|
+
limit?: number;
|
|
95
|
+
cursor?: string;
|
|
96
|
+
actorId?: string;
|
|
97
|
+
}): Promise<PaginatedMemories>;
|
|
98
|
+
/** Echoed back for debugging — never sent to the wire. */
|
|
99
|
+
get defaultActorId(): string | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare class MnemoError extends Error {
|
|
103
|
+
constructor(message: string);
|
|
104
|
+
}
|
|
105
|
+
declare class MnemoHTTPError extends MnemoError {
|
|
106
|
+
readonly status: number;
|
|
107
|
+
readonly body?: unknown | undefined;
|
|
108
|
+
constructor(message: string, status: number, body?: unknown | undefined);
|
|
109
|
+
}
|
|
110
|
+
declare class MnemoTimeoutError extends MnemoError {
|
|
111
|
+
constructor(timeoutMs: number);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { type ClientConfig, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type SearchHit, type SearchResponse, type SearchSource };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var MnemoError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "MnemoError";
|
|
6
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var MnemoHTTPError = class extends MnemoError {
|
|
10
|
+
constructor(message, status, body) {
|
|
11
|
+
super(`[${status}] ${message}`);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.body = body;
|
|
14
|
+
this.name = "MnemoHTTPError";
|
|
15
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
16
|
+
}
|
|
17
|
+
status;
|
|
18
|
+
body;
|
|
19
|
+
};
|
|
20
|
+
var MnemoTimeoutError = class extends MnemoError {
|
|
21
|
+
constructor(timeoutMs) {
|
|
22
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
23
|
+
this.name = "MnemoTimeoutError";
|
|
24
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/client.ts
|
|
29
|
+
var DEFAULT_BASE_URL = "https://api.getmnemo.xyz";
|
|
30
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
31
|
+
var SDK_VERSION = "0.1.0";
|
|
32
|
+
var USER_AGENT = `@mnemo/memory/${SDK_VERSION}`;
|
|
33
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
34
|
+
var RETRY_BASE_DELAY_MS = 200;
|
|
35
|
+
var RETRY_MAX_DELAY_MS = 5e3;
|
|
36
|
+
var IS_BROWSER_LIKE = typeof globalThis !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
typeof globalThis.window !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
typeof globalThis.document !== "undefined";
|
|
39
|
+
function retryDelayMs(attempt) {
|
|
40
|
+
const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS);
|
|
41
|
+
return Math.floor(Math.random() * capped);
|
|
42
|
+
}
|
|
43
|
+
function isRetryableStatus(status) {
|
|
44
|
+
if (status === 501) return false;
|
|
45
|
+
return status === 429 || status >= 500 && status < 600;
|
|
46
|
+
}
|
|
47
|
+
function parseRetryAfterMs(headerValue) {
|
|
48
|
+
if (!headerValue) return null;
|
|
49
|
+
const trimmed = headerValue.trim();
|
|
50
|
+
const seconds = Number(trimmed);
|
|
51
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
52
|
+
return Math.min(seconds * 1e3, RETRY_MAX_DELAY_MS);
|
|
53
|
+
}
|
|
54
|
+
const epoch = Date.parse(trimmed);
|
|
55
|
+
if (!Number.isNaN(epoch)) {
|
|
56
|
+
const delta = epoch - Date.now();
|
|
57
|
+
return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS));
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function delayForResponse(res, attempt) {
|
|
62
|
+
const hint = parseRetryAfterMs(res.headers.get("retry-after"));
|
|
63
|
+
return hint !== null ? hint : retryDelayMs(attempt);
|
|
64
|
+
}
|
|
65
|
+
function sleep(ms) {
|
|
66
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
67
|
+
}
|
|
68
|
+
var Mnemo = class {
|
|
69
|
+
#baseUrl;
|
|
70
|
+
#headers;
|
|
71
|
+
#fetch;
|
|
72
|
+
#timeoutMs;
|
|
73
|
+
#maxRetries;
|
|
74
|
+
#defaultActorId;
|
|
75
|
+
constructor(cfg) {
|
|
76
|
+
if (!cfg.apiKey) throw new Error("Mnemo: apiKey is required");
|
|
77
|
+
if (!cfg.workspaceId) throw new Error("Mnemo: workspaceId is required");
|
|
78
|
+
this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
79
|
+
this.#headers = {
|
|
80
|
+
authorization: `Bearer ${cfg.apiKey}`,
|
|
81
|
+
"x-workspace-id": cfg.workspaceId,
|
|
82
|
+
"content-type": "application/json"
|
|
83
|
+
};
|
|
84
|
+
if (IS_BROWSER_LIKE) {
|
|
85
|
+
this.#headers["x-getmnemo-client"] = USER_AGENT;
|
|
86
|
+
} else {
|
|
87
|
+
this.#headers["user-agent"] = USER_AGENT;
|
|
88
|
+
}
|
|
89
|
+
if (cfg.actorId) this.#headers["x-actor-id"] = cfg.actorId;
|
|
90
|
+
this.#defaultActorId = cfg.actorId;
|
|
91
|
+
this.#fetch = cfg.fetch ?? fetch;
|
|
92
|
+
this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
93
|
+
this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
94
|
+
}
|
|
95
|
+
async search(input) {
|
|
96
|
+
return this.#request("POST", "/v1/search", {
|
|
97
|
+
query: input.query,
|
|
98
|
+
limit: input.limit ?? 8,
|
|
99
|
+
...input.actorId !== void 0 ? { actorId: input.actorId } : {}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async add(input) {
|
|
103
|
+
return this.#request("POST", "/v1/memories", {
|
|
104
|
+
content: input.content,
|
|
105
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {},
|
|
106
|
+
...input.actorId !== void 0 ? { actorId: input.actorId } : {}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async update(id, input) {
|
|
110
|
+
if (input.content === void 0 && input.metadata === void 0) {
|
|
111
|
+
throw new Error("Mnemo.update: at least one of content/metadata must be provided");
|
|
112
|
+
}
|
|
113
|
+
return this.#request("PATCH", `/v1/memories/${encodeURIComponent(id)}`, input);
|
|
114
|
+
}
|
|
115
|
+
async get(id) {
|
|
116
|
+
return this.#request("GET", `/v1/memories/${encodeURIComponent(id)}`);
|
|
117
|
+
}
|
|
118
|
+
async delete(id) {
|
|
119
|
+
await this.#request("DELETE", `/v1/memories/${encodeURIComponent(id)}`);
|
|
120
|
+
}
|
|
121
|
+
async list(input) {
|
|
122
|
+
const params = new URLSearchParams();
|
|
123
|
+
if (input?.limit !== void 0) params.set("limit", String(input.limit));
|
|
124
|
+
if (input?.cursor !== void 0) params.set("cursor", input.cursor);
|
|
125
|
+
if (input?.actorId !== void 0) params.set("actorId", input.actorId);
|
|
126
|
+
const qs = params.toString();
|
|
127
|
+
return this.#request("GET", `/v1/memories${qs ? `?${qs}` : ""}`);
|
|
128
|
+
}
|
|
129
|
+
/** Echoed back for debugging — never sent to the wire. */
|
|
130
|
+
get defaultActorId() {
|
|
131
|
+
return this.#defaultActorId;
|
|
132
|
+
}
|
|
133
|
+
async #request(method, path, body) {
|
|
134
|
+
const serializedBody = body === void 0 ? void 0 : JSON.stringify(body);
|
|
135
|
+
let lastErr;
|
|
136
|
+
for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {
|
|
137
|
+
const ctrl = new AbortController();
|
|
138
|
+
const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs);
|
|
139
|
+
try {
|
|
140
|
+
const res = await this.#fetch(`${this.#baseUrl}${path}`, {
|
|
141
|
+
method,
|
|
142
|
+
headers: { ...this.#headers },
|
|
143
|
+
body: serializedBody,
|
|
144
|
+
signal: ctrl.signal
|
|
145
|
+
});
|
|
146
|
+
if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {
|
|
147
|
+
const wait = delayForResponse(res, attempt);
|
|
148
|
+
await res.text().catch(() => void 0);
|
|
149
|
+
await sleep(wait);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const text = await res.text();
|
|
153
|
+
const parsed = text ? safeJson(text) : void 0;
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
const message = (parsed && typeof parsed === "object" && "message" in parsed ? String(parsed.message) : null) ?? `HTTP ${res.status} ${res.statusText}`;
|
|
156
|
+
throw new MnemoHTTPError(message, res.status, parsed);
|
|
157
|
+
}
|
|
158
|
+
return parsed;
|
|
159
|
+
} catch (err) {
|
|
160
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
161
|
+
throw new MnemoTimeoutError(this.#timeoutMs);
|
|
162
|
+
}
|
|
163
|
+
if (err instanceof MnemoHTTPError) throw err;
|
|
164
|
+
lastErr = err;
|
|
165
|
+
if (attempt < this.#maxRetries) {
|
|
166
|
+
await sleep(retryDelayMs(attempt));
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
throw err;
|
|
170
|
+
} finally {
|
|
171
|
+
clearTimeout(timer);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
throw lastErr ?? new Error("Mnemo: request failed");
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
function safeJson(s) {
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(s);
|
|
180
|
+
} catch {
|
|
181
|
+
return s;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export { Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError };
|
|
186
|
+
//# sourceMappingURL=index.js.map
|
|
187
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":";AAAO,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EACpC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AACZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;AAEO,IAAM,cAAA,GAAN,cAA6B,UAAA,CAAW;AAAA,EAC7C,WAAA,CACE,OAAA,EACS,MAAA,EACA,IAAA,EACT;AACA,IAAA,KAAA,CAAM,CAAA,CAAA,EAAI,MAAM,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AAHrB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAGT,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AAAA,EANW,MAAA;AAAA,EACA,IAAA;AAMb;AAEO,IAAM,iBAAA,GAAN,cAAgC,UAAA,CAAW;AAAA,EAChD,YAAY,SAAA,EAAmB;AAC7B,IAAA,KAAA,CAAM,CAAA,wBAAA,EAA2B,SAAS,CAAA,EAAA,CAAI,CAAA;AAC9C,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AACZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;;;ACEA,IAAM,gBAAA,GAAmB,0BAAA;AACzB,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,WAAA,GAAc,OAAA;AACpB,IAAM,UAAA,GAAa,iBAAiB,WAAW,CAAA,CAAA;AAC/C,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,kBAAA,GAAqB,GAAA;AAI3B,IAAM,eAAA,GACJ,OAAO,UAAA,KAAe,WAAA;AAEtB,OAAQ,WAAmB,MAAA,KAAW,WAAA;AAEtC,OAAQ,WAAmB,QAAA,KAAa,WAAA;AAE1C,SAAS,aAAa,OAAA,EAAyB;AAC7C,EAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,mBAAA,GAAsB,CAAA,IAAK,SAAS,kBAAkB,CAAA;AAE9E,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,MAAM,CAAA;AAC1C;AAEA,SAAS,kBAAkB,MAAA,EAAyB;AAElD,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,KAAA;AAC3B,EAAA,OAAO,MAAA,KAAW,GAAA,IAAQ,MAAA,IAAU,GAAA,IAAO,MAAA,GAAS,GAAA;AACtD;AAEA,SAAS,kBAAkB,WAAA,EAA2C;AACpE,EAAA,IAAI,CAAC,aAAa,OAAO,IAAA;AACzB,EAAA,MAAM,OAAA,GAAU,YAAY,IAAA,EAAK;AAEjC,EAAA,MAAM,OAAA,GAAU,OAAO,OAAO,CAAA;AAC9B,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,IAAK,WAAW,CAAA,EAAG;AAC5C,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,OAAA,GAAU,GAAA,EAAM,kBAAkB,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAChC,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,IAAA,CAAK,GAAA,EAAI;AAC/B,IAAA,OAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,KAAA,EAAO,kBAAkB,CAAC,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,gBAAA,CAAiB,KAAe,OAAA,EAAyB;AAChE,EAAA,MAAM,OAAO,iBAAA,CAAkB,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAC,CAAA;AAC7D,EAAA,OAAO,IAAA,KAAS,IAAA,GAAO,IAAA,GAAO,YAAA,CAAa,OAAO,CAAA;AACpD;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEO,IAAM,QAAN,MAAY;AAAA,EACR,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,eAAA;AAAA,EAET,YAAY,GAAA,EAAmB;AAC7B,IAAA,IAAI,CAAC,GAAA,CAAI,MAAA,EAAQ,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAC5D,IAAA,IAAI,CAAC,GAAA,CAAI,WAAA,EAAa,MAAM,IAAI,MAAM,gCAAgC,CAAA;AACtE,IAAA,IAAA,CAAK,YAAY,GAAA,CAAI,OAAA,IAAW,gBAAA,EAAkB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACnE,IAAA,IAAA,CAAK,QAAA,GAAW;AAAA,MACd,aAAA,EAAe,CAAA,OAAA,EAAU,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,MACnC,kBAAkB,GAAA,CAAI,WAAA;AAAA,MACtB,cAAA,EAAgB;AAAA,KAClB;AAIA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,IAAA,CAAK,QAAA,CAAS,mBAAmB,CAAA,GAAI,UAAA;AAAA,IACvC,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA,GAAI,UAAA;AAAA,IAChC;AACA,IAAA,IAAI,IAAI,OAAA,EAAS,IAAA,CAAK,QAAA,CAAS,YAAY,IAAI,GAAA,CAAI,OAAA;AACnD,IAAA,IAAA,CAAK,kBAAkB,GAAA,CAAI,OAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,KAAA,IAAS,KAAA;AAC3B,IAAA,IAAA,CAAK,UAAA,GAAa,IAAI,SAAA,IAAa,kBAAA;AACnC,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAA,CAAI,cAAc,mBAAmB,CAAA;AAAA,EACtE;AAAA,EAEA,MAAM,OAAO,KAAA,EAIe;AAC1B,IAAA,OAAO,IAAA,CAAK,QAAA,CAAyB,MAAA,EAAQ,YAAA,EAAc;AAAA,MACzD,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,KAAA,EAAO,MAAM,KAAA,IAAS,CAAA;AAAA,MACtB,GAAI,MAAM,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAQ,GAAI;AAAC,KACjE,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,IAAI,KAAA,EAIU;AAClB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAiB,MAAA,EAAQ,cAAA,EAAgB;AAAA,MACnD,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,GAAI,MAAM,QAAA,KAAa,MAAA,GAAY,EAAE,QAAA,EAAU,KAAA,CAAM,QAAA,EAAS,GAAI,EAAC;AAAA,MACnE,GAAI,MAAM,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAQ,GAAI;AAAC,KACjE,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,MAAA,CACJ,EAAA,EACA,KAAA,EACiB;AACjB,IAAA,IAAI,KAAA,CAAM,OAAA,KAAY,MAAA,IAAa,KAAA,CAAM,aAAa,MAAA,EAAW;AAC/D,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,OAAO,IAAA,CAAK,SAAiB,OAAA,EAAS,CAAA,aAAA,EAAgB,mBAAmB,EAAE,CAAC,IAAI,KAAK,CAAA;AAAA,EACvF;AAAA,EAEA,MAAM,IAAI,EAAA,EAA6B;AACrC,IAAA,OAAO,KAAK,QAAA,CAAiB,KAAA,EAAO,gBAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAE,CAAA;AAAA,EAC9E;AAAA,EAEA,MAAM,OAAO,EAAA,EAA2B;AACtC,IAAA,MAAM,KAAK,QAAA,CAAkB,QAAA,EAAU,gBAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAE,CAAA;AAAA,EACjF;AAAA,EAEA,MAAM,KAAK,KAAA,EAIoB;AAC7B,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,IAAA,IAAI,KAAA,EAAO,UAAU,MAAA,EAAW,MAAA,CAAO,IAAI,OAAA,EAAS,MAAA,CAAO,KAAA,CAAM,KAAK,CAAC,CAAA;AACvE,IAAA,IAAI,OAAO,MAAA,KAAW,MAAA,SAAkB,GAAA,CAAI,QAAA,EAAU,MAAM,MAAM,CAAA;AAClE,IAAA,IAAI,OAAO,OAAA,KAAY,MAAA,SAAkB,GAAA,CAAI,SAAA,EAAW,MAAM,OAAO,CAAA;AACrE,IAAA,MAAM,EAAA,GAAK,OAAO,QAAA,EAAS;AAC3B,IAAA,OAAO,IAAA,CAAK,SAA4B,KAAA,EAAO,CAAA,YAAA,EAAe,KAAK,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,GAAK,EAAE,CAAA,CAAE,CAAA;AAAA,EACpF;AAAA;AAAA,EAGA,IAAI,cAAA,GAAqC;AACvC,IAAA,OAAO,IAAA,CAAK,eAAA;AAAA,EACd;AAAA,EAEA,MAAM,QAAA,CAAY,MAAA,EAAgB,IAAA,EAAc,IAAA,EAA4B;AAC1E,IAAA,MAAM,iBAAiB,IAAA,KAAS,MAAA,GAAY,MAAA,GAAY,IAAA,CAAK,UAAU,IAAI,CAAA;AAC3E,IAAA,IAAI,OAAA;AACJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,IAAA,CAAK,aAAa,OAAA,EAAA,EAAW;AAC5D,MAAA,MAAM,IAAA,GAAO,IAAI,eAAA,EAAgB;AACjC,MAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,UAAU,CAAA;AAC5D,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,GAAG,IAAA,CAAK,QAAQ,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI;AAAA,UACvD,MAAA;AAAA,UACA,OAAA,EAAS,EAAE,GAAG,IAAA,CAAK,QAAA,EAAS;AAAA,UAC5B,IAAA,EAAM,cAAA;AAAA,UACN,QAAQ,IAAA,CAAK;AAAA,SACd,CAAA;AACD,QAAA,IAAI,kBAAkB,GAAA,CAAI,MAAM,CAAA,IAAK,OAAA,GAAU,KAAK,WAAA,EAAa;AAG/D,UAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE1C,UAAA,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AACtC,UAAA,MAAM,MAAM,IAAI,CAAA;AAChB,UAAA;AAAA,QACF;AACA,QAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,QAAA,MAAM,MAAA,GAAkB,IAAA,GAAO,QAAA,CAAS,IAAI,CAAA,GAAI,KAAA,CAAA;AAChD,QAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,UAAA,MAAM,WACH,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,aAAa,MAAA,GAClD,MAAA,CAAQ,MAAA,CAAgC,OAAO,IAC/C,IAAA,KAAS,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,CAAA,EAAI,IAAI,UAAU,CAAA,CAAA;AACnD,UAAA,MAAM,IAAI,cAAA,CAAe,OAAA,EAAS,GAAA,CAAI,QAAQ,MAAM,CAAA;AAAA,QACtD;AACA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,GAAA,YAAe,KAAA,IAAS,GAAA,CAAI,IAAA,KAAS,YAAA,EAAc;AACrD,UAAA,MAAM,IAAI,iBAAA,CAAkB,IAAA,CAAK,UAAU,CAAA;AAAA,QAC7C;AACA,QAAA,IAAI,GAAA,YAAe,gBAAgB,MAAM,GAAA;AACzC,QAAA,OAAA,GAAU,GAAA;AACV,QAAA,IAAI,OAAA,GAAU,KAAK,WAAA,EAAa;AAC9B,UAAA,MAAM,KAAA,CAAM,YAAA,CAAa,OAAO,CAAC,CAAA;AACjC,UAAA;AAAA,QACF;AACA,QAAA,MAAM,GAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB;AAAA,IACF;AACA,IAAA,MAAM,OAAA,IAAW,IAAI,KAAA,CAAM,uBAAuB,CAAA;AAAA,EACpD;AACF;AAEA,SAAS,SAAS,CAAA,EAAoB;AACpC,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,EACrB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAA;AAAA,EACT;AACF","file":"index.js","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from '@mnemo/memory'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.' })\n * const { hits } = await memory.search({ query: 'what rice does the user like?' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n ClientConfig,\n Memory,\n PaginatedMemories,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.getmnemo.xyz'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.0'\nconst USER_AGENT = `@mnemo/memory/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultActorId: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n if (cfg.actorId) this.#headers['x-actor-id'] = cfg.actorId\n this.#defaultActorId = cfg.actorId\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n async search(input: {\n query: string\n limit?: number\n actorId?: string\n }): Promise<SearchResponse> {\n return this.#request<SearchResponse>('POST', '/v1/search', {\n query: input.query,\n limit: input.limit ?? 8,\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async add(input: {\n content: string\n metadata?: Record<string, unknown>\n actorId?: string\n }): Promise<Memory> {\n return this.#request<Memory>('POST', '/v1/memories', {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async update(\n id: string,\n input: { content?: string; metadata?: Record<string, unknown> },\n ): Promise<Memory> {\n if (input.content === undefined && input.metadata === undefined) {\n throw new Error('Mnemo.update: at least one of content/metadata must be provided')\n }\n return this.#request<Memory>('PATCH', `/v1/memories/${encodeURIComponent(id)}`, input)\n }\n\n async get(id: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async delete(id: string): Promise<void> {\n await this.#request<unknown>('DELETE', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async list(input?: {\n limit?: number\n cursor?: string\n actorId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.actorId !== undefined) params.set('actorId', input.actorId)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultActorId(): string | undefined {\n return this.#defaultActorId\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "getmnemo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript / JavaScript SDK for Mnemo Memory — long-term memory infrastructure for AI agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"dev": "tsup --watch",
|
|
28
|
+
"lint": "eslint src",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"mnemo",
|
|
35
|
+
"memory",
|
|
36
|
+
"ai",
|
|
37
|
+
"agents",
|
|
38
|
+
"rag",
|
|
39
|
+
"sdk",
|
|
40
|
+
"typescript"
|
|
41
|
+
],
|
|
42
|
+
"homepage": "https://getmnemo.xyz",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/ledgermem/getmnemo-js.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/getmnemo/getmnemo-js/issues"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^22.10.0",
|
|
53
|
+
"eslint": "^9.17.0",
|
|
54
|
+
"tsup": "^8.3.5",
|
|
55
|
+
"typescript": "^5.7.2",
|
|
56
|
+
"vitest": "^2.1.8"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"sideEffects": false
|
|
62
|
+
}
|