R2LiveImageStore overview

Experimental whole-image R2 storage for one externally owned live volume. Each mutation replaces one object with an ETag condition. R2's concurrent same-key write limit and the absence of a reader lease require a single application-controlled gateway for the experimental writable NFS profile.

Added in v0.5.0


utils

ObjectRecord (interface)

A complete R2 image plus the metadata needed to validate and fence it.

Signature

export interface ObjectRecord {
  readonly bytes: Uint8Array
  readonly etag: string
  readonly generation: string | undefined
  readonly digest: string | undefined
}

Example

import type { ObjectRecord } from "@effect-vfs/persistence/R2LiveImageStore"
 
const record: ObjectRecord = {
  bytes: new Uint8Array(),
  etag: '"version-1"',
  generation: "0",
  digest: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}

Added in v0.5.0

Options (interface)

Configuration for one experimental R2-backed image.

Signature

export interface Options {
  readonly client: R2Client
  readonly key: string
  readonly maxImageBytes: ByteSize.ByteSize
  /** Assert R2's documented synchronous durable-write contract for a verified R2 endpoint and single owner. */
  readonly durability?: "survives-power-loss"
}

Example

import type { Options } from "@effect-vfs/persistence/R2LiveImageStore"
import { Effect, ByteSize } from "effect"
 
const client = {
  read: (_key: string) => Effect.succeed(null),
  write: () => Effect.succeed(null)
}
const options: Options = {
  client,
  key: "effect-vfs-nfs-test/live-image",
  maxImageBytes: ByteSize.mebibytes(16)
}

Added in v0.5.0

R2Client (interface)

Transport operations required by the live-image adapter.

Signature

export interface R2Client {
  readonly read: (key: string) => Effect.Effect<ObjectRecord | null, LiveVolume.LiveVolumeError>
  readonly write: (
    key: string,
    bytes: Uint8Array,
    generation: string,
    digest: string,
    condition: { readonly ifMatch: string } | { readonly ifNoneMatch: "*" }
  ) => Effect.Effect<{ readonly etag: string } | null, LiveVolume.LiveVolumeError>
}

Example

import { S3Client } from "@aws-sdk/client-s3"
import * as R2LiveImageStore from "@effect-vfs/persistence/R2LiveImageStore"
 
const s3 = new S3Client({
  region: "auto",
  endpoint: "https://ACCOUNT_ID.r2.cloudflarestorage.com",
  credentials: { accessKeyId: "ACCESS_KEY_ID", secretAccessKey: "SECRET_ACCESS_KEY" }
})
const client: R2LiveImageStore.R2Client = R2LiveImageStore.fromS3(s3, "test-bucket")

Added in v0.5.0

fromS3

Use R2's S3-compatible API from a Bun or Node NFS server.

Signature

export declare const fromS3: (client: S3Client, bucket: string) => R2Client

Example

import { S3Client } from "@aws-sdk/client-s3"
import * as R2LiveImageStore from "@effect-vfs/persistence/R2LiveImageStore"
 
const s3 = new S3Client({
  region: "auto",
  endpoint: "https://ACCOUNT_ID.r2.cloudflarestorage.com",
  credentials: { accessKeyId: "ACCESS_KEY_ID", secretAccessKey: "SECRET_ACCESS_KEY" }
})
const client = R2LiveImageStore.fromS3(s3, "test-bucket")

Added in v0.5.0

layer

A single-key experimental store. The application must ensure one live owner; ETag conditions detect stale writes but cannot prevent stale reads.

Signature

export declare const layer: (
  options: Options
) => Layer.Layer<LiveVolume.LiveImageStore, LiveVolume.LiveVolumeError, Crypto.Crypto>

Example

import * as R2LiveImageStore from "@effect-vfs/persistence/R2LiveImageStore"
import { ByteSize, Effect } from "effect"
 
const client: R2LiveImageStore.R2Client = {
  read: () => Effect.succeed(null),
  write: () => Effect.succeed(null)
}
const store = R2LiveImageStore.layer({
  client,
  key: "effect-vfs-nfs-test/live-image",
  maxImageBytes: ByteSize.mebibytes(16)
})

Added in v0.5.0