Dashboard

Storage Adapters

The SHL SDK supports multiple storage backends. Choose based on your infrastructure:

Comparison

Adapter Use Case Infra Required Peer Dependency Cost
FhirflyStorage Zero-infra, just works None None Included free
LocalStorage Development, testing Filesystem None
S3Storage AWS production S3 bucket @aws-sdk/client-s3 Your AWS bill
AzureStorage Azure production Blob container @azure/storage-blob Your Azure bill
GCSStorage GCP production GCS bucket @google-cloud/storage Your GCP bill

Store encrypted content on FHIRfly's hosted service. No infrastructure to manage. Included free in all plans.

import { SHL } from "@fhirfly-io/shl";

const storage = new SHL.FhirflyStorage({
  apiKey: process.env.FHIRFLY_API_KEY,
  // apiBaseUrl: "https://api.fhirfly.io", // default
});

FHIRfly stores only opaque encrypted blobs. The decryption key is embedded in the shlink:/ URL and never sent to FHIRfly. This means FHIRfly cannot decrypt your content.

Per-Plan Limits

Plan Active SHLs Attachments/SHL Per-file limit
Free 25 10 1 MB
Developer 500 10 1 MB
Pro 5,000 10 1 MB
Business 50,000 10 1 MB
Enterprise Unlimited 10 1 MB

"Active" means non-revoked and non-expired. Revoke unused SHLs to free up quota. See Pricing for full plan details.

LocalStorage

Filesystem storage for local development and testing.

const storage = new SHL.LocalStorage({
  directory: "./shl-data",
  baseUrl: "http://localhost:3456/shl",
});

S3Storage

AWS S3 storage for production workloads.

npm install @aws-sdk/client-s3
const storage = new SHL.S3Storage({
  bucket: "my-shl-bucket",
  region: "us-east-1",
  baseUrl: "https://shl.example.com",
  prefix: "shl-data/", // optional
});

AzureStorage

Azure Blob Storage for Azure-based deployments.

npm install @azure/storage-blob
const storage = new SHL.AzureStorage({
  container: "shl-data",
  connectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
  baseUrl: "https://shl.example.com",
  prefix: "shl-data/", // optional
});

GCSStorage

Google Cloud Storage for GCP-based deployments.

npm install @google-cloud/storage
const storage = new SHL.GCSStorage({
  bucket: "my-shl-bucket",
  baseUrl: "https://shl.example.com",
  prefix: "shl-data/", // optional
});

Storage Interface

All storage adapters implement the SHLStorage interface:

interface SHLStorage {
  /** Base URL for manifest access */
  readonly baseUrl: string;

  /** Store a file (key = "{shlId}/{filename}") */
  store(key: string, content: string | Uint8Array): Promise<void>;

  /** Delete all files for an SHL (prefix = "{shlId}/") */
  delete(prefix: string): Promise<void>;
}

You can implement this interface to create custom storage adapters for any backend.

Concurrency Note

When self-hosting with cloud storage (S3, Azure, GCS), the SDK's access counter uses a plain read-modify-write pattern without conditional writes or ETags. Under concurrent load, a few extra accesses may be allowed beyond maxAccesses. For strict one-time links, use FhirflyStorage (which uses atomic MongoDB $inc) or add your own atomic counter (e.g., Redis, DynamoDB). See the Server Guide for details.