Local & Simulator Adapters
The Mock Adapters guide used fully in-memory adapters. This guide swaps them for ArweaveLocalStorageAdapter and MidnightSimulatorChainAdapter — adapters that behave like the real thing (real network calls to a local Arweave node, and real execution of the DataRegistry contract) but still need no Midnight proof server, no wallet extension, and no real tokens.
This is a good next step once Mock Adapters feels too simplified: refId values now use the real circuit-derived format, and ownership checks run exactly as they would against the live chain — so tests written against these adapters exercise realistic behavior.
Prerequisites
- Node.js 22 or later
- arlocal — a local Arweave-compatible node
- No Midnight proof server, wallet extension, or DUST tokens needed —
MidnightSimulatorChainAdapterruns the realDataRegistrycircuits in-process
Fast track: clone starter-template and wire up this guide's adapters in minutes.
Step 1 — Start arlocal
docker run -d --rm -p 1984:1984 textury/arlocal
# or, without Docker:
npx arlocalNo real AR tokens are needed — arlocal auto-funds test wallets.
Once you've finished working through this guide, stop arlocal so it doesn't keep running in the background. If you started it with npx arlocal, press Ctrl+C in that terminal. If you started it with Docker, run:
docker stop $(docker ps -q --filter ancestor=textury/arlocal)The --rm flag used when starting the container cleans it up automatically once stopped.
Step 2 — Configure the SDK
This guide keeps the same three-adapter shape from Mock Adapters, but swaps two of them out for versions that behave like the real thing — only encryptionAdapters stays as-is:
storageAdapter—ArweaveLocalStorageAdapter.createWithTestWallet()replacesMockStorageAdapter. It generates a fresh, disposable JWK test wallet (not connected to real funds) and funds it with test AR against your running arlocal instance.chainAdapter—MidnightSimulatorChainAdapterreplacesMockChainAdapter, running the realDataRegistrycontract logic in-process instead of simulating it in memory. It's still not talking to the Midnight network — no node, indexer, or proof server involved — just a much more faithful in-process simulator thanMockChainAdapter's.encryptionAdapters— unchanged.PasswordEncryptionAdapterstill protects the per-upload encryption key exactly as it did in the Mock Adapters guide.
import {
DStorage,
ArweaveLocalStorageAdapter,
MidnightSimulatorChainAdapter,
PasswordEncryptionAdapter,
} from "@dstorage-tech/dstorage-sdk";
const { adapter: storageAdapter } = await ArweaveLocalStorageAdapter.createWithTestWallet({
fundAr: 5, // amount of test AR to fund the generated wallet with
});
const sdk = new DStorage({
storageAdapter,
chainAdapter: new MidnightSimulatorChainAdapter(),
encryptionAdapters: [
new PasswordEncryptionAdapter({
password: "Correct-Horse-Battery!",
salt: "myapp:v1",
}),
],
});Step 3 — Init, store, retrieve
The API is identical to the Mock Adapters guide — that's the point, adapters are interchangeable:
await sdk.init();
const { chainRefId } = await sdk.store(
new TextEncoder().encode("hello, dStorage"),
);
const { bytes } = await sdk.retrieveByRefId(chainRefId);
console.log(new TextDecoder().decode(bytes)); // "hello, dStorage"What's different from Mock under the hood:
chainRefIdis now generated by running the realDataRegistrycontract logic — a 32-byte hex ID, not the random placeholder ID thatMockChainAdapteruses.- Ownership checks are enforced by the simulator just as they would be by the real contract running on the Midnight network, so tests here catch ownership bugs that Mock's simplified checks would miss.
- Uploads are sent over the network to your local arlocal instance, instead of just being held in memory like
MockStorageAdapterdid. storageIdis now a real Arweave transaction ID in your local arlocal instance, instead of a random placeholder — it's not on the real Arweave network, but it can actually be looked up there.
Learn More
- Browse the FAQ for the full adapter reference.