Early Access The dStorage SDK is under active development (v0.0.x). APIs may still change — it's safe to follow the guides, but hold off on production use for now.
Skip to content

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 — MidnightSimulatorChainAdapter runs the real DataRegistry circuits in-process

Fast track: clone starter-template and wire up this guide's adapters in minutes.

Step 1 — Start arlocal

sh
docker run -d --rm -p 1984:1984 textury/arlocal
# or, without Docker:
npx arlocal

No 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:

sh
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:

  • storageAdapterArweaveLocalStorageAdapter.createWithTestWallet() replaces MockStorageAdapter. It generates a fresh, disposable JWK test wallet (not connected to real funds) and funds it with test AR against your running arlocal instance.
  • chainAdapterMidnightSimulatorChainAdapter replaces MockChainAdapter, running the real DataRegistry contract 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 than MockChainAdapter's.
  • encryptionAdapters — unchanged. PasswordEncryptionAdapter still protects the per-upload encryption key exactly as it did in the Mock Adapters guide.
typescript
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:

typescript
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:

  • chainRefId is now generated by running the real DataRegistry contract logic — a 32-byte hex ID, not the random placeholder ID that MockChainAdapter uses.
  • 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 MockStorageAdapter did.
  • storageId is 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.