@ruvos/client
v0.1.22
Published
TypeScript client for the Ruvos healthcare data exchange API
Maintainers
Readme
@ruvos/client
TypeScript client for the Ruvos healthcare data exchange API.
Provides typed methods for every tenant-accessible endpoint — connectors, connections, jobs, FHIR queries, webhooks, handlers, hooks, exports, and more.
Installation
npm install @ruvos/clientQuick Start
import { RuvosClient } from "@ruvos/client";
const ruvos = new RuvosClient({
baseUrl: "https://api.dev.ruvos.io",
apiKey: "rk_your_api_key",
tenantId: "your-tenant-id",
});
// List available data sources
const connectors = await ruvos.listConnectors();
// Create a fetch job
const job = await ruvos.createJob({
tenantConnectorId: connectors[0].id,
connectionId: "conn_abc",
input: {
resourceTypes: ["Patient", "Coverage"],
patientIdentityToken: "eyJhbGciOi...",
},
});
// Poll until complete and get results in one call
const { job: completed, result } = await ruvos.createAndPollJob(
{
tenantConnectorId: "tc_abc",
connectionId: "conn_xyz",
input: { resourceTypes: ["Patient"] },
},
{ onUpdate: (j) => console.log(`Status: ${j.status}`) },
);
if (result && "resources" in result) {
console.log(`Got ${result.resources.length} FHIR resources`);
}API Overview
Constructor
const ruvos = new RuvosClient({
baseUrl: string; // Ruvos API URL
apiKey: string; // Your tenant API key (rk_...)
tenantId: string; // Your tenant UUID
fetch?: typeof fetch; // Optional custom fetch (for Node 16 or test mocking)
});Connectors
ruvos.listConnectors() // Public — no auth needed
ruvos.listConnectorsAuthenticated() // With auth — full details
ruvos.getConnector(connectorId)
ruvos.updateConnector(connectorId, settings)Connections (OAuth)
const { authorizationUrl } = await ruvos.authorize(connectorId, userId, returnUrl);
// Redirect user to authorizationUrl...
ruvos.listConnections()
ruvos.getConnection(connectionId)
ruvos.revokeConnection(connectionId)Jobs
ruvos.createJob({ tenantConnectorId, connectionId, input })
ruvos.getJob(jobId)
ruvos.listJobs({ limit: 20, cursor: "..." })
ruvos.getJobResult(jobId)
ruvos.getJobResult(jobId, { clientPublicKeyPem: pem }) // E2E encrypted
// Poll with status updates
const completed = await ruvos.pollJob(jobId, {
intervalMs: 3000,
maxAttempts: 60,
onUpdate: (job) => console.log(job.status),
});
// Create + poll + get result in one call
const { job, result } = await ruvos.createAndPollJob(input, pollOptions);FHIR
ruvos.fhirCapabilityStatement()
ruvos.fhirSearch("Patient", { _count: "10" })
ruvos.fhirRead("Patient", "patient-123")
ruvos.fhirImport(connectionId, ["Patient", "Coverage"])Webhooks
const wh = await ruvos.createWebhook({ url: "https://...", events: ["job.completed"] });
ruvos.listWebhooks()
ruvos.deleteWebhook(wh.id)Handlers & Hooks
ruvos.upsertHandler("my-handler", { displayName: "My Handler", type: "webhook", webhookUrl: "..." })
ruvos.listHandlers()
ruvos.listAvailableHandlers() // Platform + tenant handlers
ruvos.deleteHandler("my-handler")
ruvos.registerHook({ stage: "pre_store", handlerId: "my-handler", handlerScope: "tenant", priority: 10 })
ruvos.listHooks()
ruvos.deleteHook("pre_store", "my-handler")API Keys, Export, Stats, Search, Audit
ruvos.createApiKey()
ruvos.listApiKeys()
ruvos.revokeApiKey(keyId)
ruvos.createExport("[email protected]")
ruvos.getExport(exportId)
ruvos.getStats()
ruvos.getMetrics({ groupBy: "connector", from: "2026-01-01" })
ruvos.search({ q: "patient", status: "completed" })
ruvos.getAuditLog({ limit: 50, action: "phi_read" })Error Handling
All API errors throw RuvosError with structured information:
import { RuvosClient, RuvosError, RuvosTimeoutError } from "@ruvos/client";
try {
await ruvos.getJobResult(jobId);
} catch (err) {
if (err instanceof RuvosError) {
console.error(`API error: ${err.code} (${err.status}): ${err.message}`);
console.error(`Correlation: ${err.correlationId}`);
}
if (err instanceof RuvosTimeoutError) {
console.error(`Polling timed out for job ${err.jobId} (last: ${err.lastStatus})`);
}
}Data Delivery Modes
The getJobResult method handles all three delivery modes automatically:
const result = await ruvos.getJobResult(jobId);
if ("dataDeliveryMode" in result && result.dataDeliveryMode === "metadata") {
// Tenant configured for metadata-only — no PHI returned
console.log(`Processed ${result.resourceCount} resources`);
} else {
// Full FHIR resources available
for (const resource of result.resources) {
console.log(resource.resourceType, resource.id);
}
}If the tenant is set to none, getJobResult throws a RuvosError with code FORBIDDEN.
License
MIT
