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-sdkUsage
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 testsBehavior notes
- Non-persistent. The store lives in the process. Everything is lost when the process exits, and two
Filesinstances built from separatememory()calls don't share data. Not for production. - Value semantics. Bodies are copied in on upload (and on seed), so mutating a
Uint8Arrayyou passed in later doesn't change the stored bytes. - Content ETag. The
etagis a stable hash of the bytes (pure-JS FNV-1a, nonode:crypto), so re-uploading identical content yields the same ETag - matching how real backends behave.
Compatibility
| Method | Status | Notes |
|---|---|---|
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. |