npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dignetwork/dig-sdk

v0.9.0

Published

The typed front door for building dapps on the DIG Network: a Chia wallet abstraction (ChiaProvider) plus DigClient read-crypto (verify + decrypt content by URN) and the canonical CHIP-0035 spend builder. ESM + CJS + .d.ts, browser + Node 18+.

Readme

@dignetwork/dig-sdk

The typed front door for building dapps on the DIG Network. One npm i gives you:

  • ChiaProvider — a Chia wallet your dapp gets for free. It prefers the injected DIG Browser wallet (window.chia) and falls back to WalletConnect → Sage, behind one normalized CHIP-0002 surface (getAddress, signMessage, signCoinSpends, takeOffer, balances, coins).
  • DigClient — read verified, encrypted content by URN. It derives the URN's keys in the browser, verifies inclusion against the on-chain root, and decrypts — the serving host stays blind (it only ever relays opaque ciphertext + proofs).
  • @dignetwork/dig-sdk/spend — the canonical CHIP-0035 spend builder (@dignetwork/chip35-dl-coin-wasm) re-exported. Build store / NFT / CAT spends through the SDK and sign them with the wallet. Spends are never hand-rolled.
  • Paywall — a high-level pay-to-unlock helper. Charge XCH or a CAT (e.g. $DIG) to unlock a resource, then gate access by verifying the payment — or gate on holding an NFT / a collection membership. It composes ChiaProvider with the canonical monetization spends; the wasm builds every coin spend, the wallet signs it.
  • Framework adapters@dignetwork/dig-sdk/vite (a Vite plugin) and @dignetwork/dig-sdk/next (a Next static-export adapter): inject a window.chia dev wallet during dev, and ship your build to a DIG capsule on a publish script. See Framework adapters.
  • @dignetwork/dig-sdk/dig-client — the read-crypto on its own (just DigClient + the loader + URN helpers), for consumers that want only the read path (e.g. a worker). Same digest-pinned wasm.

Ships ESM + CJS + .d.ts, runs in the browser and Node 18+, and is eval-free (usable in CSP-strict contexts).

npm i @dignetwork/dig-sdk
# Optional: only if you use the WalletConnect → Sage fallback
npm i @walletconnect/sign-client

Read verified, encrypted content in 5 lines

import { DigClient } from "@dignetwork/dig-sdk";

const dig = new DigClient(); // resolves your node via the §5.3 ladder (see below)
const text = await dig.readText({
  urn: "urn:dig:chia:<storeId>/index.html", // the resource to read
  root: "<onchain-root-hex>", // the trust anchor (from the chain)
});
console.log(text);

Rendering or serving content? Use the secure-by-default readers. readVerified() (and the string-decoding readText()) fetch, decrypt, and fail closed: they throw DECRYPT_FAILED when the bytes don't decrypt under the URN, and INCLUSION_UNVERIFIED when the bytes are read under a pinned root (a concrete 64-hex generation root) yet fail their on-chain inclusion proof — decryption success alone proves only "knows a public key", so an untrusted node under the §5.3 ladder could otherwise serve Enc(publicKey, malicious) that decrypts fine. Under an unpinned / "latest" root inclusion can't be proven in the blind model, so it stays advisory (the blind-model exception) and the gate is decryption-only.

The oblivious primitive. read() / readResource() are the genuine blind-model reads: they return { bytes, verified, decrypted } and never throw on unverified/undecryptable content (beyond a transport failure or a missing root) — a decoy is just opaque bytes, so presence stays unknowable. Use them only when you deliberately handle unverified bytes (a decoy, or content whose inclusion you verify yourself); check rootIsPinned(root) — which is fail-closed, so any root that is not an explicit ""/latest sentinel must satisfy verified — and verified yourself before trusting.

A private store adds a salt — either inline in the URN (…/secret.txt?salt=<hex>) or as dig.read({ urn, root, salt }).

Which node does it read from? (the §5.3 ladder)

