{
  "openrpc": "1.2.6",
  "info": {
    "title": "dig RPC — node profile (local dig-node / dig-companion / in-process DIG Browser)",
    "version": "1.0.0",
    "description": "The NODE PROFILE: a distinct, smaller surface than the network profile. Of the byte methods it implements ONLY dig.getContent (local-first, else proxy); everything else proxies upstream or returns -32601. It ADDS node-only methods the security model depends on — chiefly dig.getAnchoredRoot (the CHIP-0035 on-chain head, the trusted root for mandatory root-pinning), dig.stage, and cache.*. Gate on dig.methods rather than assuming one uniform surface. See https://docs.dig.net/docs/protocol/dig-rpc#node-profile.",
    "license": {
      "name": "GPL-2.0",
      "url": "https://github.com/DIG-Network/digstore/blob/main/LICENSE"
    }
  },
  "servers": [
    {
      "name": "local dig-node",
      "url": "http://127.0.0.1:9778",
      "summary": "The local node the DIG Browser runs in-process (FFI) and dig-node serves on 127.0.0.1:9778."
    }
  ],
  "methods": [
    {
      "name": "dig.getContent",
      "summary": "Stream one resource’s ciphertext (local-first, then proxy).",
      "description": "Identical wire contract to the network profile, but served LOCAL-FIRST: from a cached compiled .dig (serve_blind over <cache>/modules/<store>/<root>.module), else an authenticated §21.9 whole-store sync, else the raw JSON-RPC body is proxied upstream to rpc.dig.net. The in-process node ADDITIVELY tags each chunk with `source` (\"local\"|\"remote\").",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "store_id",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/StoreId"
          }
        },
        {
          "name": "retrieval_key",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/RetrievalKey"
          }
        },
        {
          "name": "root",
          "required": false,
          "schema": {
            "$ref": "#/components/schemas/Root"
          }
        },
        {
          "name": "offset",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "length",
          "required": false,
          "description": "Clamped to the node window (3 MiB).",
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "result": {
        "name": "chunk",
        "schema": {
          "$ref": "#/components/schemas/ChunkObject"
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        },
        {
          "$ref": "#/components/errors/RESOURCE_UNAVAILABLE"
        }
      ]
    },
    {
      "name": "dig.getAnchoredRoot",
      "summary": "Resolve the store’s CHIP-0035 on-chain head root (the trusted root).",
      "description": "Walks the CHIP-0035 DataStore singleton lineage on coinset.org (digstore_chain::singleton::sync_datastore) and returns metadata.root_hash — the on-chain-anchored tip. This is the TRUSTED root a client pins a rootless chia:// URN against; verification must never trust the rpc-served \"latest\". Coinset host defaults to api.coinset.org (override DIG_NODE_COINSET). NODE-PROFILE ONLY: absent from the network profile (dig-node lib.rs:721-743).",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "store_id",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/StoreId"
          }
        }
      ],
      "result": {
        "name": "anchored",
        "schema": {
          "type": "object",
          "properties": {
            "store_id": {
              "$ref": "#/components/schemas/StoreId"
            },
            "root": {
              "$ref": "#/components/schemas/StoreId"
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "dig.stage",
      "summary": "Compile a local folder into a capsule .dig, in-process.",
      "description": "Compiles a local directory into a capsule (.dig) in-process for preview/publish. NODE-PROFILE ONLY (dig-node lib.rs:768-904).",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "result": {
        "name": "staged",
        "schema": {
          "type": "object",
          "properties": {
            "store_id": {
              "$ref": "#/components/schemas/StoreId"
            },
            "root": {
              "$ref": "#/components/schemas/StoreId"
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "cache.getConfig",
      "summary": "Read the local node cache configuration.",
      "description": "Part of the node-only cache.* control surface (getConfig/setCapBytes/clear/listCached/removeCached/fetchAndCache). NODE-PROFILE ONLY (dig-node lib.rs:1143-1231).",
      "paramStructure": "by-name",
      "params": [],
      "result": {
        "name": "config",
        "schema": {
          "type": "object"
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "dig.getPeers",
      "summary": "Return the peers this node knows, with peer_id + candidate addresses.",
      "description": "Peer-exchange over RPC: the peers in this node's address book, each with its peer_id (SHA-256 of the peer's TLS SPKI DER) and candidate addresses. Mirrors the gossip RequestPeers/RespondPeers exchange so an agent can drive discovery without speaking the binary peer protocol. NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#peer-rpc.",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "network_id",
          "required": false,
          "description": "Filter to one network (e.g. DIG_MAINNET).",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "limit",
          "required": false,
          "description": "Cap the number of peers returned.",
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "result": {
        "name": "peers",
        "schema": {
          "type": "object",
          "required": [
            "peers"
          ],
          "properties": {
            "peers": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/PeerRecord"
              }
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        },
        {
          "$ref": "#/components/errors/PEER_UNREACHABLE"
        }
      ]
    },
    {
      "name": "dig.announce",
      "summary": "Advertise this node (peer_id + addresses) to a peer or the introducer.",
      "description": "Announce this node's peer_id + candidate addresses so a target peer (or, if `target` is omitted, the relay introducer) learns to reach it. The RPC face of the introducer/announce path. NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#peer-rpc.",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "peer_id",
          "required": true,
          "description": "The announcing node's peer_id.",
          "schema": {
            "$ref": "#/components/schemas/PeerId"
          }
        },
        {
          "name": "addresses",
          "required": true,
          "description": "The announcing node's candidate addresses.",
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CandidateAddress"
            }
          }
        },
        {
          "name": "network_id",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "target",
          "required": false,
          "description": "A specific peer to announce to; omit to register with the relay introducer.",
          "schema": {
            "$ref": "#/components/schemas/PeerId"
          }
        }
      ],
      "result": {
        "name": "announced",
        "schema": {
          "type": "object",
          "required": [
            "accepted"
          ],
          "properties": {
            "accepted": {
              "type": "boolean",
              "description": "Whether the announcement was accepted."
            },
            "known_peers": {
              "type": "integer",
              "minimum": 0,
              "description": "The recipient's resulting peer-view size."
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        },
        {
          "$ref": "#/components/errors/PEER_UNREACHABLE"
        }
      ]
    },
    {
      "name": "dig.getNetworkInfo",
      "summary": "Report this node's identity, reachability, candidate addresses + relay state.",
      "description": "The node's own network posture: its peer_id, listen + STUN-reflexive addresses, candidate addresses, direct-vs-relayed reachability, and relay-reservation state. The self-describe surface for discovery + NAT traversal. NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#peer-rpc.",
      "paramStructure": "by-name",
      "params": [],
      "result": {
        "name": "network_info",
        "schema": {
          "type": "object",
          "required": [
            "peer_id",
            "reachability"
          ],
          "properties": {
            "peer_id": {
              "$ref": "#/components/schemas/PeerId"
            },
            "network_id": {
              "type": "string"
            },
            "listen_addr": {
              "type": "string",
              "description": "The node's configured listen address (host:port)."
            },
            "reflexive_addr": {
              "type": [
                "string",
                "null"
              ],
              "description": "The STUN-discovered public IP:port, or null if not yet learned."
            },
            "candidate_addresses": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/CandidateAddress"
              }
            },
            "reachability": {
              "type": "string",
              "enum": [
                "direct",
                "relayed"
              ],
              "description": "direct = a direct inbound path exists; relayed = only reachable through the relay."
            },
            "relay": {
              "type": "object",
              "description": "The relay reservation state.",
              "properties": {
                "url": {
                  "type": "string",
                  "description": "The relay endpoint (default wss://relay.dig.net:9450)."
                },
                "reserved": {
                  "type": "boolean",
                  "description": "Whether a relay reservation (RLY-001) is currently held."
                },
                "connected_peers": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "dig.getAvailability",
      "summary": "Batch-ask whether this peer holds given stores / roots / capsules (before fetching).",
      "description": "The pre-fetch availability check. Batch per-item query at three granularities inferred from each item's fields — store_id only (has_store), + root (has_root / capsule), + retrieval_key (has_resource). Returns one answer per item (positionally aligned): available plus, where cheap, planning metadata (roots for a store; total_length + chunk_count + complete for a root/resource) so a downloader filters to holders and plans ranges WITHOUT a probe fetch. A small control RPC (message-style, not streamed). Absence is available:false, NOT an error. NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#availability.",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "items",
          "required": true,
          "description": "The stores / roots / capsules to check in one call.",
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailabilityItem"
            }
          }
        }
      ],
      "result": {
        "name": "availability",
        "schema": {
          "type": "object",
          "required": [
            "items"
          ],
          "properties": {
            "items": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/AvailabilityAnswer"
              },
              "description": "One answer per queried item, in the same order."
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "dig.listInventory",
      "summary": "Enumerate what this peer serves — its stores, or the roots it holds for a store.",
      "description": "Discovery variant of availability: omit store_id to list the stores the peer serves; supply it to list the roots the peer holds for that store. Best-effort — a peer MAY cap or omit enumeration (privacy/size); dig.getAvailability is the authoritative per-item check. NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#availability.",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "store_id",
          "required": false,
          "description": "Omit to list stores; supply to list that store's roots.",
          "schema": {
            "$ref": "#/components/schemas/StoreId"
          }
        },
        {
          "name": "limit",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "result": {
        "name": "inventory",
        "schema": {
          "type": "object",
          "properties": {
            "store_id": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$",
              "description": "Echoed when roots are listed for a store."
            },
            "stores": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^[0-9a-f]{64}$",
                "description": "32 bytes as 64 lower-case hex characters."
              },
              "description": "The stores this peer serves (when store_id is omitted)."
            },
            "roots": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^[0-9a-f]{64}$",
                "description": "32 bytes as 64 lower-case hex characters."
              },
              "description": "The roots this peer holds for the store (when store_id is given)."
            }
          }
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        }
      ]
    },
    {
      "name": "dig.fetchRange",
      "summary": "Stream a byte range [offset, offset+length) of a resource or capsule (multi-source).",
      "description": "STREAMING + BYTE-RANGE fetch: return only the requested byte range of a content resource (store_id + retrieval_key) or a whole capsule/.dig (capsule: true, identified by store_id[:root]), delivered as an ordered STREAM of RangeFrame chunks over a logical stream of the multiplexed peer transport (read incrementally with backpressure; reassemble by offset). The FIRST frame carries total_length + chunk_lens + chunk_index + inclusion_proof so the range is INDEPENDENTLY verifiable against the capsule's chain-anchored merkle root — a downloader fans different ranges out to different peers concurrently, verifies each, retries a bad range from another source, and resumes per-range. The range is widened to whole-chunk boundaries so each returned chunk is a complete verifiable unit; length is clamped to the node window (3 MiB). NODE-PROFILE ONLY. See https://docs.dig.net/docs/protocol/peer-network#range.",
      "paramStructure": "by-name",
      "params": [
        {
          "name": "store_id",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/StoreId"
          }
        },
        {
          "name": "retrieval_key",
          "required": false,
          "description": "The content resource to fetch; omit when capsule=true.",
          "schema": {
            "$ref": "#/components/schemas/RetrievalKey"
          }
        },
        {
          "name": "root",
          "required": false,
          "description": "The generation; defaults to the chain-anchored tip.",
          "schema": {
            "$ref": "#/components/schemas/Root"
          }
        },
        {
          "name": "capsule",
          "required": false,
          "description": "true to fetch the whole capsule/.dig (identified by store_id[:root]) instead of a resource.",
          "schema": {
            "type": "boolean",
            "default": false
          }
        },
        {
          "name": "offset",
          "required": false,
          "description": "Byte offset into the resource ciphertext.",
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "length",
          "required": true,
          "description": "Bytes to return; clamped to the node window (3 MiB) and widened to whole-chunk boundaries.",
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "result": {
        "name": "frame",
        "schema": {
          "$ref": "#/components/schemas/RangeFrame"
        }
      },
      "errors": [
        {
          "$ref": "#/components/errors/INVALID_PARAMS"
        },
        {
          "$ref": "#/components/errors/INTERNAL_ERROR"
        },
        {
          "$ref": "#/components/errors/RESOURCE_UNAVAILABLE"
        },
        {
          "$ref": "#/components/errors/RANGE_NOT_SATISFIABLE"
        }
      ]
    }
  ],
  "components": {
    "schemas": {
      "StoreId": {
        "type": "string",
        "pattern": "^[0-9a-f]{64}$",
        "description": "32 bytes as 64 lower-case hex characters.",
        "title": "StoreId"
      },
      "RetrievalKey": {
        "type": "string",
        "pattern": "^[0-9a-f]{64}$",
        "description": "retrieval_key = sha256(urn).",
        "title": "RetrievalKey"
      },
      "Root": {
        "title": "Root",
        "oneOf": [
          {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          {
            "type": "string",
            "const": "latest"
          }
        ],
        "description": "A generation root: 64 hex of one capsule, or the literal \"latest\" for the newest confirmed generation."
      },
      "ChunkObject": {
        "title": "ChunkObject",
        "type": "object",
        "description": "The streaming chunk object returned by every byte-bearing method (dig.getContent, dig.getCapsule, dig.getManifest). Reassemble until `complete`, verify `inclusion_proof` over the whole ciphertext against the CALLER-supplied chain-anchored `root`, split by `chunk_lens`, then AES-256-GCM-SIV-open each chunk. There is NO `decoy` field on the wire: a blind miss is the capsule's own indistinguishable, non-verifying response, discovered client-side by inclusion-proof failure and/or decryption-tag failure.",
        "required": [
          "ciphertext",
          "total_length",
          "offset",
          "length",
          "complete",
          "next_offset",
          "inclusion_proof",
          "root"
        ],
        "properties": {
          "ciphertext": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "This window's bytes, standard base64."
          },
          "total_length": {
            "type": "integer",
            "minimum": 0,
            "description": "The full resource ciphertext length before windowing."
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "description": "Byte offset where this window begins in the full object."
          },
          "length": {
            "type": "integer",
            "minimum": 0,
            "description": "This window's byte length (= decoded ciphertext length)."
          },
          "complete": {
            "type": "boolean",
            "description": "true when offset + length >= total_length."
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The offset to request next, or null when complete."
          },
          "inclusion_proof": {
            "type": [
              "string",
              "null"
            ],
            "contentEncoding": "base64",
            "description": "Base64 merkle inclusion proof for the WHOLE resource, relayed verbatim from the capsule. Sent on every window for getContent/getManifest; empty string / null for getCapsule."
          },
          "chunk_lens": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Per-chunk CIPHERTEXT byte lengths of the full resource, in order. REQUIRED to split + decrypt a multi-chunk resource. Emitted on the FIRST window only (offset == 0); empty/absent ⇒ a single chunk = the whole ciphertext."
          },
          "root": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The resolved generation root (hex). Pin subsequent chunks to it."
          },
          "program_hash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The served .dig's sha256 (hex) — the on-chain program identity."
          }
        }
      },
      "MetadataManifest": {
        "title": "MetadataManifest",
        "type": "object",
        "description": "The store's plaintext, ungated metadata manifest, embedded in the compiled module (Digstore §8.4).",
        "properties": {
          "schema_version": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "authors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "handle": {
                  "type": "string"
                },
                "contact": {
                  "type": "string"
                }
              }
            }
          },
          "license": {
            "type": "string"
          },
          "homepage": {
            "type": "string"
          },
          "repository": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "icon": {
            "type": "string"
          },
          "content_type": {
            "type": "string"
          },
          "links": {
            "type": "object"
          },
          "custom": {
            "type": "object"
          }
        }
      },
      "CapsuleEntry": {
        "title": "CapsuleEntry",
        "type": "object",
        "description": "One confirmed capsule (anchored generation) in a store lineage.",
        "required": [
          "seq",
          "root"
        ],
        "properties": {
          "seq": {
            "type": "integer",
            "minimum": 0,
            "description": "Monotonic generation number."
          },
          "root": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The generation root passed to the byte methods."
          },
          "program_hash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "32 bytes as 64 lower-case hex characters."
          },
          "coin_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The anchoring spend coin id."
          },
          "anchored_at": {
            "type": "integer",
            "description": "Unix timestamp of the anchoring spend."
          }
        }
      },
      "PeerId": {
        "type": "string",
        "pattern": "^[0-9a-f]{64}$",
        "title": "PeerId",
        "description": "A DIG Node peer identity: SHA-256 of the peer's TLS SubjectPublicKeyInfo DER, as 64 lower-case hex characters (32 bytes)."
      },
      "CandidateAddress": {
        "title": "CandidateAddress",
        "type": "object",
        "description": "One address at which a peer may be reachable, tagged by how it was learned. Peers dial candidates most-direct-first.",
        "required": [
          "host",
          "port",
          "kind"
        ],
        "properties": {
          "host": {
            "type": "string",
            "description": "IP literal or hostname."
          },
          "port": {
            "type": "integer",
            "minimum": 0,
            "maximum": 65535,
            "description": "The peer's P2P port (default 9444)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "direct",
              "reflexive",
              "mapped",
              "relay"
            ],
            "description": "How the address was learned: advertised/observed direct, STUN reflexive, UPnP/NAT-PMP/PCP mapped, or relay-reachable."
          }
        }
      },
      "PeerRecord": {
        "title": "PeerRecord",
        "type": "object",
        "description": "A known peer with its identity and candidate addresses (the peer-exchange record).",
        "required": [
          "peer_id",
          "addresses"
        ],
        "properties": {
          "peer_id": {
            "$ref": "#/components/schemas/PeerId"
          },
          "addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CandidateAddress"
            },
            "description": "The peer's candidate addresses."
          },
          "network_id": {
            "type": "string",
            "description": "The network the peer is on (e.g. DIG_MAINNET)."
          },
          "last_seen": {
            "type": "integer",
            "description": "Unix seconds this peer was last seen."
          },
          "via": {
            "type": "string",
            "enum": [
              "direct",
              "relay"
            ],
            "description": "How this node currently reaches the peer."
          }
        }
      },
      "AvailabilityItem": {
        "title": "AvailabilityItem",
        "type": "object",
        "description": "One item to check in a dig.getAvailability batch. Granularity is inferred from the fields present: store_id only = has_store; + root = has_root (the capsule store_id:root); + retrieval_key = has_resource within the capsule.",
        "required": [
          "store_id"
        ],
        "properties": {
          "store_id": {
            "$ref": "#/components/schemas/StoreId"
          },
          "root": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Optional generation root — narrows the check to that capsule."
          },
          "retrieval_key": {
            "$ref": "#/components/schemas/RetrievalKey"
          }
        }
      },
      "AvailabilityAnswer": {
        "title": "AvailabilityAnswer",
        "type": "object",
        "description": "One answer in a dig.getAvailability result, positionally aligned with the queried items. Reports whether the peer holds the item plus (where cheap) planning metadata so the caller can partition ranges without a probe fetch.",
        "required": [
          "available"
        ],
        "properties": {
          "available": {
            "type": "boolean",
            "description": "Whether the peer holds the queried item."
          },
          "roots": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$",
              "description": "32 bytes as 64 lower-case hex characters."
            },
            "description": "STORE granularity: the generation roots the peer currently holds for the store, newest-first."
          },
          "total_length": {
            "type": "integer",
            "minimum": 0,
            "description": "ROOT/RESOURCE granularity: the resource/capsule ciphertext length."
          },
          "chunk_count": {
            "type": "integer",
            "minimum": 0,
            "description": "ROOT/RESOURCE granularity: the number of chunks (plan ranges against this)."
          },
          "complete": {
            "type": "boolean",
            "description": "Whether the peer holds the FULL resource/capsule (true) or only part of it (false); a partial holder still serves the ranges it has."
          }
        }
      },
      "RangeFrame": {
        "title": "RangeFrame",
        "type": "object",
        "description": "One frame of a streamed dig.fetchRange response. Data is delivered as an ordered stream of these frames over a logical stream of the multiplexed peer transport — the caller reads incrementally with backpressure and reassembles by `offset`. The FIRST frame (offset == range start) additionally carries the range-verification metadata (total_length, chunk_lens, chunk_index, inclusion_proof) so a range fetched from ONE peer is independently verifiable against the capsule's chain-anchored merkle root without the whole file. See https://docs.dig.net/docs/protocol/peer-network#range.",
        "required": [
          "offset",
          "length",
          "bytes",
          "complete"
        ],
        "properties": {
          "offset": {
            "type": "integer",
            "minimum": 0,
            "description": "This frame's start offset within the requested range (bytes into the resource ciphertext)."
          },
          "length": {
            "type": "integer",
            "minimum": 0,
            "description": "This frame's byte length (= decoded `bytes` length)."
          },
          "bytes": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "This frame's ciphertext bytes, standard base64."
          },
          "complete": {
            "type": "boolean",
            "description": "true when this is the final frame of the requested range."
          },
          "total_length": {
            "type": "integer",
            "minimum": 0,
            "description": "FIRST FRAME ONLY: the full resource ciphertext length (so a client can plan its ranges)."
          },
          "chunk_lens": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "description": "FIRST FRAME ONLY: per-chunk ciphertext lengths of the WHOLE resource, in order (identical to the dig RPC chunk_lens). Maps a byte range to the chunk(s) covering it; required to split + verify + decrypt."
          },
          "chunk_index": {
            "type": "integer",
            "minimum": 0,
            "description": "FIRST FRAME ONLY: index into chunk_lens of the first chunk in this range."
          },
          "inclusion_proof": {
            "type": [
              "string",
              "null"
            ],
            "contentEncoding": "base64",
            "description": "FIRST FRAME ONLY: base64 merkle inclusion proof of the WHOLE resource against the generation `root`, relayed verbatim. Verify the range against the CALLER-supplied chain-anchored root — the node is never the trust anchor. null for capsule fetches (capsule: true), which self-verify on install."
          },
          "root": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "FIRST FRAME ONLY: the resolved generation root the inclusion_proof is against."
          }
        }
      }
    },
    "errors": {
      "PARSE_ERROR": {
        "code": -32700,
        "message": "Parse error",
        "data": {
          "type": "object"
        }
      },
      "INVALID_REQUEST": {
        "code": -32600,
        "message": "Invalid request",
        "data": {
          "type": "object"
        }
      },
      "METHOD_NOT_FOUND": {
        "code": -32601,
        "message": "Method not found",
        "data": {
          "type": "object"
        }
      },
      "INVALID_PARAMS": {
        "code": -32602,
        "message": "Invalid params",
        "data": {
          "type": "object"
        }
      },
      "INTERNAL_ERROR": {
        "code": -32603,
        "message": "Internal error",
        "data": {
          "type": "object"
        }
      },
      "RESOURCE_UNAVAILABLE": {
        "code": -32004,
        "message": "Resource not available at the requested root",
        "data": {
          "type": "object"
        }
      },
      "ROOT_NOT_ANCHORED": {
        "code": -32005,
        "message": "Root not chain-anchored",
        "data": {
          "type": "object"
        }
      },
      "PEER_UNREACHABLE": {
        "code": -32006,
        "message": "Peer unreachable",
        "data": {
          "type": "object"
        }
      },
      "RANGE_NOT_SATISFIABLE": {
        "code": -32007,
        "message": "Range not satisfiable",
        "data": {
          "type": "object"
        }
      },
      "CONTENT_REDIRECT": {
        "code": -32008,
        "message": "Content held elsewhere — redirect",
        "data": {
          "type": "object"
        }
      },
      "UPSTREAM_ERROR": {
        "code": -32010,
        "message": "Upstream error",
        "data": {
          "type": "object"
        }
      },
      "STAGE_DIR_UNREADABLE": {
        "code": -32011,
        "message": "Stage: source directory unreadable",
        "data": {
          "type": "object"
        }
      },
      "STAGE_NO_FILES": {
        "code": -32012,
        "message": "Stage: no files to stage",
        "data": {
          "type": "object"
        }
      },
      "STAGE_OVER_CAP": {
        "code": -32013,
        "message": "Stage: content exceeds capsule size cap",
        "data": {
          "type": "object"
        }
      },
      "STAGE_COMPILE_IO": {
        "code": -32014,
        "message": "Stage: compile/IO failure",
        "data": {
          "type": "object"
        }
      },
      "ONION_CIRCUIT_UNAVAILABLE": {
        "code": -32020,
        "message": "Onion circuit unavailable",
        "data": {
          "type": "object"
        }
      },
      "PRIVACY_REQUIRES_LOCAL_NODE": {
        "code": -32021,
        "message": "Privacy requires a local node",
        "data": {
          "type": "object"
        }
      },
      "ONION_HOPS_OUT_OF_RANGE": {
        "code": -32022,
        "message": "Onion hop count out of range",
        "data": {
          "type": "object"
        }
      },
      "CONTROL_UNAUTHORIZED": {
        "code": -32030,
        "message": "Unauthorized (control)",
        "data": {
          "type": "object"
        }
      },
      "CONTROL_NOT_SUPPORTED": {
        "code": -32031,
        "message": "Not supported (control)",
        "data": {
          "type": "object"
        }
      },
      "CONTROL_ERROR": {
        "code": -32032,
        "message": "Control error",
        "data": {
          "type": "object"
        }
      }
    }
  },
  "externalDocs": {
    "description": "dig RPC methods (prose)",
    "url": "https://docs.dig.net/docs/protocol/dig-rpc"
  }
}
