@inversealtruism/cairn-sdk 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,6 @@ The **Compute Substrate dApp kit:** one cohesive toolkit for building apps on CS
8
8
  | `cairn.chain` | Node RPC + transaction builders + a verifying **light client** (re-exports the `csd-*` primitives). |
9
9
  | `cairn.index` | The L2 **explorer/indexer**: REST + merkle proofs + live SSE/WS feeds. |
10
10
  | `cairn.content` | **Self-certifying content:** hash for an on-chain Propose, fetch with client-side verification. |
11
- | `cairn.registry` | L3 **peer / gateway / identity** resolution. |
12
11
  | `cairn.names` | **.csd names + CairnX reads:** name resolution, reverse/primary lookup, tokens, offers, bids, canonical state. |
13
12
 
14
13
  ```bash
@@ -40,8 +39,8 @@ cairn.index.streamAll({ onBlock: (e) => console.log("new block", e) });
40
39
 
41
40
  The SDK follows the exact model MetaMask uses, there is **no allowlist you maintain**:
42
41
 
43
- - **`connect()` / `getAddress()`** grant *address visibility*. The first time a site connects, the user approves once; after that the wallet answers silently (the site shows up under **Settings → Connected sites**, revocable anytime). This is the only "silent" call.
44
- - **Every signing / fund-moving call:** `send`, `propose`, `attest`, `signIn`, `sealClaim`, `revealClaim`, **always** opens the wallet's clear-signing approval window, **every time**, no matter what. Being "connected" never pre-approves a signature. A connected site cannot move a satoshi without an explicit, fully-disclosed approval click.
42
+ - **`connect()` / `getAddress()`** grant *address visibility*. The first time a site connects, the user approves once; after that the wallet answers silently (the site shows up under **Settings → Connected sites**, revocable anytime). These are the only calls that can return the address without a prompt. `getPermissions()` (read this site's own grant) and `revokePermissions()` (drop it) are silent too; neither signs anything.
43
+ - **Every signing / fund-moving call:** `send`, `propose`, `attest`, `fillOffer`, `sealClaim`, `revealClaim` and `signInWithCsd`, **always** opens the wallet's clear-signing approval window, **every time**, no matter what. Being "connected" never pre-approves a signature. A connected site cannot move a satoshi without an explicit, fully-disclosed approval click. The legacy `signIn()` is deprecated and first-party-only: the wallet refuses it from any other site with `FIRST_PARTY_ONLY` before prompting; use `signInWithCsd()`.
45
44
 
46
45
  ```ts
47
46
  import { connect, UserRejectedError, NotInstalledError } from "@inversealtruism/cairn-sdk";
