JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 84
  • Score
    100M100P100Q107319F
  • License MIT

SDK for building custom pipeline handlers for the Ruvos healthcare data exchange platform

Package Exports

  • @ruvos/handler-sdk

Readme

@ruvos/handler-sdk

npm version

SDK for building custom pipeline handlers for the Ruvos healthcare data exchange platform.

Handlers let you intercept and process FHIR resources at three stages of the Ruvos data pipeline:

  • post_downstream_fetch — after data is fetched from an external source
  • pre_store — before data is encrypted and stored
  • post_store — after data is persisted

Installation

npm install @ruvos/handler-sdk

Quick Start

Scaffold a new handler project

npx @ruvos/handler-sdk create-handler my-handler
cd ruvos-handler-my-handler
npm install

This generates a complete project with TypeScript config, esbuild bundling, Terraform infrastructure, and a GitLab CI pipeline.

Write a handler

import { createHandler, type HandlerInput, type HandlerOutcome } from "@ruvos/handler-sdk";

async function handle(input: HandlerInput): Promise<HandlerOutcome> {
  const { stage, payload, tenantId, connectorType } = input;

  // Transform: modify resources before storage
  if (stage === "pre_store" && payload.resources) {
    const enriched = payload.resources.map((r) => ({
      ...r,
      meta: { ...r.meta, tag: [{ code: "reviewed", display: "Reviewed by handler" }] },
    }));
    return { action: "transform", resources: enriched };
  }

  // Passthrough: continue normal pipeline
  return { action: "passthrough" };
}

export const handler = createHandler({ handlerId: "my-handler" }, handle);

Handler Outcomes

Every handler must return one of five outcomes:

Outcome Description
passthrough Continue normal pipeline processing
transform Replace resources with a modified set
route_to Forward the payload to an HTTPS URL (skip normal storage)
requeue Retry processing later with an optional delay
fail Abort the job with a reason
// passthrough
return { action: "passthrough" };

// transform
return { action: "transform", resources: modifiedResources, metadata: { source: "enriched" } };

// route_to
return { action: "route_to", url: "https://my-service.example.com/ingest", body: payload };

// requeue
return { action: "requeue", delaySeconds: 30 };

// fail
return { action: "fail", reason: "Missing required patient identifier" };

API Reference

createHandler(options, fn)

Wraps a handler function with logging, timeout, and outcome validation.

import { createHandler } from "@ruvos/handler-sdk";

export const handler = createHandler(
  { handlerId: "my-handler", timeoutMs: 60_000 },
  async (input) => { /* ... */ }
);

Options:

  • handlerId — unique identifier for this handler
  • timeoutMs — execution timeout (default: 120,000ms)

parseCcda(xml)

Parses a C-CDA XML document into FHIR resources (Patient + Composition).

import { parseCcda } from "@ruvos/handler-sdk";

const resources = parseCcda(xmlString);
// [{ resourceType: "Patient", ... }, { resourceType: "Composition", ... }]

validateOutcome(value)

Validates that a handler outcome has the correct structure. Called automatically by createHandler, but available for testing.

import { validateOutcome, HandlerValidationError } from "@ruvos/handler-sdk";

try {
  const validated = validateOutcome(result);
} catch (err) {
  if (err instanceof HandlerValidationError) {
    console.error("Invalid outcome:", err.message);
  }
}

createHandlerLogger(context)

Creates a structured JSON logger for use within handlers.

import { createHandlerLogger } from "@ruvos/handler-sdk";

const logger = createHandlerLogger({
  handlerId: "my-handler",
  correlationId: input.correlationId,
  tenantId: input.tenantId,
  stage: input.stage,
});

logger.info("processing_resources", { count: input.payload.resources?.length });

Types

type HookStage = "post_downstream_fetch" | "pre_store" | "post_store";

interface HandlerInput {
  stage: HookStage;
  tenantId: string;
  jobId: string;
  correlationId: string;
  connectorType: string;
  config?: Record<string, unknown>;
  payload: {
    resources?: FHIRResource[];
    metadata?: Record<string, unknown>;
    s3Key?: string;
  };
}

type HandlerOutcome =
  | { action: "passthrough" }
  | { action: "transform"; resources: FHIRResource[]; metadata?: Record<string, unknown> }
  | { action: "route_to"; url: string; method?: string; headers?: Record<string, string>; body: unknown }
  | { action: "requeue"; delaySeconds?: number }
  | { action: "fail"; reason: string };

interface FHIRResource {
  resourceType: string;
  id?: string;
  [key: string]: unknown;
}

License

MIT