Deployment & Configuration
What are the prerequisites for running the SDK locally?
- Node.js 22+, npm
- Docker (for Midnight proof server and Arweave Local)
- 1AM wallet extension (latest version) — or Lace, or another dApp Connector-compatible wallet (browser connector flows only)
- Wander wallet extension (Arweave browser flows only)
The DataRegistry contract ships pre-compiled with the SDK package (compiled circuits and keys included) — the Midnight Compact compiler is only needed if you're modifying the contract itself, not for normal SDK usage.
How do I start the local Midnight proof server?
docker run -p 6300:6300 midnightntwrk/proof-server:8.1.0 -- midnight-proof-server -vHow do I start a local Arweave node for testing?
docker run -d --rm -p 1984:1984 textury/arlocal
# or: npx arlocalNo real AR tokens are needed — arlocal auto-funds test wallets.
What Midnight networks does the adapter support?
Any Midnight network — undeployed (localhost), preprod, preview, or another — passed as the required network field. The adapter has no built-in default endpoints:
- Provider mode requires
indexerEndpoint,indexerWsEndpoint, andproofServerEndpoint; the constructor throws if any is missing. - Connector mode uses the indexer endpoints reported by the connected wallet unless you set
indexerEndpoint/indexerWsEndpointyourself, andinit()throws if the wallet is on a different network thannetwork. With the defaultprover(PROVER_MODE.PROOF_SERVER_URL),proofServerEndpointis required too; the wallet prover modes use the wallet's proof server or the wallet itself instead (see Where are ZK proofs generated in connector mode?).
How do I configure MidnightChainAdapter for browser vs Node.js?
Use the walletMode discriminated union:
Node.js (provider mode) — caller supplies a pre-built, synced WalletFacade:
{
walletMode: "provider",
walletProvider, // AdapterWalletProvider built and synced by the app
privateStatePassword, // password for local LevelDB state encryption
network: "undeployed",
indexerEndpoint, // required: indexer GraphQL (HTTP) URL
indexerWsEndpoint, // required: indexer GraphQL WebSocket URL
proofServerEndpoint: "http://localhost:6300", // required
zkArtifactsPath, // optional: absolute path to keys/ and zkir/ dirs — the SDK
// ships its own compiled copy (see below), no separate compile needed
}Browser (connector mode) — delegates to a wallet extension (1AM, Lace, or another dApp Connector wallet):
{
walletMode: "connector",
connectorName: "1am", // wallet to prefer under window.midnight
zkConfigBaseUrl: window.location.origin, // base URL serving keys/ and zkir/
network: "preprod", // must match the network the wallet is set to
proofServerEndpoint: "http://localhost:6300", // required with the default prover
// indexer endpoints come from the wallet unless set here
}walletMode and network are required.
Does WebAuthnPrfEncryptionAdapter work in a Node.js app?
Only partially. register() and authenticate() require real browser globals — window, navigator.credentials, PublicKeyCredential — and throw WEBAUTHN_PRF_UNAVAILABLE if they're missing, which is always the case in a plain Node.js process. isSupported() behaves the same way: it returns false (rather than throwing) whenever window is undefined.
So the interactive passkey ceremony only runs in a real browser tab, or in an Electron renderer process (which exposes those same browser globals) — never in a Node.js backend, CLI, or Electron main process.
The one part of the adapter that does work in Node is fromPublicKey(): it only needs raw public-key bytes and never touches WebAuthn, so a Node.js backend can use it for upload-only delegation on behalf of a browser-registered passkey owner (see WebAuthnPrfEncryptionAdapter in Adapters).
How do I configure ArweaveBundlerStorageAdapter for managed uploads?
new ArweaveBundlerStorageAdapter({
managedPayment: {
signingServerUrl: "https://portal.dstorage.pro",
// Token format: <credential>.<base64url_modulus> — issued by the signing server.
// The modulus (512 bytes, base64url) is the server's RSA-4096 public key and is
// used to pin the expected signing key at construction time.
authToken: process.env.DSTORAGE_AUTH_TOKEN ?? "",
},
});How do I reuse an existing DataRegistry contract?
Pass the previously deployed address:
new MidnightChainAdapter({
contractAddress: "a1b2c3…", // 64 lowercase hex chars
// … rest of config
});Omit contractAddress to deploy a new contract on first init().
Where do ZK artifacts live and how are they served?
DataRegistry is dStorage's own fixed contract — not something you compile yourself. Its compiled ZK artifacts (prover/verifier keys and ZKIR) ship inside the @dstorage-tech/dstorage-sdk package at dist/contracts/dataregistry/managed/{keys,zkir}.
- Node.js: pass an absolute path via
zkArtifactsPath. The adapter readskeys/andzkir/from that directory. Resolve the bundled copy via the package's ownpackage.jsonrather than hardcoding anode_modulespath:typescriptimport { createRequire } from "node:module"; import path from "node:path"; const zkArtifactsPath = path.join( path.dirname(createRequire(import.meta.url).resolve("@dstorage-tech/dstorage-sdk/package.json")), "dist/contracts/dataregistry/managed", ); - Browser: copy
keys/andzkir/fromnode_modules/@dstorage-tech/dstorage-sdk/dist/contracts/dataregistry/managed/into your application's public assets directory, then passzkConfigBaseUrl: window.location.origin. Artifacts are fetched over HTTP. (Thedstorage-starter-template'snpm run devdoes this automatically — seescripts/copy-zk-artifacts.mjs.)