@@ -57,29 +56,27 @@ try {
57
56
 
58
57
  ## API by namespace
59
58
 
60
- **`cairn.index`:** `tipHeight()`, `block()/blockTxids()`, `tx()/txStatus()/txMerkleProof()`, `address()/addressTxs()/addressUtxo()`, `domains()/domainProposals(domain)`, `proposal()/attestations()`, `reputation()`, `registryPeers()/registryGateways()/identity()`, **`verifyInclusion(txid)`** (trust-minimized), `streamAll()/streamBlocks()/streamDomain()` (SSE), `subscribe()` (WS).
59
+ **`cairn.index`:** `tipHeight()`, `block()/blockTxids()`, `tx()/txStatus()/txMerkleProof()`, `address()/addressTxs()/addressUtxo()`, `domains()/domainProposals(domain)`, `proposal()/attestations()`, `reputation()`, **`verifyInclusion(txid)`** (trust-minimized), `streamAll()/streamBlocks()/streamDomain()` (SSE), `subscribe()` (WS).
61
60
 
62
- **`cairn.names`:** `resolve(name)` (display-path name to address), `name(name)`/`nameHistory(name)`, `primary(addr)` (reverse lookup)/`namesOf(addr)`, `names()`, `tokens()/token(ticker)`, `offers()`, `bids()`, `state()` (the canonical CairnX state). Reads go through the public `/trade/api/cairnx/*` proxy; for payment-grade name resolution verify through the wallet or a replaying resolver, not a bare read (see `src/names.ts` header).
61
+ **`cairn.names`:** `resolve(name)` (display-path name to address), `name(name)`/`nameHistory(name)`, `primary(addr)` (reverse lookup)/`namesOf(addr)`, `names()`, `tokens()/token(ticker)`, `offers()`/`bids()` (open rows by default; pass `{ status }` for another status, or `{ status: "all" }` for every row), `state()` (the canonical CairnX state). Reads go through the public `/trade/api/cairnx/*` proxy; for payment-grade name resolution verify through the wallet or a replaying resolver, not a bare read (see `src/names.ts` header).
63
62
 
64
63
  **`cairn.content`:** `prepare(obj)`/`put(obj)` → `{ payloadHash, canonical, bytes }`; `get(hash)` / `getBytes(hash)` (fetch **and verify** `sha256(bytes) === hash`, throws `ContentVerificationError` on tamper); `hash(obj)`.
65
64
 
66
65
  **`cairn.chain`:** `tip()`, `utxos(addr)`, `submit(nodeJsonTx)`, `.client` (full `CsdClient`), `.light()` (verifying light client). The package also re-exports the primitives under the `/chain` subpath: `buildSend/buildPropose/buildAttest`, `signTx`, `keygen`, `payloadHash`, `verifyMerkleProof`, `LightClient`, etc.
67
66
 
68
- **`cairn.registry`:** `gateways()`, `peers()`, `resolveName(handle)`, `reverseName(addr)`, `.fromRecords` (deterministic local resolvers).
69
-
70
- Subpath imports are available for tree-shaking: `@inversealtruism/cairn-sdk/{connect,indexer,content,registry,chain,controller,react}`.
67
+ Subpath imports are available for tree-shaking: `@inversealtruism/cairn-sdk/{connect,indexer,content,chain,controller,react}`.
71
68
 
72
69
  ## Examples
73
70
 
74
- - **`examples/read-only.mjs`:** runs today against live mainnet, no wallet, no build: `npm run test:live`. Demonstrates chain/indexer/registry reads + verified merkle inclusion + verified content fetch.
75
- - **`examples/hello-csd/`:** a no-framework browser dApp (connect → read recent proposals → live feed). Build the bundle with `npm run build:example`, then serve the folder from **localhost** (the wallet injects there) with the Cairn Wallet installed.
71
+ - **`examples/read-only.mjs`:** runs against live mainnet with no wallet. It imports the built `dist/`, so run `pnpm build` first, then `pnpm test:live`. Demonstrates chain/indexer reads + verified merkle inclusion + verified content fetch.
72
+ - **`examples/hello-csd/`:** a no-framework browser dApp (connect → read recent proposals → live feed). Build the bundle with `pnpm build:example`, then serve the folder from **localhost** (the wallet injects there) with the Cairn Wallet installed.
76
73
 
77
74
  ## Trust model & honest limits
78
75
 
79
- - **Content is always verified client-side.** `cairn.content.get()` rejects bytes that don't hash to the requested `payloadHash`, an untrusted gateway can't serve tampered content.
80
- - **Merkle inclusion is trust-minimized, to the strength of your header source.** `verifyInclusion()` folds the proof and cross-checks its root against a header merkle from `headerMerkleAt`. The default `Cairn` wiring backs that with a light client that PoW-verifies headers forward from a pinned checkpoint, so a match reads `trustLevel: "verified-inclusion"` with `included: true`. A header within 12 blocks of the light client's cached tip is first compared with the header the base serves at that height, so a block orphaned by a reorg stops counting; the hosted base edge-caches rows at or below its tip minus 6, so there this catches reorgs of up to 6 blocks. When no header can be verified (below the checkpoint, header source unreachable, no source configured) the result is `"proof-consistent"` with `included: false` and a `reason`: the indexer alone vouches for it. Gate on `included` or on `trustLevel === "verified-inclusion"`; they agree.
81
- - **Balances are RPC-trusted.** Headers don't commit to the UTXO set; balance reads trust the node/proxy (same as every light client).
82
- - **Indexer/swarm run behind the cairn proxy.** By default `cairn.index` and content resolution use the cairn server's hardened, read-only, rate-limited `/explorer/api` reverse proxy (no separate public indexer needed). **SSE works through it; `subscribe()` (WebSocket) needs a direct indexer endpoint:** set `baseUrls.indexer` to a private/localhost indexer for WS.
76
+ Content bytes are always verified client-side; merkle inclusion is verified when a PoW-verified header backs it (`trustLevel: "verified-inclusion"`); balances are RPC-trusted. The full trust model (each `trustLevel`, the checkpoint, reorgs near the tip) is in [`docs/SDK-GUIDE.md`](docs/SDK-GUIDE.md#what-the-sdk-verifies-vs-trusts-read-this).
77
+
78
+ - **Content comes from the cairn origin.** `cairn.content` reads `/content/<hash>` on the cairn base and verifies every byte against the hash.
79
+ - **The indexer runs behind the cairn proxy.** By default `cairn.index` uses the cairn server's hardened, read-only, rate-limited `/explorer/api` reverse proxy (no separate public indexer needed). **SSE works through that proxy; `subscribe()` (WebSocket) needs a direct indexer endpoint:** set `baseUrls.indexer` to a private/localhost indexer for WS.
83
80
  - **The wallet injects on every site** (connect-anywhere shipped in 0.2.4x) behind a per-origin consent gate: a site sees nothing until the user approves the connection, and some request kinds stay first-party-only (the `FIRST_PARTY_ONLY` error code).
84
81
 
85
82
  ## Configuration
@@ -91,7 +88,6 @@ new Cairn({
91
88
  cairn: "https://cairn-substrate.com", // /api/rpc proxy + /api/headers + /content origin + names
92
89
  rpc: "https://cairn-substrate.com/api/rpc", // node RPC (proxy)
93
90
  indexer: "https://cairn-substrate.com/explorer/api",
94
- swarm: undefined, // optional direct swarm gateway
95
91
  },
96
92
  fetch, // custom fetch (Node <18, tests)
97
93
  timeoutMs: 15000,
@@ -103,8 +99,8 @@ new Cairn({
103
99
 
104
100
  ```bash
105
101
  pnpm build && pnpm test # unit (offline): error mapping, client paths, content+merkle verify
106
- pnpm test:e2e:read # live reads vs mainnet + adversarial (free)
107
- pnpm test:e2e:wallet # real extension + real connector under Xvfb: connect/consent/sign (free)
102
+ pnpm test:live # examples/read-only.mjs + live reads vs mainnet + adversarial (free)
103
+ pnpm test:live:wallet # real extension + real connector under Xvfb: connect/consent/sign (free)
108
104
  ```
109
105
 
110
106
  See [`test/e2e/README.md`](test/e2e/README.md) for coverage, requirements, and cost of each layer. All three suites are free; none spends CSD.
@@ -69,18 +69,6 @@ var IndexerClient = class {
69
69
  attestations(id) {
70
70
  return this.http.getJson(`/proposal/${encodeURIComponent(id)}/attestations`);
71
71
  }
72
- registryPeers() {
73
- return this.http.getJson("/registry/peers");
74
- }
75
- registryGateways() {
76
- return this.http.getJson("/registry/gateways");
77
- }
78
- identity(handle) {
79
- return this.http.getJson(`/identity/${encodeURIComponent(handle)}`);
80
- }
81
- reverseIdentity(addr) {
82
- return this.http.getJson(`/address/${encodeURIComponent(addr)}/identity`);
83
- }
84
72
  // ---- trust-minimized inclusion ----------------------------------------
85
73
  /**
86
74
  * Verify a tx is included in a block by folding its merkle branch to the root
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  CairnError,
3
3
  ContentVerificationError
4
- } from "./chunk-2A4AJBO5.js";
4
+ } from "./chunk-UAPWZZQK.js";
5
5
 
6
6
  // src/content.ts
7
7
  import { payloadHash, canonicalJson, verifyContentBytes } from "@inversealtruism/csd-codec";
8
8
  var ContentClient = class {
9
- sources;
9
+ cairn;
10
10
  constructor(opts) {
11
- this.sources = [];
12
- if (opts.swarm) this.sources.push({ name: "swarm", http: opts.swarm, path: (h) => `/content/${h}` });
13
- if (opts.indexer) this.sources.push({ name: "indexer", http: opts.indexer, path: (h) => `/content/${h}` });
14
- if (opts.cairn) this.sources.push({ name: "cairn", http: opts.cairn, path: (h) => `/content/${h}` });
11
+ if (!opts?.cairn || typeof opts.cairn.getBytes !== "function") {
12
+ throw new TypeError("ContentClient needs a `cairn` Http client (the swarm and indexer sources were removed in 0.7.0)");
13
+ }
14
+ this.cairn = opts.cairn;
15
15
  }
16
16
  /**
17
17
  * Compute the canonical hash + bytes for an object, ready to anchor on-chain.
@@ -35,31 +35,21 @@ var ContentClient = class {
35
35
  }
36
36
  /**
37
37
  * Fetch content by hash and VERIFY it self-certifies (sha256(bytes) == hash).
38
- * Tries each configured source in order; a source that is unreachable, lacks
39
- * the content or serves bytes that don't match the hash is skipped. Returns the
40
- * first verified bytes, or null if no source holds it. Throws
41
- * ContentVerificationError only when no source served verified bytes and at
42
- * least one served mismatching bytes (tampering / wrong object).
38
+ * Returns the verified bytes, or null when the origin does not hold the content
39
+ * or cannot be reached (as 0.6.0 did when every source failed). Throws
40
+ * ContentVerificationError when the origin serves bytes that don't match the hash.
43
41
  */
44
42
  async getBytes(hash) {
45
43
  const h = normalizeHash(hash);
46
- let mismatched = false;
47
- for (const src of this.sources) {
48
- let got = null;
49
- try {
50
- got = await src.http.getBytes(src.path(h));
51
- } catch {
52
- continue;
53
- }
54
- if (!got) continue;
55
- if (!verifyContentBytes(got.bytes, h)) {
56
- mismatched = true;
57
- continue;
58
- }
59
- return got.bytes;
44
+ let got = null;
45
+ try {
46
+ got = await this.cairn.getBytes(`/content/${h}`);
47
+ } catch {
48
+ return null;
60
49
  }
61
- if (mismatched) throw new ContentVerificationError(h);
62
- return null;
50
+ if (!got) return null;
51
+ if (!verifyContentBytes(got.bytes, h)) throw new ContentVerificationError(h);
52
+ return got.bytes;
63
53
  }
64
54
  /** Fetch + verify + parse as UTF-8 JSON. Returns null if not found. Throws a CairnError with code
65
55
  * CONTENT_NOT_JSON when the verified bytes are not JSON. */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getWallet
3
- } from "./chunk-BMH2MACB.js";
3
+ } from "./chunk-WWO3FXHG.js";
4
4
 
5
5
  // src/controller.ts
6
6
  var DISCONNECTED = Object.freeze({ status: "disconnected", account: null, error: null });
@@ -1,5 +1,5 @@
1
1
  // src/errors.ts
2
- var SDK_VERSION = "0.6.0";
2
+ var SDK_VERSION = "0.8.0";
3
3
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
4
4
  var CairnError = class extends Error {
5
5
  /** Stable machine code for programmatic branching. */
@@ -4,7 +4,7 @@ import {
4
4
  UnsupportedMethodError,
5
5
  mapProviderError,
6
6
  mapSubmitResultError
7
- } from "./chunk-2A4AJBO5.js";
7
+ } from "./chunk-UAPWZZQK.js";
8
8
 
9
9
  // src/connect.ts
10
10
  var DEFAULT_PROVIDER_TIMEOUT_MS = 10 * 6e4;
package/dist/connect.cjs CHANGED
@@ -30,7 +30,7 @@ __export(connect_exports, {
30
30
  module.exports = __toCommonJS(connect_exports);
31
31
 
32
32
  // src/errors.ts
33
- var SDK_VERSION = "0.6.0";
33
+ var SDK_VERSION = "0.8.0";
34
34
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
35
35
  var CairnError = class extends Error {
36
36
  /** Stable machine code for programmatic branching. */
package/dist/connect.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  discoverProviders,
6
6
  getWallet,
7
7
  isInstalled
8
- } from "./chunk-BMH2MACB.js";
9
- import "./chunk-2A4AJBO5.js";
8
+ } from "./chunk-WWO3FXHG.js";
9
+ import "./chunk-UAPWZZQK.js";
10
10
  export {
11
11
  WalletConnection,
12
12
  connect,
package/dist/content.cjs CHANGED
@@ -26,7 +26,7 @@ module.exports = __toCommonJS(content_exports);
26
26
  var import_csd_codec = require("@inversealtruism/csd-codec");
27
27
 
28
28
  // src/errors.ts
29
- var SDK_VERSION = "0.6.0";
29
+ var SDK_VERSION = "0.8.0";
30
30
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
31
31
  var CairnError = class extends Error {
32
32
  /** Stable machine code for programmatic branching. */
@@ -80,12 +80,12 @@ var ContentVerificationError = class extends CairnError {
80
80
 
81
81
  // src/content.ts
82
82
  var ContentClient = class {
83
- sources;
83
+ cairn;
84
84
  constructor(opts) {
85
- this.sources = [];
86
- if (opts.swarm) this.sources.push({ name: "swarm", http: opts.swarm, path: (h) => `/content/${h}` });
87
- if (opts.indexer) this.sources.push({ name: "indexer", http: opts.indexer, path: (h) => `/content/${h}` });
88
- if (opts.cairn) this.sources.push({ name: "cairn", http: opts.cairn, path: (h) => `/content/${h}` });
85
+ if (!opts?.cairn || typeof opts.cairn.getBytes !== "function") {
86
+ throw new TypeError("ContentClient needs a `cairn` Http client (the swarm and indexer sources were removed in 0.7.0)");
87
+ }
88
+ this.cairn = opts.cairn;
89
89
  }
90
90
  /**
91
91
  * Compute the canonical hash + bytes for an object, ready to anchor on-chain.
@@ -109,31 +109,21 @@ var ContentClient = class {
109
109
  }
110
110
  /**
111
111
  * Fetch content by hash and VERIFY it self-certifies (sha256(bytes) == hash).
112
- * Tries each configured source in order; a source that is unreachable, lacks
113
- * the content or serves bytes that don't match the hash is skipped. Returns the
114
- * first verified bytes, or null if no source holds it. Throws
115
- * ContentVerificationError only when no source served verified bytes and at
116
- * least one served mismatching bytes (tampering / wrong object).
112
+ * Returns the verified bytes, or null when the origin does not hold the content
113
+ * or cannot be reached (as 0.6.0 did when every source failed). Throws
114
+ * ContentVerificationError when the origin serves bytes that don't match the hash.
117
115
  */
118
116
  async getBytes(hash) {
119
117
  const h = normalizeHash(hash);
120
- let mismatched = false;
121
- for (const src of this.sources) {
122
- let got = null;
123
- try {
124
- got = await src.http.getBytes(src.path(h));
125
- } catch {
126
- continue;
127
- }
128
- if (!got) continue;
129
- if (!(0, import_csd_codec.verifyContentBytes)(got.bytes, h)) {
130
- mismatched = true;
131
- continue;
132
- }
133
- return got.bytes;
118
+ let got = null;
119
+ try {
120
+ got = await this.cairn.getBytes(`/content/${h}`);
121
+ } catch {
122
+ return null;
134
123
  }
135
- if (mismatched) throw new ContentVerificationError(h);
136
- return null;
124
+ if (!got) return null;
125
+ if (!(0, import_csd_codec.verifyContentBytes)(got.bytes, h)) throw new ContentVerificationError(h);
126
+ return got.bytes;
137
127
  }
138
128
  /** Fetch + verify + parse as UTF-8 JSON. Returns null if not found. Throws a CairnError with code
139
129
  * CONTENT_NOT_JSON when the verified bytes are not JSON. */
@@ -1,23 +1,19 @@
1
1
  import { H as Http } from './http-C9C4L4hz.cjs';
2
2
 
3
3
  interface ContentClientOptions {
4
- /** Swarm gateway HTTP client (e.g. https://cairn-substrate.com/swarm). */
5
- swarm?: Http;
6
- /** Cairn origin HTTP client (serves /content as origin + fallback). */
7
- cairn?: Http;
8
- /** Indexer HTTP client (also joins the swarm gateway at /content). */
9
- indexer?: Http;
4
+ /** Cairn origin HTTP client; it serves `/content/<hash>`. */
5
+ cairn: Http;
10
6
  }
11
7
  interface PreparedContent {
12
8
  /** The 0x-prefixed sha256 payload hash that goes on-chain. */
13
9
  payloadHash: string;
14
10
  /** The exact canonical JSON string that was hashed. */
15
11
  canonical: string;
16
- /** UTF-8 bytes of the canonical JSON (what the swarm stores / serves). */
12
+ /** UTF-8 bytes of the canonical JSON (what the origin stores and serves). */
17
13
  bytes: Uint8Array;
18
14
  }
19
15
  declare class ContentClient {
20
- private readonly sources;
16
+ private readonly cairn;
21
17
  constructor(opts: ContentClientOptions);
22
18
  /**
23
19
  * Compute the canonical hash + bytes for an object, ready to anchor on-chain.
@@ -30,11 +26,9 @@ declare class ContentClient {
30
26
  hash(obj: unknown): string;
31
27
  /**
32
28
  * Fetch content by hash and VERIFY it self-certifies (sha256(bytes) == hash).
33
- * Tries each configured source in order; a source that is unreachable, lacks
34
- * the content or serves bytes that don't match the hash is skipped. Returns the
35
- * first verified bytes, or null if no source holds it. Throws
36
- * ContentVerificationError only when no source served verified bytes and at
37
- * least one served mismatching bytes (tampering / wrong object).
29
+ * Returns the verified bytes, or null when the origin does not hold the content
30
+ * or cannot be reached (as 0.6.0 did when every source failed). Throws
31
+ * ContentVerificationError when the origin serves bytes that don't match the hash.
38
32
  */
39
33
  getBytes(hash: string): Promise<Uint8Array | null>;
40
34
  /** Fetch + verify + parse as UTF-8 JSON. Returns null if not found. Throws a CairnError with code
package/dist/content.d.ts CHANGED
@@ -1,23 +1,19 @@
1
1
  import { H as Http } from './http-C9C4L4hz.js';
2
2
 
3
3
  interface ContentClientOptions {
4
- /** Swarm gateway HTTP client (e.g. https://cairn-substrate.com/swarm). */
5
- swarm?: Http;
6
- /** Cairn origin HTTP client (serves /content as origin + fallback). */
7
- cairn?: Http;
8
- /** Indexer HTTP client (also joins the swarm gateway at /content). */
9
- indexer?: Http;
4
+ /** Cairn origin HTTP client; it serves `/content/<hash>`. */
5
+ cairn: Http;
10
6
  }
11
7
  interface PreparedContent {
12
8
  /** The 0x-prefixed sha256 payload hash that goes on-chain. */
13
9
  payloadHash: string;
14
10
  /** The exact canonical JSON string that was hashed. */
15
11
  canonical: string;
16
- /** UTF-8 bytes of the canonical JSON (what the swarm stores / serves). */
12
+ /** UTF-8 bytes of the canonical JSON (what the origin stores and serves). */
17
13
  bytes: Uint8Array;
18
14
  }
19
15
  declare class ContentClient {
20
- private readonly sources;
16
+ private readonly cairn;
21
17
  constructor(opts: ContentClientOptions);
22
18
  /**
23
19
  * Compute the canonical hash + bytes for an object, ready to anchor on-chain.
@@ -30,11 +26,9 @@ declare class ContentClient {
30
26
  hash(obj: unknown): string;
31
27
  /**
32
28
  * Fetch content by hash and VERIFY it self-certifies (sha256(bytes) == hash).
33
- * Tries each configured source in order; a source that is unreachable, lacks
34
- * the content or serves bytes that don't match the hash is skipped. Returns the
35
- * first verified bytes, or null if no source holds it. Throws
36
- * ContentVerificationError only when no source served verified bytes and at
37
- * least one served mismatching bytes (tampering / wrong object).
29
+ * Returns the verified bytes, or null when the origin does not hold the content
30
+ * or cannot be reached (as 0.6.0 did when every source failed). Throws
31
+ * ContentVerificationError when the origin serves bytes that don't match the hash.
38
32
  */
39
33
  getBytes(hash: string): Promise<Uint8Array | null>;
40
34
  /** Fetch + verify + parse as UTF-8 JSON. Returns null if not found. Throws a CairnError with code
package/dist/content.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ContentClient
3
- } from "./chunk-QEYBWBXC.js";
4
- import "./chunk-2A4AJBO5.js";
3
+ } from "./chunk-DTPADO7N.js";
4
+ import "./chunk-UAPWZZQK.js";
5
5
  export {
6
6
  ContentClient
7
7
  };
@@ -25,7 +25,7 @@ __export(controller_exports, {
25
25
  module.exports = __toCommonJS(controller_exports);
26
26
 
27
27
  // src/errors.ts
28
- var SDK_VERSION = "0.6.0";
28
+ var SDK_VERSION = "0.8.0";
29
29
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
30
30
  var CairnError = class extends Error {
31
31
  /** Stable machine code for programmatic branching. */
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  CairnController
3
- } from "./chunk-MLNW2RQB.js";
4
- import "./chunk-BMH2MACB.js";
5
- import "./chunk-2A4AJBO5.js";
3
+ } from "./chunk-JXBO4LV6.js";
4
+ import "./chunk-WWO3FXHG.js";
5
+ import "./chunk-UAPWZZQK.js";
6
6
  export {
7
7
  CairnController
8
8
  };