MemoFSMemoFS
Adapters

Cloudflare R2 Adapter

Cloudflare R2 blob storage adapter for MemoFS remote-blob memory stores.

The @memofs/adapter-r2 adapter provides serverless raw byte storage for MemoFS using Cloudflare R2 object storage buckets (R2Bucket).

It implements core's provider-neutral BlobClient interface, allowing MemoFS's RemoteBlobMemoryStore to persist canonical .memofs/ files across distributed edge runtimes.

Installation

npm install @memofs/adapter-r2

Requires Node.js >= 22 or the Cloudflare Workers runtime.

Usage in Cloudflare Workers

In your Cloudflare Worker, bind an R2 bucket (e.g. env.BLOBS), create a BlobClient with createR2BlobClient(), and pair it with a metadata store in RemoteBlobMemoryStore:

import { MemoFS, RemoteBlobMemoryStore } from "@memofs/core";
import { createR2BlobClient } from "@memofs/adapter-r2";
import { createTursoMetadataStore } from "@memofs/adapter-turso";
import { createClient } from "@libsql/client";

export interface Env {
  BLOBS: R2Bucket; // R2 Bucket binding from wrangler.jsonc / wrangler.toml
  TURSO_DATABASE_URL: string;
  TURSO_AUTH_TOKEN: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const projectId = "team-workspace";

    // 1. Initialize R2 Blob Client (implements BlobClient)
    const blobClient = createR2BlobClient({
      binding: env.BLOBS,
    });

    // 2. Initialize Turso Metadata Store (implements MetadataStore)
    const metadata = createTursoMetadataStore({
      client: createClient({
        url: env.TURSO_DATABASE_URL,
        authToken: env.TURSO_AUTH_TOKEN,
      }),
      projectId,
    });

    // 3. Compose the provider-neutral RemoteBlobMemoryStore
    const store = new RemoteBlobMemoryStore({
      blobClient,
      metadata,
      rootKey: projectId,
    });

    // 4. Initialize MemoFS
    const memo = new MemoFS({
      store,
      projectId,
      mode: "local",
    });

    const coreMemory = await memo.core.read();
    return new Response(coreMemory, {
      headers: { "Content-Type": "text/markdown" },
    });
  },
};

Content Addressing & Storage Layout

@memofs/adapter-r2 adheres to MemoFS's content-addressed storage architecture:

  1. SHA-256 Keying: The runtime computes the 64-character lowercase hexadecimal SHA-256 hash of the canonical file content and passes it as the blob key (blobKey === sha256).
  2. Exact Cloud Replica Parity: Matches the cloud sync engine's file replica format (r2_key === sha256) exactly. Identical file contents across multiple projects or file paths share the same underlying blob storage without duplication.
  3. Idempotent Operations: Because keys are derived strictly from file content, writing the same file repeatedly is fully idempotent. Deleting non-existent keys succeeds safely without errors.

Configuration API (CreateR2BlobClientOptions)

The createR2BlobClient(options) factory accepts CreateR2BlobClientOptions:

OptionTypeRequiredDescription
bindingR2BucketYesThe Cloudflare R2 bucket binding object from env.

Method Reference (BlobClient)

The returned BlobClient exposes three provider-neutral methods:

interface BlobClient {
  /** Reads raw bytes from R2; returns null if key is absent. */
  get(key: string): Promise<ArrayBuffer | null>;
  /** Writes bytes or streams to R2 under the content-derived key. */
  put(key: string, body: BufferSource | ReadableStream<Uint8Array>): Promise<void>;
  /** Deletes a blob from R2; idempotent. */
  delete(key: string): Promise<void>;
}

See Also

On this page