JSPM

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

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

Package Exports

  • @ruvos/handler-sdk

Readme

@ruvos/handler-sdk

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