@synapsor/client
v0.1.6
Published
Node.js SDK for Synapsor, the agent-native database for auditable AI applications
Downloads
659
Maintainers
Readme
Synapsor Node.js SDK
The Synapsor Node.js SDK connects applications to hosted or local Synapsor databases. Use it for SQL, branch workflows, agent contexts, capabilities, evidence, memory, and safe write proposals from Node.js applications.
Local Usage
import { Synapsor } from "@synapsor/client";
const db = await Synapsor.connect("app.db", { autoStart: true });
db.setSession({
tenant_id: "acme",
principal: "support_agent_17",
session_id: "agent_run_1",
});
await db.execute("CREATE TABLE messages (id INT, body VARCHAR);");
await db.execute("INSERT INTO messages VALUES (1, 'hello');");
const rows = await db.query("SELECT * FROM messages;");
const proposal = await db.proposeMemoryFact({
scope: ["tenant", "acme"],
subject: ["preference", "answer_style"],
claim: "The operator prefers concise answers.",
source: ["turn", "msg_1"],
trust: "verified",
approval: "approved",
reason: "stable preference extracted from chat",
});
await db.approveMemoryProposal(proposal.proposal.proposal_id, "operator approved");
await db.close();Hosted Usage
Install from npm:
npm install @synapsor/clientimport { Synapsor } from "@synapsor/client";
const db = await Synapsor.connect("https://synapsor.ai", {
apiKey: process.env.SYNAPSOR_API_KEY,
});
db.setSession({
tenant_id: "acme",
principal: "app_user_1",
session_id: "first_hosted_run",
});
console.log(await db.query("SELECT 1;"));
const ctx = await db.invokeAgentCapability("chat.prepare_llm_context", { question: "..." });Use database-scoped API keys from the Synapsor control panel for hosted projects.
Agent Workflows
Use agentRuns when an agent framework owns routing, but Synapsor should own
the durable workflow contract: session scope, capability calls, evidence,
proposal branches, outbox actions, settlement, and replay.
const run = await db.agentRuns.start({
workflow: "billing.late_fee_waiver_flow",
version: "2026-05-27",
input: { user_request: "Can we waive this late fee?" },
});
const answer = await run.invokeCapability("support.answer_ticket_question", {
stepKey: "answer_ticket_question",
arguments: { question: "Can we waive this late fee?" },
responseEnvelope: true,
});
const proposal = await run.invokeCapability("billing.propose_late_fee_waiver", {
stepKey: "propose_waiver",
arguments: { amount_cents: 2500 },
mode: "propose_only",
autoBranch: true,
responseEnvelope: true,
});
const action = await run.proposeExternalAction("stripe.issue_refund", {
stepKey: "refund_customer",
arguments: { charge_id: "ch_123", amount_cents: 2500 },
idempotencyKey: "refund:TCK_1001:2500",
});
await run.checkpoint("before_worker_claim", {
payload: { reason: "external action queued" },
});
await run.complete({ decision: "waiver_proposed" }, { status: "waiting_approval" });
const graph = await run.explain();Find the persisted run/evidence/proposal later by business object, workflow, tenant, query fingerprint, or time window:
const activity = await db.agentActivity.search({
tenantId: "acme",
businessObjectId: "T-1042",
workflow: "support.ticket_refund_flow",
timeRange: { from: 123, to: 456 },
limit: 50,
});This helper sends the native lookup form:
SELECT *
FROM AGENT ACTIVITY
WHERE tenant_id = 'acme'
AND business_object_id = 'T-1042'
ORDER BY created_at DESC
LIMIT 50;Replay a stored capability run by using the numeric agent_run_id returned by
Synapsor. Deterministic replay returns the captured persisted run; comparison
modes can inspect the original snapshot, current state, a commit version, a
timestamp, or a review branch.
const replay = await db.replayAgentRun(123, {
mode: "original_snapshot",
});
const branchReplay = await db.replayAgentRun(123, {
mode: "branch",
branchName: "review_run_123",
});Workers should claim and confirm side effects through the outbox namespace:
const task = await db.externalActions.claim({
queue: "billing_external_actions",
workerId: "billing-worker-1",
});
await db.externalActions.confirm(task.action_instance_id, {
status: "succeeded",
providerRequestId: "re_456",
response: { status: "succeeded" },
});External DB Writeback Worker
For existing Postgres/MySQL integrations, keep Synapsor in proposal mode. The agent stages an evidence-backed external write proposal, a human or settlement policy approves it, and a trusted worker in your app environment applies the approved change back to your existing database with parameterized SQL.
import { createExternalDbWritebackWorker } from "@synapsor/client/external-db-writeback";
const worker = createExternalDbWritebackWorker({
synapsorApiKey: process.env.SYNAPSOR_API_KEY,
sourceName: "app_postgres",
execute: async ({ sql, params }) => {
// Use your own Postgres/MySQL client here. The model never provides SQL.
return appDb.query(sql, params);
},
});
await worker.pollOnce();The worker validates Synapsor-provided mapping metadata, only writes allowlisted
columns, adds tenant and primary-key guards, checks optional conflict columns,
and reports applied, conflict, or failed back to Synapsor idempotently.
CLI MCP Risk Review
The package installs a synapsor CLI. Use synapsor mcp audit <target> for a
static MCP database risk review of exported tool manifests, remote tools/list
endpoints, or stdio MCP servers.
synapsor mcp audit ./tools-manifest.json
synapsor mcp audit https://mcp.example.com --bearer-env MCP_AUDIT_TOKEN --json
synapsor mcp audit 'stdio:node ./server.mjs' --timeout-ms 5000The audit flags patterns such as generic execute_sql tools, model-controlled
tenant/table/column inputs, model-callable approval or commit tools, missing
proposal boundaries, missing structured output schemas, and missing idempotency
or conflict-guard metadata. It never calls business tools during the audit.
This is a static MCP database risk review, not proof that an MCP server is secure. MCP annotations are treated as descriptive hints, not enforcement.
API Surface
execute(sql)andquery(sql)setSession({...})invokeAgentCapability(name, args, options)agentRuns.start(...),run.invokeCapability(...),run.checkpoint(...),run.complete(...),run.explain(...)agentActivity.search({ tenantId, businessObjectId, workflow, timeRange, limit })replayAgentRun(id, { mode, version, timestamp, branchName })externalActions.claim(...)andexternalActions.confirm(...)createAgentEval(...)/evals.create(...)for run-history orsourceTabledataset evalsevals.run(...).failures()listCapabilities(query)rememberFact({...})proposeMemoryFact({...})approveMemoryProposal(id, reason)rejectMemoryProposal(id, reason)listMemoryProposals({...})recallMemory({...})retireFact(id, {...})andforgetFact(id, reason)checkFactForAction({...})- branch helpers:
createBranch,useBranch,diffBranch,mergeBranch,dropBranch - write lifecycle helpers:
previewWrite,approveWrite,commitWrite,rejectWrite,settleWrite - external DB writeback worker:
createExternalDbWritebackWorkerfrom@synapsor/client/external-db-writeback readResource(uri)
Errors from Synapsor become SynapsorError with status, code,
requestId, retryable, and the raw payload. Include requestId when
opening support or incident tickets so server, gateway, and runtime logs can be
joined without exposing secrets.