DigClient prefers your OWN running node and falls back to the public gateway only as a last resort — it never hard-codes rpc.dig.net as the primary endpoint. It resolves the endpoint once (memoized per instance), using the first that responds:

  1. new DigClient({ rpc }) — an explicit endpoint (overrides everything, no probing).
  2. DIG_NODE_URL — the environment override (Node only; no probing).
  3. dig.local — the installed local node (https://127.0.0.2:443).
  4. localhost — a loopback node (http://localhost:9778).
  5. https://rpc.dig.net — the public gateway, the terminal fallback.

Each local rung is health-probed on a short timeout and falls through on no answer. In a browser the local rungs are skipped (a page can't probe a plaintext-loopback or self-signed-localhost node) — so the browser build resolves explicit › DIG_NODE_URL › gateway; pass { rpc } to point a page at a specific node. Call await dig.resolveEndpoint() to see which node was chosen ({ url, via }), or capabilities().nodeResolution for the machine-readable ladder.

Connect a wallet + sign

import { ChiaProvider } from "@dignetwork/dig-sdk";

// Prefers the injected DIG Browser wallet; falls back to WalletConnect → Sage.
const provider = await ChiaProvider.connect({
  mode: "auto",
  walletConnect: {
    projectId: "<walletconnect-cloud-project-id>",
    metadata: {
      name: "My DIG dapp",
      description: "Built with @dignetwork/dig-sdk",
      url: "https://my-dapp.example",
      icons: ["https://my-dapp.example/icon.png"],
    },
    onUri: (uri) => showWalletConnectQr(uri), // render the QR / copy-link for the fallback
  },
});

const address = await provider.getAddress();
const { publicKey, signature } = await provider.signMessage(
  "Login to My DIG dapp",
);
// → verify the BLS signature server-side against the CHIP-0002 message hash + publicKey

If you only target the DIG Browser, drop walletConnect and use mode: "injected" (or "auto", which still prefers injected). provider.backend tells you which transport connected.

Offer a chooser: 'Browser Wallet' vs 'WalletConnect'

mode: "auto" above is a convenience that silently prefers the injected wallet — fine for a single-wallet-target dapp, but a user who has BOTH a DIG Browser wallet and Sage should get to pick. ChiaProvider.listConnectors() enumerates the connectors a chooser UI can offer, without connecting to either (no auto-pick):

import { ChiaProvider } from "@dignetwork/dig-sdk";

const connectors = ChiaProvider.listConnectors();
// → [
//     { id: "browser-wallet", backend: "injected",      label: "Browser Wallet", available: true|false },
//     { id: "walletconnect",  backend: "walletconnect",  label: "WalletConnect",  available: true },
//   ]

// Render one button per connector (disable any with `available: false`), then connect with the
// user's pick — pass its `id` straight through as `mode`:
const provider = await ChiaProvider.connect({
  mode: chosenConnector.id, // "browser-wallet" | "walletconnect"
  walletConnect, // only needed if the user picked "walletconnect"
});

"browser-wallet" is an alias of "injected" — same transport, chooser-facing name. Browser Wallet is available only when an injected window.chia is detected; WalletConnect is always offered (its relay has no local presence to detect). Persist the user's last pick (e.g. localStorage) to pre-select it next time, but always let them switch — the SDK itself holds no UI state, that's the app's call.

Build + sign a store spend

import { ChiaProvider } from "@dignetwork/dig-sdk";
import * as spend from "@dignetwork/dig-sdk/spend"; // the canonical CHIP-0035 builder

spend.init();
// Build a spend bundle with the wasm builder (e.g. spend.mintStore(...) / spend.updateStoreMetadata(...)),
// then hand its coin spends to the wallet to sign:
const provider = await ChiaProvider.connect({ mode: "injected" });
const aggregatedSignature = await provider.signCoinSpends(
  /* coinSpends from the builder */ [],
);

The hub builds spend bundles in-browser via this wasm and pushes them to the wallet for signing — your dapp does the same through the SDK.

Charge for access (Paywall)

Paywall turns the monetization spends into a pay-to-unlock flow. It sources the buyer's coins from the connected wallet, asks the wasm to build the payment, pushes those coin spends to the wallet to sign, and hands you back a receipt — it never assembles a spend itself.

import { ChiaProvider, Paywall } from "@dignetwork/dig-sdk";

const provider = await ChiaProvider.connect({ mode: "auto", walletConnect });
const paywall = new Paywall(provider); // chip35 monetization wasm is loaded lazily under a bundler

// Charge 0.25 XCH to unlock a resource (amount is mojos). `memo` derives a deterministic unlock nonce.
const { receipt, signature } = await paywall.requestPayment({
  amount: 250_000_000_000n,
  owner: dappOwnerPuzzleHashHex,
  memo: `unlock:${resourceId}:${userId}`,
});

// …or charge a CAT (e.g. $DIG) by passing its tail hash:
await paywall.requestPayment({
  amount: 100n,
  owner: dappOwnerPuzzleHashHex,
  assetId: digTailHashHex,
});

// Later, gate access by re-checking the on-chain payment against the receipt:
const { ok } = await paywall.verifyReceipt({
  observed: observedPayment, // an ObservedPayment you filled in after reading the owner's coin
  owner: dappOwnerPuzzleHashHex,
  minAmount: 250_000_000_000n,
});
if (ok) grantAccess();

// Or gate on holding an NFT (or a collection membership) instead of a payment:
const access = await paywall.proveAccess({
  parentSpend,
  owner,
  nft: nftLauncherIdHex,
});
// const access = await paywall.proveAccess({ parentSpend, owner, collection: creatorDidHex });

No bundler? Pass the spend builder in yourself — new Paywall(provider, { spends }), where spends is import * as spends from "@dignetwork/dig-sdk/spend" (or the chip35 module). The builder is always the canonical wasm; the Paywall only orchestrates it.


API surface

ChiaProvider

| Member | Description | | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | static connect(options) | Connect a wallet. See ConnectOptions below. | | static listConnectors(options?) | Enumerate the connectors a chooser can offer — { id, backend, label, available }[] for "browser-wallet" and "walletconnect". Pure/side-effect-free (never connects); pass { acceptAnyInjected: true } to widen Browser Wallet detection to any window.chia. | | connectWallet(options) | Convenience alias for ChiaProvider.connect. | | backend / session | The connected transport ("injected" | "walletconnect") and session descriptor. | | getAddress() | The wallet's receive address (cached). | | getPublicKeys() | The wallet's synthetic public keys. | | signMessage(message, address?) | Sign a UTF-8 message; returns { publicKey, signature } (0x-normalized). | | signCoinSpends(coinSpends) | Sign raw CHIP-0035 coin spends (partialSign); returns the aggregated signature hex. | | takeOffer(offer, fee?) | Accept a Chia offer string (e.g. an NFT offer). | | getXchBalance() / getCatBalance(assetId) | Spendable balances (mojo/base-unit strings). | | getXchCoins(limit?) / getCatCoins(assetId, limit?) | Unspent coins for funding a spend. | | request(method, params?) | Escape hatch: a raw CHIP-0002 request through the active transport. | | supports(method) / disconnect() | Capability check / teardown. |

Transports are also exported directly (InjectedTransport, WalletConnectTransport, isInjectedAvailable, getInjectedProvider) for advanced flows (e.g. restoring a WC session via WalletConnectTransport.restore(...)).

ConnectOptions

| Field | Type | Default | Description | | ------------------- | ------------------------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | mode | "auto" | "injected" | "browser-wallet" | "walletconnect" | "auto" | "auto" prefers the injected DIG wallet and falls back to WalletConnect (silent — kept for backward compatibility); "browser-wallet" (alias of "injected") requires the injected wallet (throws NO_INJECTED_WALLET if absent) — pass this once the user picks it from listConnectors(); "walletconnect" forces WalletConnect→Sage (throws WC_OPTIONS_REQUIRED if walletConnect is omitted). | | walletConnect | WalletConnectOptions | — | Required for the WalletConnect fallback/force path (projectId, metadata, onUri). Omit if you only target the injected DIG Browser wallet. | | chain | string | "chia:mainnet" | CAIP-2 chain id. Mainnet only — there is no testnet flow. | | acceptAnyInjected | boolean | false | Accept any window.chia for the injected path, not just the DIG Browser's unspoofable isDIG provider. Use with care — a non-DIG provider is not feature-detected. |

DigClient

| Member | Description | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | new DigClient({ rpc?, fetch?, nodeProbe?, probeTimeoutMs?, isBrowser? }) | Resolves the node endpoint via the §5.3 ladder (below). An explicit rpc overrides it. | | resolveEndpoint() | The resolved { url, via } (memoized per instance) — which node was chosen and why. | | read({ urn, root?, salt? }, opts?) | Oblivious primitive → { bytes, verified, decrypted, … }; never throws on unverified/undecryptable content. | | readVerified({ urn, root?, salt? }, opts?) | Secure-by-default: throws DECRYPT_FAILED, or INCLUSION_UNVERIFIED under a pinned root that fails inclusion. Use to render/serve. | | readText({ urn, root?, salt? }, opts?) | As readVerified, decoded to a UTF-8 string. | | readResource({ storeId, resourceKey, root, salt? }, opts?) | Oblivious read by explicit parts instead of a URN (advisory flags, never throws on content). | | rootIsPinned(root) (export) | Fail-closed: true unless root is absent or an unpinned sentinel ("" / latest, any casing/padding). Roots are gated by default. | | deriveUrnKeys({ urn, salt? }) | The root-independent { retrievalKey, decryptionKey } for a URN. | | retrievalKey(storeId, key) / deriveKey(storeId, key, salt?) | The individual derivations. | | verifyInclusion(ciphertext, proof, root) / reconstructUrn(...) | Lower-level read-crypto. | | getCollection({ launcherIds, did? }, opts?) | Public NFT-collection facts → { did, declared_did, item_count, resolved_count, royalty_basis_points }. | | listCollectionItems({ launcherIds, offset?, limit? }, opts?) | A page of items resolved to their CURRENT on-chain owner + royalty + CHIP-0007 metadata → { items, offset, limit, total, next_offset }. | | wasm() | The raw read-crypto wasm (decryptChunk, encryptResource, version, …); integrity per the loader path. |

Paywall

| Member | Description | | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | new Paywall(provider, { spends? }) | Wrap a connected ChiaProvider. spends defaults to a lazy import("@dignetwork/chip35-dl-coin-wasm") (pass it for non-bundler runtimes). | | requestPayment({ amount, owner, assetId?, memo?, nonce?, fee?, coinLimit? }) | Build the payment via the wasm (buildPayment XCH / buildCatPayment CAT) and push it to the wallet to sign. Returns { signature, receipt, coinSpends, nonce }. | | verifyReceipt({ observed, owner, minAmount, asset?, nonce? }) | Verify an observed on-chain payment unlocks the paywall (wasm verifyPaymentReceipt). Returns { ok, error? }. | | proveAccess({ parentSpend, owner, nft? \| collection? }) | Prove NFT ownership (proveNftOwnership) or collection membership (proveCollectionMembership). Returns { ok, proof?, error? }. |

amount / minAmount / fee accept a number or bigint; hashes/ids/nonces are hex (with or without 0x). The Paywall holds no spend-assembly logic — if the canonical wasm builder is unavailable it throws rather than fabricate a spend.

URN helpers (pure)

parseUrn, isUrn, reconstructUrn, reconstructUrnWithRoot and the ParsedUrn type — the same URN grammar the hub, extension, and companion use.

Spend builder

import * as spend from "@dignetwork/dig-sdk/spend" re-exports @dignetwork/chip35-dl-coin-wasm (≥ 0.13.0): store coins (mintStore, meltStore, updateStoreMetadata, updateStoreOwnership, oracleSpend), assets (mintNft, bulkMint, bulkMintFunded, createDid, issueCat), CHIP-0007 metadata (buildChip0007Metadata, validateChip0007, generateItemMetadata), offers (encodeOffer, decodeOffer), monetization (buildPayment, buildCatPayment, paymentNonce, verifyPaymentReceipt, proveNftOwnership, proveCollectionMembership — these back the Paywall helper), and helpers (addFee, dataStoreFromSpend, hexSpendBundleToCoinSpends, spendBundleToHex, digstoreOwnerHint, sha256, init).


Framework adapters

Make DIG a first-class deploy target for the frameworks you already use. Each adapter does two things: injects a window.chia dev wallet during local dev (the same injected-provider contract ChiaProvider detects in production, so the wallet path runs end-to-end locally), and ships your build to a DIG capsule via digstore deploy --json on a publish script.

Deploying spends $DIG (each deploy publishes a new capsule), so it is a deliberate, credentialed step — never wired into the default build. Config + secrets are read from your project's dig.toml and DIGSTORE_* env vars, exactly like digstore deploy; the deploy key and store salt come from the env only (never argv) so they don't leak. Requires the digstore CLI on PATH.

Vite — @dignetwork/dig-sdk/vite

// vite.config.ts
import { defineConfig } from "vite";
import { digVite } from "@dignetwork/dig-sdk/vite";

export default defineConfig({
  plugins: [digVite()], // injects the window.chia dev shim during `vite dev`
});
// package.json — opt in to deploy with a publish script (after the build)
{
  "scripts": {
    "publish:dig": "vite build && node -e \"import('@dignetwork/dig-sdk/vite').then(m => m.digDeploy())\"",
  },
}

digDeploy() shells out to digstore deploy --json, ships the build dir to a new capsule, and prints the chia:// content-open address + the https://hub.dig.net/stores/<id> DIGHUb view URL (result.chiaUrl / result.hubUrl; result.digUrl is a deprecated alias of chiaUrl). Disable the dev shim with digVite({ devWallet: false }); set its mock address with digVite({ devWalletOptions: { address } }).

Next.js (static export) — @dignetwork/dig-sdk/next

Next has no Vite-style HTML hook, so the dev shim is a helper you drop into your <head> (guarded to dev), and digDeploy() ships the out/ static export:

// app/layout.tsx — dev-only window.chia shim
import { digNextDevShimTag } from "@dignetwork/dig-sdk/next";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <head>
        {process.env.NODE_ENV !== "production" && (
          <script
            dangerouslySetInnerHTML={{
              __html: digNextDevShimTag().replace(/^<script>|<\/script>$/g, ""),
            }}
          />
        )}
      </head>
      <body>{children}</body>
    </html>
  );
}
// package.json — deploy the static export (next.config: `output: "export"`)
{
  "scripts": {
    "publish:dig": "next build && node -e \"import('@dignetwork/dig-sdk/next').then(m => m.digDeploy())\"",
  },
}

digDeploy() defaults the output dir to out (Next's export dir); override any field via digDeploy({ outputDir, storeId, message, … }) or dig.toml.

Configuration

Both adapters resolve config with this precedence: digDeploy() options > DIGSTORE_* env > dig.toml > defaults (mirroring digstore deploy). Common keys: store-id, output-dir, message, network, remote (in dig.toml); secrets DIGSTORE_DEPLOY_KEY and (private stores) DIGSTORE_STORE_SALT from the env. The pure building blocks (config resolution, deploy-arg construction, the dev-shim string, the dig.toml reader) are exported from @dignetwork/dig-sdk/adapters if you want to compose your own deploy step.


Machine-readable surface (for agents)

The SDK is self-describing: an agent can introspect its version, modules, methods, chains, and the full error catalogue without reading source, and every failure carries a stable machine code.

Capabilities & version

import { SDK_VERSION, capabilities } from "@dignetwork/dig-sdk";

SDK_VERSION; // "0.2.0" — the published version, injected from package.json at build time
capabilities(); // (alias: describe()) the machine-readable surface ↓

capabilities() (and its alias describe()) returns:

| Field | Type | Description | | ---------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------- | | name | string | "@dignetwork/dig-sdk". | | version | string | SDK_VERSION. | | modules | { name, summary, entry }[] | The pillars: ChiaProvider, DigClient, Paywall, spend, adapters (each with its import entry). | | walletMethods | string[] | The canonical CHIP-0002 method surface both transports negotiate. | | signMethods | string[] | Message-signing methods, in preference order. | | transports | ("injected" \| "walletconnect")[] | The wallet transports. | | chains | string[] | CAIP-2 chains — ["chia:mainnet"] (no testnet flow). | | defaultRpc | string | The public gateway (https://rpc.dig.net) — the §5.3 ladder's terminal fallback, not a primary. | | nodeResolution | NodeResolutionDescriptor | The §5.3 client→node ladder: ordered rungs, the DIG_NODE_URL env var, and localProbing: "node-only". | | readCryptoWasmSha256 | string | SRI digest of the @dignetwork/dig-capsule-wasm read-crypto wasm (fail-closed on mismatch). | | errorCodes | string[] | The full stable error-code catalogue (see below). |

Error codes

Every failure the SDK surfaces is a DigSdkError (an Error subclass) with a stable, documented .code (UPPER_SNAKE) plus structured .context. Branch on err.code (or the isDigSdkError(err, code) type guard) — never on the human .message.

import { DigClient, DigSdkError, isDigSdkError } from "@dignetwork/dig-sdk";

try {
  await new DigClient().read({ urn });
} catch (e) {
  if (isDigSdkError(e, "ROOT_REQUIRED")) promptForRoot();
  else if (isDigSdkError(e, "RPC_TRANSPORT")) retryLater();
  else throw e;
}
// DigSdkError also has .toJSON() → { code, message, context }

The catalogue is exported as the typed DIG_SDK_ERROR_CODES const (and the DigSdkErrorCode union), and is also returned by capabilities().errorCodes:

| Code | Thrown when | Key context fields | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | WC_OPTIONS_REQUIRED | WalletConnect was needed but no walletConnect options were given. | mode | | NO_INJECTED_WALLET | mode:"injected" (or the injected leg of auto) found no usable window.chia. | mode, acceptAnyInjected | | WC_DEPENDENCY_MISSING | The optional @walletconnect/sign-client peer dep is not installed. | — | | METHOD_NOT_SUPPORTED | The active session/transport does not grant the requested method. | method | | WALLET_TIMEOUT | A wallet RPC timed out (e.g. Sage did not respond). | method, timeoutMs | | WALLET_NO_KEYS | The wallet returned no public keys / no key to sign with. | — | | ROOT_REQUIRED | A content read needs a confirmed on-chain root and none was supplied. | urn | | DECRYPT_FAILED | readVerified/readText: the resource did not decrypt under this URN (wrong key/salt, or a decoy). | urn | | INCLUSION_UNVERIFIED | readVerified/readText: under a pinned root, inclusion failed — refused chain-unbacked bytes. Use read for the advisory path. | urn, root | | CONTENT_UNVERIFIED | Deprecated — the pre-#2262 blanket unverified code. No path throws it now; superseded by INCLUSION_UNVERIFIED. | urn, root | | RPC_TRANSPORT | The dig RPC could not be reached (network/transport failure). | rpcMethod | | RPC_ERROR | The dig RPC returned an HTTP error or a JSON-RPC error. | rpcMethod, httpStatus, rpcCode | | RPC_MALFORMED_RESPONSE | The dig RPC returned a malformed/inconsistent payload. | rpcMethod | | RESOURCE_TOO_LARGE | A node declared a total_length above the protocol ceiling (or one the host can't allocate) — refused before allocating. | rpcMethod, declaredLength, maxLength | | WASM_INTEGRITY | The read-crypto wasm failed its SRI check — fail closed. | expected, actual | | WASM_LOAD_FAILED | The read-crypto wasm could not be loaded. | httpStatus, wasmUrl | | SPEND_BUILDER_UNAVAILABLE | The canonical chip35 wasm builder for the operation is unavailable (never hand-rolled). | builder | | NO_SECURE_RANDOM | No secure random source to generate a payment nonce. | — | | DIGSTORE_NOT_FOUND | The digstore binary could not be spawned (not installed / not on PATH). | bin | | CONTENT_NO_REACHABLE_HOLDER | A node redirected (-32008) but no named holder could be reached before the redirect budget or the ladder ran out. NOT a not-found — the content exists. | providers, redirectHops, retryable | | CONTENT_MISS_RATE_LIMITED | A node answered -32003: this client is driving its miss lookups too fast and the back-off attempts were spent. Scoped to the NODE, never the content. | rpcMethod, retryable, scope | | CONTENT_AVAILABILITY_UNKNOWN | A node answered -32017: availability could not be established because part of the search did not answer. Unknown, not absent. | rpcMethod, retryable | | DEPLOY_FAILED | digstore deploy exited non-zero. | exitCode, stderr | | DEPLOY_OUTPUT_UNPARSEABLE | digstore deploy --json output could not be parsed into a capsule. | stdout | | INVALID_ARGUMENT | A malformed argument (non-hex, bad URN, mutually-exclusive options, malformed capsule). | value, expected |


Key concepts

  • URNurn:dig:chia:<storeId>[:<root>]/<resourceKey>[?salt=<hex>] addresses one resource in a store. The retrieval + decryption keys are root-independent (the root is only the trust anchor for verification).
  • Oblivious / blind host — the dig RPC returns indistinguishable ciphertext for any retrieval key, so presence is unknowable. The client decrypts what it can; it never asks the host "is this present?".
  • Trust anchor — content is verified against an on-chain root that you resolve from the chain (coinset.org / the store singleton) and pass to read({ root }). The serving host can never be the trust anchor.
  • Pinned vs unpinned root — a root is unpinned only when it is absent or one of the sentinels "" / latest; anything else is pinned (rootIsPinned(root) === true) and the secure readers enforce inclusion against it. The predicate is fail-closed on purpose: an unrecognised root can only fail its proof loudly, whereas an unrecognised pinned root would skip the gate silently. An unpinned root can't be proven in the blind model, so inclusion is advisory there (the blind-model exception) and the secure readers gate on decryption only.
  • Oblivious vs secure-by-default readsread/readResource are the oblivious primitives (advisory flags, never throw on content); readVerified/readText are the fail-closed readers to use whenever you render or serve the bytes.

Read-crypto wasm provenance

DigClient runs the same dig_client read-crypto WASM the DIG Browser, the dig-chrome-extension, the dig-node, and hub.dig.net use. The SDK consumes it from the published @dignetwork/dig-capsule-wasm package (no vendoring): in Node the synchronous nodejs build, in the browser the web build. The wasm is pinned by SHA-256 (DIG_CLIENT_WASM_SHA256, the same digest the package publishes in its integrity.json). Its integrity anchor depends on the load path:

  • Byte-level SRI (fail-closed) on the Node path and on the explicit configureWasm({ wasmBytes | wasmUrl }) path — the raw bytes are SHA-256-verified against the pinned digest and a tampered or wrong artifact fails closed rather than running unverified crypto.
  • Pinned-package trust on the default browser (bundler) path — the web glue resolves and instantiates its own sibling wasm, which is the exact-version package artifact the SDK depends on, so the package supply chain is the trust anchor. CSP-strict / untrusted-delivery apps opt into byte-level SRI via configureWasm({ wasmUrl }) (see below).

CSP-strict / no-bundler browsers

The wasm is loaded lazily; in a bundler that resolves package files it is found automatically. If your environment can't resolve the package files (or your CSP blocks runtime fetches), fetch + verify the bytes yourself and hand them in before the first read:

import { configureWasm } from "@dignetwork/dig-sdk";
configureWasm({
  wasmBytes: myVerifiedBytes,
  glueUrl: "/dig-client/dig_client.js",
});

License

MIT