In-Memory

In-memory store backed by a Map - the test/reference adapter. Zero dependencies, isomorphic, and non-persistent. Ideal for unit tests; not for production.

Installation

This adapter has no peer dependencies and no runtime requirements - it's pure JavaScript backed by a Map, so it runs unchanged in Node, Bun, Deno, the browser, and edge runtimes.

npm install files-sdk

Usage

The in-memory adapter implements the same Adapter contract as every cloud adapter, but stores objects in a Map instead of touching disk or a network. That makes it the near-universal choice for testing code that uses Files without standing up real storage - and it doubles as the reference adapter, since it's the smallest complete implementation.

import { Files } from "files-sdk";
import { memory } from "files-sdk/memory";

// A fresh, empty store. Same Adapter contract as the cloud adapters,
// so you can swap it in for tests without changing any call sites.
const files = new Files({
  adapter: memory(),
});

await files.upload("hello.txt", "hi");
const file = await files.download("hello.txt");
await file.text(); // "hi"

Seeding fixtures

Pass initial to pre-populate the store - handy when a test needs objects present up front. Each value is a body (a string or bytes) or an object that also pins contentType / metadata / cacheControl, the way an upload() call would.

import { memory } from "files-sdk/memory";

const adapter = memory({
  initial: {
    "users/1.json": '{"id":1}',
    "logo.png": pngBytes, // a Uint8Array
    "report.csv": {
      body: "a,b,c\n1,2,3",
      contentType: "text/csv",
      metadata: { owner: "alice" },
    },
  },
});

The constructor is synchronous, so seed values must convert to bytes without awaiting - that rules out Blob/File and ReadableStream. Seed those by calling upload() after construction.

Options

Prop

Type

Inspecting the store

The raw escape hatch is the backing Map, so a test can read or reset it directly without going through the adapter:

const adapter = memory();
const files = new Files({ adapter });

await files.upload("a.txt", "x");
adapter.raw.size; // 1
adapter.raw.has("a.txt"); // true
adapter.raw.clear(); // wipe between tests

Behavior notes

  • Non-persistent. The store lives in the process. Everything is lost when the process exits, and two Files instances built from separate memory() calls don't share data. Not for production.
  • Value semantics. Bodies are copied in on upload (and on seed), so mutating a Uint8Array you passed in later doesn't change the stored bytes.
  • Content ETag. The etag is a stable hash of the bytes (pure-JS FNV-1a, no node:crypto), so re-uploading identical content yields the same ETag - matching how real backends behave.

Compatibility

MethodStatusNotes
upload
download
delete
list
head
exists
copy
url⚠️Returns an opaque, non-fetchable memory://{key} URL - there's no server backing the store. Throws NotFound for a missing key (the way a real fetch would 404). expiresIn and responseContentDisposition round-trip as query params so URL-building call sites stay testable, but nothing resolves the URL. For working dev URLs use the fs adapter with urlBaseUrl, or a real cloud adapter.
signedUploadUrl⚠️Returns an inert memory://{key} placeholder PUT target - there's no real upload endpoint, so a client can't actually PUT to it. expiresIn round-trips into the URL and contentType into the returned headers so the signing flow stays testable; maxSize and minSize are ignored. Use upload() to write bytes.

On this page