@inversealtruism/cairn-sdk 0.2.2 → 0.3.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/dist/react.cjs CHANGED
@@ -26,7 +26,7 @@ __export(react_exports, {
26
26
  module.exports = __toCommonJS(react_exports);
27
27
 
28
28
  // src/errors.ts
29
- var SDK_VERSION = "0.2.2";
29
+ var SDK_VERSION = "0.3.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. */
@@ -37,6 +37,12 @@ var CairnError = class extends Error {
37
37
  docsPath;
38
38
  /** The cairn-sdk version that produced this error. */
39
39
  version = SDK_VERSION;
40
+ /**
41
+ * Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
42
+ * declines (the default); `true` only for provably transient infra faults where nothing was signed.
43
+ * A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
44
+ */
45
+ retryable;
40
46
  constructor(shortMessage, opts = {}) {
41
47
  const docs = opts.docsPath;
42
48
  super(
@@ -47,6 +53,7 @@ var CairnError = class extends Error {
47
53
  this.code = opts.code ?? "UNKNOWN";
48
54
  this.shortMessage = shortMessage;
49
55
  this.docsPath = docs;
56
+ this.retryable = opts.retryable ?? false;
50
57
  }
51
58
  /**
52
59
  * Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
@@ -83,11 +90,43 @@ var UnsupportedMethodError = class extends CairnError {
83
90
  super(message, { code: "UNSUPPORTED_METHOD", docsPath: "/errors#unsupported-method" });
84
91
  }
85
92
  };
93
+ var SubmitInFlightError = class extends CairnError {
94
+ /** The locally-computed consensus txid to reconcile against the chain (may be undefined if the wallet omitted it). */
95
+ txid;
96
+ /** Always true: the tx MAY be in the mempool. Reconcile via `txid`; never blind-retry. */
97
+ maybeSent = true;
98
+ constructor(message, code, txid) {
99
+ super(message, { code, docsPath: "/errors#submit-inflight", retryable: false });
100
+ this.txid = txid;
101
+ }
102
+ };
86
103
  var NATIVE_CODES = /* @__PURE__ */ new Set(["ACCOUNT_CHANGED", "FIRST_PARTY_ONLY", "RATE_LIMITED", "APPROVAL_CLOSED", "FORBIDDEN", "INTERNAL"]);
104
+ var NESTED_TRANSIENT = /* @__PURE__ */ new Set(["VERIFY_UNAVAILABLE", "OFFER_UNKNOWN"]);
105
+ var NESTED_TERMINAL = /* @__PURE__ */ new Set([
106
+ "FILL_UNSAFE",
107
+ "FILL_WRONG_TARGET",
108
+ "SOURCE_DIVERGENCE",
109
+ "VERIFY_TAMPER",
110
+ "SUBMIT_REJECTED",
111
+ "BAD_REQUEST",
112
+ "BAD_FEE",
113
+ "BAD_OUTPUTS",
114
+ "NO_OUTPUTS",
115
+ "ZERO_ADDR_REFUSED",
116
+ "TOO_MANY_INPUTS",
117
+ "INSUFFICIENT",
118
+ "FEE_CAP",
119
+ "FEE_TOO_LOW",
120
+ "ACCOUNT_CHANGED",
121
+ "GHOST_INPUTS_SKIPPED",
122
+ "NOTHING_TO_CONSOLIDATE"
123
+ ]);
87
124
  function mapProviderError(error, code) {
88
125
  if (code === "USER_REJECTED" || code === "APPROVAL_CLOSED") return new UserRejectedError(error);
89
126
  if (code === "WALLET_LOCKED") return new WalletLockedError(error);
90
127
  if (code === "UNSUPPORTED_METHOD" || code === "UNKNOWN_KIND") return new UnsupportedMethodError(error);
128
+ if (code && NESTED_TRANSIENT.has(code)) return new CairnError(error || code, { code, retryable: true });
129
+ if (code && NESTED_TERMINAL.has(code)) return new CairnError(error || code, { code, retryable: false });
91
130
  if (code && NATIVE_CODES.has(code)) return new CairnError(error || code, { code });
92
131
  const e = String(error || "").toLowerCase();
93
132
  if (e.includes("rejected by user")) return new UserRejectedError(error);
@@ -95,6 +134,14 @@ function mapProviderError(error, code) {
95
134
  if (e.includes("unsupported dapp method") || e.includes("predates") || e.includes("too old")) return new UnsupportedMethodError(error);
96
135
  return new CairnError(error || "Unknown wallet error");
97
136
  }
137
+ function mapSubmitResultError(result) {
138
+ const code = result?.code;
139
+ const msg = typeof result?.error === "string" && result.error || code || "The wallet refused the transaction.";
140
+ if (code === "SUBMIT_MAYBE_INFLIGHT" || code === "SUBMIT_DUPLICATE") {
141
+ return new SubmitInFlightError(msg, code, typeof result?.txid === "string" ? result.txid : void 0);
142
+ }
143
+ return mapProviderError(msg, code);
144
+ }
98
145
 
99
146
  // src/connect.ts
100
147
  function detectProvider(opts = {}) {
@@ -143,6 +190,13 @@ function unwrap(reply) {
143
190
  if (reply && reply.ok) return reply.result;
144
191
  throw mapProviderError(reply?.error ?? "Unknown wallet error", reply?.code);
145
192
  }
193
+ function unwrapWrite(reply) {
194
+ const result = unwrap(reply);
195
+ if (result && typeof result === "object" && result.ok === false) {
196
+ throw mapSubmitResultError(result);
197
+ }
198
+ return result;
199
+ }
146
200
  var WalletConnection = class {
147
201
  provider;
148
202
  _addr = null;
@@ -209,12 +263,18 @@ var WalletConnection = class {
209
263
  return null;
210
264
  }
211
265
  }
212
- /** Atomic fill (CairnX DvP): pay + attest in ONE tx. Always prompts with clear-signing. */
266
+ /**
267
+ * CairnX fill: pay + attest in ONE tx (atomic SETTLEMENT SHAPE, both revert together). Always prompts with
268
+ * clear-signing. The payment recipient in `params.outputs` is RESOLVER-TRUSTED here: this SDK does NOT
269
+ * SPV-verify it, so a lying resolver can redirect the payment. A dApp settling real value MUST corroborate
270
+ * the offer on-chain before building `outputs` (F13). The wallet's own fill-SPV boundary (cairn-wallet
271
+ * 0.2.60+, which binds payment/rebate/fee to the merkle-proven offer) is the payment-grade check; see FillParams.
272
+ */
213
273
  fillOffer(params) {
214
274
  if (typeof this.provider.fillOffer !== "function") {
215
275
  return Promise.reject(new UnsupportedMethodError("this wallet predates fillOffer() \u2014 ask the user to update the Cairn Wallet"));
216
276
  }
217
- return Promise.resolve(this.provider.fillOffer(params)).then(unwrap);
277
+ return Promise.resolve(this.provider.fillOffer(params)).then(unwrapWrite);
218
278
  }
219
279
  /** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
220
280
  async getPermissions() {
@@ -247,26 +307,26 @@ var WalletConnection = class {
247
307
  }
248
308
  /** Send CSD (always prompts with clear-signing; wallet picks inputs + returns change to itself). */
249
309
  send(params) {
250
- return Promise.resolve(this.provider.send(params)).then(unwrap);
310
+ return Promise.resolve(this.provider.send(params)).then(unwrapWrite);
251
311
  }
252
312
  /** Low-level Propose (always prompts). Prefer `cairn.board.propose()` which computes the hash/uri/expiry. */
253
313
  propose(params) {
254
- return Promise.resolve(this.provider.propose(params)).then(unwrap);
314
+ return Promise.resolve(this.provider.propose(params)).then(unwrapWrite);
255
315
  }
256
316
  /** Attest/support a proposal (always prompts). */
257
317
  attest(params) {
258
- return Promise.resolve(this.provider.attest(params)).then(unwrap);
318
+ return Promise.resolve(this.provider.attest(params)).then(unwrapWrite);
259
319
  }
260
320
  /** Seal a commit-reveal claim (always prompts; salt stays inside the wallet). */
261
321
  sealClaim(params) {
262
- return Promise.resolve(this.provider.sealClaim(params)).then(unwrap);
322
+ return Promise.resolve(this.provider.sealClaim(params)).then(unwrapWrite);
263
323
  }
264
324
  /** Reveal a previously sealed claim by its sealing txid (always prompts). */
265
325
  revealClaim(txid) {
266
326
  if (typeof txid !== "string" || !txid) {
267
327
  return Promise.reject(new UnsupportedMethodError("revealClaim requires the sealing txid"));
268
328
  }
269
- return Promise.resolve(this.provider.revealClaim(txid)).then(unwrap);
329
+ return Promise.resolve(this.provider.revealClaim(txid)).then(unwrapWrite);
270
330
  }
271
331
  };
272
332
  async function getWallet(opts = {}) {
package/dist/react.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  CairnController
3
- } from "./chunk-LCE4IWMW.js";
4
- import "./chunk-QRVMYGSL.js";
5
- import "./chunk-ZJURNM5P.js";
3
+ } from "./chunk-UMXLWUEF.js";
4
+ import "./chunk-QV2GIXO7.js";
5
+ import "./chunk-E2Z3XSCW.js";
6
6
 
7
7
  // src/react.ts
8
8
  function createCairnHooks(React, controllerOrOpts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inversealtruism/cairn-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "The Compute Substrate dApp kit — one cohesive toolkit to connect the Cairn Wallet, read the chain/board, publish self-certifying content, and resolve registries. Composes the published csd-* primitives.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -58,14 +58,27 @@
58
58
  "LICENSE",
59
59
  "README.md"
60
60
  ],
61
+ "scripts": {
62
+ "build": "tsup src/index.ts src/connect.ts src/board.ts src/indexer.ts src/content.ts src/registry.ts src/chain.ts src/controller.ts src/react.ts --format esm,cjs --dts --clean",
63
+ "test": "tsx test/sdk.test.ts && tsx test/connect.test.ts && tsx test/errors.test.ts && tsx test/controller.test.ts && tsx test/react.test.ts && tsx test/hardening.test.ts && tsx test/spv-checkpoint.test.ts && tsx test/names-b10.test.ts && tsx test/fillverify.test.ts",
64
+ "test:live": "node examples/read-only.mjs",
65
+ "build:example": "node scripts/build-example.mjs",
66
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
67
+ "test:e2e:read": "node test/e2e/e2e-read.mjs",
68
+ "test:e2e:wallet": "xvfb-run -a node test/e2e/e2e-wallet-connect.mjs",
69
+ "test:e2e:write": "node test/e2e/e2e-write.mjs",
70
+ "test:e2e": "node test/e2e/e2e-read.mjs && xvfb-run -a node test/e2e/e2e-wallet-connect.mjs",
71
+ "test:all": "pnpm test && pnpm test:e2e",
72
+ "prepublishOnly": "npm run build && npm test"
73
+ },
61
74
  "dependencies": {
62
- "@inversealtruism/cairnx-core": "0.1.36",
75
+ "@inversealtruism/cairnx-core": "0.1.38",
63
76
  "@inversealtruism/csd-client": "0.1.15",
64
77
  "@inversealtruism/csd-codec": "0.1.15",
65
78
  "@inversealtruism/csd-crypto": "0.1.15",
66
- "@inversealtruism/csd-light": "0.1.17",
79
+ "@inversealtruism/csd-light": "0.1.18",
67
80
  "@inversealtruism/csd-registry": "0.1.16",
68
- "@inversealtruism/csd-tx": "0.1.16"
81
+ "@inversealtruism/csd-tx": "0.1.17"
69
82
  },
70
83
  "devDependencies": {
71
84
  "esbuild": "^0.27.0",
@@ -76,6 +89,12 @@
76
89
  "@inversealtruism/csd-siwc": "0.1.15"
77
90
  },
78
91
  "sideEffects": false,
92
+ "packageManager": "pnpm@10.32.1",
93
+ "pnpm": {
94
+ "onlyBuiltDependencies": [
95
+ "esbuild"
96
+ ]
97
+ },
79
98
  "license": "MIT",
80
99
  "publishConfig": {
81
100
  "access": "public"
@@ -93,17 +112,5 @@
93
112
  "dapp",
94
113
  "sdk",
95
114
  "blockchain"
96
- ],
97
- "scripts": {
98
- "build": "tsup src/index.ts src/connect.ts src/board.ts src/indexer.ts src/content.ts src/registry.ts src/chain.ts src/controller.ts src/react.ts --format esm,cjs --dts --clean",
99
- "test": "tsx test/sdk.test.ts && tsx test/connect.test.ts && tsx test/errors.test.ts && tsx test/controller.test.ts && tsx test/react.test.ts && tsx test/hardening.test.ts && tsx test/spv-checkpoint.test.ts && tsx test/names-b10.test.ts",
100
- "test:live": "node examples/read-only.mjs",
101
- "build:example": "node scripts/build-example.mjs",
102
- "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
103
- "test:e2e:read": "node test/e2e/e2e-read.mjs",
104
- "test:e2e:wallet": "xvfb-run -a node test/e2e/e2e-wallet-connect.mjs",
105
- "test:e2e:write": "node test/e2e/e2e-write.mjs",
106
- "test:e2e": "node test/e2e/e2e-read.mjs && xvfb-run -a node test/e2e/e2e-wallet-connect.mjs",
107
- "test:all": "pnpm test && pnpm test:e2e"
108
- }
109
- }
115
+ ]
116
+ }