The TypeScript SDK is the lightest way to use mnueron from any JS runtime. Zero runtime dependencies, dual ESM + CommonJS builds, works in Node 18+, Deno, Bun, Cloudflare Workers, and browsers (CORS permitting).
Install
npm install @mnueron/sdk
Quick start
import { Mnueron } from '@mnueron/sdk';
const m = new Mnueron({ apiKey: 'mnu_...' }); // or set MNUERON_API_KEY env
// Save
const mem = await m.save('User prefers concise replies', {
namespace: 'my-app',
tags: ['preferences'],
});
// Full-text search (BM25 server-side)
const hits = await m.search('how does the user like responses?', {
namespace: 'my-app',
k: 5,
});
for (const r of hits) console.log(r.content, r.score);
// Partial update — metadata MERGED (pass null in values to delete a key)
await m.update(mem.id, {
tags: ['preferences', 'tone'],
metadata: { confidence: 0.9 },
});
await m.delete(mem.id);
Configuration
Set the env var once and the constructor picks it up automatically:
export MNUERON_API_KEY=mnu_xxxxxxxxxxxxxxxxxxxxx
# Optional — default is https://www.mnueron.com
export MNUERON_API_URL=https://www.mnueron.com
const m = new Mnueron(); // reads env
Date + metadata filters
Date values are epoch milliseconds. metadata_filter is passed to
Postgres' @> jsonb containment operator.
const yesterday = Date.now() - 24 * 60 * 60 * 1000;
const recent = await m.list({
namespace: 'my-app',
created_after: yesterday,
metadata_filter: { speaker: 'sarah' },
});
Bulk search
Up to 25 queries in one HTTP round-trip:
const results = await m.bulkSearch(
['onboarding', 'billing edge cases', 'JWT setup'],
{ namespace: 'work', k: 5 },
);
for (const r of results) {
console.log(r.query, '→', r.hits.length, 'hits');
}
Webhooks
Register a delivery endpoint:
const hook = await m.createWebhook('https://example.com/mnueron-hook', {
events: ['memory.saved', 'memory.deleted'],
description: 'forward saves into our event bus',
});
console.log('Store this once — won\'t appear again:', hook.secret);
Verify incoming deliveries — works in Node, Workers, Deno, Bun. The
verifier uses Node's node:crypto when available and falls back to
Web Crypto everywhere else, so the same code runs in any runtime.
import { verifyWebhookSignature } from '@mnueron/sdk';
// Express
app.post('/mnueron-hook',
express.raw({ type: 'application/json' }),
async (req, res) => {
const sig = req.header('X-Mnueron-Signature');
const ok = await verifyWebhookSignature(secret, req.body, sig);
if (!ok) return res.status(401).end();
// ... handle payload
res.status(200).end();
},
);
// Next.js App Router
export async function POST(req: Request) {
const raw = new Uint8Array(await req.arrayBuffer());
const sig = req.headers.get('x-mnueron-signature');
if (!(await verifyWebhookSignature(secret, raw, sig))) {
return new Response('invalid signature', { status: 401 });
}
// ... handle JSON.parse(new TextDecoder().decode(raw))
return new Response(null, { status: 204 });
}
Combine with an LLM client
import OpenAI from 'openai';
import { Mnueron } from '@mnueron/sdk';
const m = new Mnueron();
const llm = new OpenAI();
const context = await m.search(userMessage, { namespace: 'user-123', k: 5 });
const promptContext = context.map((r) => r.content).join('\n');
const reply = await llm.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: `Relevant context:\n${promptContext}` },
{ role: 'user', content: userMessage },
],
});
// Opt into v0.2.9 fact extraction on this save
await m.save(reply.choices[0].message.content!, {
namespace: 'user-123',
source: 'auto',
metadata: { extract_facts: true },
});
Same shape works with @anthropic-ai/sdk, Mistral, Gemini, or any
other client.
Edge runtimes
The SDK is bundler-friendly and ships no Node-only code in the import path. It runs unmodified in:
- Cloudflare Workers
- Vercel Edge Functions
- Deno Deploy
- Bun's edge-style handlers
- Modern browsers (set
apiKeyexplicitly — noprocess.envthere)
API reference
| Method | Returns | Notes |
|---|---|---|
save(content, opts?) | Memory | Single insert. Fires memory.saved webhooks. |
search(query, opts?) | Memory[] | BM25 search with stacking filters. |
bulkSearch(queries, opts?) | BulkSearchResult[] | Up to 25 queries per batch. |
list(opts?) | Memory[] | Newest-first; supports date + metadata filters. |
get(id) | Memory | null | Returns null on 404. |
update(id, patch) | Memory | Partial; metadata is merged. |
delete(id) | void | Fires memory.deleted webhooks. |
namespaces() | string[] | All namespaces in your org. |
health() | { ok: true } | Liveness probe. |
listWebhooks() / createWebhook() / getWebhook() / updateWebhook() / deleteWebhook() | — | Full CRUD over webhook subscriptions. |
verifyWebhookSignature(secret, body, sigHeader) | Promise<boolean> | Constant-time HMAC-SHA256 check. Exported as a standalone function too. |
Throws a typed MnueronError on non-2xx responses with the server's
error message attached.