@inversealtruism/cairn-sdk 0.4.0 → 0.4.1
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/board.cjs +1 -1
- package/dist/board.js +2 -2
- package/dist/chunk-7UOTIAYK.js +224 -0
- package/dist/{chunk-2ZML7IKV.js → chunk-DUTVUIQF.js} +1 -1
- package/dist/{chunk-MREZG2HN.js → chunk-ERBT4DFD.js} +1 -1
- package/dist/{chunk-2L5QNDAE.js → chunk-OCEHXK6A.js} +1 -1
- package/dist/{chunk-RKR3JMIA.js → chunk-PIPN6FSA.js} +22 -3
- package/dist/{chunk-GTTLMWGY.js → chunk-QATE6AIP.js} +25 -13
- package/dist/connect.cjs +22 -3
- package/dist/connect.d.cts +4 -1
- package/dist/connect.d.ts +4 -1
- package/dist/connect.js +2 -2
- package/dist/content.cjs +1 -1
- package/dist/content.js +2 -2
- package/dist/controller.cjs +46 -15
- package/dist/controller.d.cts +4 -1
- package/dist/controller.d.ts +4 -1
- package/dist/controller.js +3 -3
- package/dist/index.cjs +182 -62
- package/dist/index.d.cts +30 -9
- package/dist/index.d.ts +30 -9
- package/dist/index.js +125 -186
- package/dist/react.cjs +46 -15
- package/dist/react.js +3 -3
- package/dist/registry.cjs +219 -7
- package/dist/registry.d.cts +16 -11
- package/dist/registry.d.ts +16 -11
- package/dist/registry.js +2 -1
- package/package.json +6 -6
- package/dist/chunk-BGJZF7S2.js +0 -69
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.4.
|
|
29
|
+
var SDK_VERSION = "0.4.1";
|
|
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. */
|
|
@@ -213,12 +213,15 @@ var WalletConnection = class {
|
|
|
213
213
|
// genuine wallet resolves quickly once the user acts; this only fires on a truly hung/absent response.
|
|
214
214
|
call(op, label) {
|
|
215
215
|
const ms = this._timeoutMs;
|
|
216
|
-
|
|
216
|
+
const invoke = () => new Promise((resolve) => {
|
|
217
|
+
resolve(op());
|
|
218
|
+
});
|
|
219
|
+
if (!Number.isFinite(ms) || ms <= 0) return invoke();
|
|
217
220
|
let timer;
|
|
218
221
|
const timeout = new Promise((_, reject) => {
|
|
219
222
|
timer = setTimeout(() => reject(new CairnError(`the wallet did not respond to ${label} within ${ms}ms`, { retryable: false })), ms);
|
|
220
223
|
});
|
|
221
|
-
return Promise.race([
|
|
224
|
+
return Promise.race([invoke(), timeout]).finally(() => clearTimeout(timer));
|
|
222
225
|
}
|
|
223
226
|
/** The wallet's version string (e.g. "0.2.x"). */
|
|
224
227
|
get version() {
|
|
@@ -291,8 +294,24 @@ var WalletConnection = class {
|
|
|
291
294
|
if (typeof this.provider.fillOffer !== "function") {
|
|
292
295
|
return Promise.reject(new UnsupportedMethodError("this wallet predates fillOffer() \u2014 ask the user to update the Cairn Wallet"));
|
|
293
296
|
}
|
|
297
|
+
this.adviseFillSpvCapability();
|
|
294
298
|
return this.call(() => this.provider.fillOffer(params), "fillOffer").then(unwrapWrite);
|
|
295
299
|
}
|
|
300
|
+
// P75-5 MF-10: ONE capability advisory per connection. The wallet's on-device fill-SPV (0.2.60+) is the
|
|
301
|
+
// payment-grade fill boundary; when the provider SELF-REPORTS an older version, warn the integrator once
|
|
302
|
+
// and STILL RELAY. WARN, NEVER BLOCK: a hard version gate would decline honest fills (version strings are
|
|
303
|
+
// spoofable and unparseable forks exist), and the wallet itself is the enforcement point. Reads only the
|
|
304
|
+
// sync `provider.version`; never an awaited getCapabilities() round-trip on the fill hot path. An
|
|
305
|
+
// unparseable version never warns (no false alarms).
|
|
306
|
+
_fillSpvAdvised = false;
|
|
307
|
+
adviseFillSpvCapability() {
|
|
308
|
+
if (this._fillSpvAdvised) return;
|
|
309
|
+
this._fillSpvAdvised = true;
|
|
310
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(String(this.provider?.version ?? ""));
|
|
311
|
+
if (!m) return;
|
|
312
|
+
const below = Number(m[1]) === 0 && (Number(m[2]) < 2 || Number(m[2]) === 2 && Number(m[3]) < 60);
|
|
313
|
+
if (below) console.warn(`[cairn-sdk] this Cairn Wallet (v${m[0]}) predates the on-device fill-SPV boundary (cairn-wallet 0.2.60+). The fill proceeds; suggest a wallet update for payment-grade offer verification.`);
|
|
314
|
+
}
|
|
296
315
|
/** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
|
|
297
316
|
async getPermissions() {
|
|
298
317
|
if (typeof this.provider.getPermissions !== "function") return [];
|
|
@@ -355,6 +374,9 @@ var DISCONNECTED = Object.freeze({ status: "disconnected", account: null, error:
|
|
|
355
374
|
var CairnController = class {
|
|
356
375
|
state = DISCONNECTED;
|
|
357
376
|
conn = null;
|
|
377
|
+
// MF-15: connect/disconnect generation token. disconnect() bumps it; a connect() whose await straddled
|
|
378
|
+
// the bump must never commit "connected" over the torn-down session (a zombie null-connection session).
|
|
379
|
+
epoch = 0;
|
|
358
380
|
listeners = /* @__PURE__ */ new Set();
|
|
359
381
|
getWalletFn;
|
|
360
382
|
detectOpts;
|
|
@@ -407,34 +429,43 @@ var CairnController = class {
|
|
|
407
429
|
}
|
|
408
430
|
/** Detect + connect (prompts the user the first time per origin). Resolves the connected address. */
|
|
409
431
|
connect = async () => {
|
|
432
|
+
const epoch = this.epoch;
|
|
410
433
|
this.setState({ status: "connecting", error: null });
|
|
411
434
|
try {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
this.
|
|
415
|
-
this.
|
|
435
|
+
let conn = this.conn;
|
|
436
|
+
if (!conn) {
|
|
437
|
+
conn = await this.getWalletFn(this.detectOpts);
|
|
438
|
+
if (epoch !== this.epoch) throw new Error("connection was torn down while connecting - call connect() again");
|
|
439
|
+
conn.on("accountsChanged", this.onAccounts);
|
|
440
|
+
conn.on("disconnect", this.onDisconnect);
|
|
441
|
+
this.conn = conn;
|
|
416
442
|
}
|
|
417
|
-
const addr = await
|
|
443
|
+
const addr = await conn.connect();
|
|
444
|
+
if (epoch !== this.epoch) throw new Error("connection was torn down while awaiting approval - call connect() again");
|
|
418
445
|
this.setState({ status: "connected", account: addr, error: null });
|
|
419
446
|
return addr;
|
|
420
447
|
} catch (e) {
|
|
421
|
-
this.setState({ status: "disconnected", account: null, error: e?.message ?? String(e) });
|
|
448
|
+
if (epoch === this.epoch) this.setState({ status: "disconnected", account: null, error: e?.message ?? String(e) });
|
|
422
449
|
throw e;
|
|
423
450
|
}
|
|
424
451
|
};
|
|
425
|
-
/** Forget the connection locally AND revoke this origin's wallet-side permission (best-effort).
|
|
452
|
+
/** Forget the connection locally AND revoke this origin's wallet-side permission (best-effort).
|
|
453
|
+
* Local teardown is IMMEDIATE and unconditional; the wallet-side revoke happens after, so a hung
|
|
454
|
+
* provider can never hold a torn-down session in "connected". */
|
|
426
455
|
disconnect = async () => {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
} catch {
|
|
430
|
-
}
|
|
456
|
+
this.epoch++;
|
|
457
|
+
const conn = this.conn;
|
|
431
458
|
this.detach();
|
|
432
459
|
this.conn = null;
|
|
433
460
|
this.setState({ status: "disconnected", account: null, error: null });
|
|
461
|
+
try {
|
|
462
|
+
await conn?.revokePermissions();
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
434
465
|
};
|
|
435
466
|
/** Audience-bound sign-in (must connect() first). Returns the signed artifact to verify server-side. */
|
|
436
467
|
signInWithCsd = (params) => {
|
|
437
|
-
if (!this.conn) return Promise.reject(new Error("call connect() before signInWithCsd()"));
|
|
468
|
+
if (!this.conn || this.state.status !== "connected") return Promise.reject(new Error("call connect() before signInWithCsd()"));
|
|
438
469
|
return this.conn.signInWithCsd(params);
|
|
439
470
|
};
|
|
440
471
|
};
|
package/dist/react.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CairnController
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-QATE6AIP.js";
|
|
4
|
+
import "./chunk-PIPN6FSA.js";
|
|
5
|
+
import "./chunk-ERBT4DFD.js";
|
|
6
6
|
|
|
7
7
|
// src/react.ts
|
|
8
8
|
function createCairnHooks(React, controllerOrOpts) {
|
package/dist/registry.cjs
CHANGED
|
@@ -34,19 +34,221 @@ __export(registry_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(registry_exports);
|
|
36
36
|
var import_csd_registry = require("@inversealtruism/csd-registry");
|
|
37
|
+
|
|
38
|
+
// src/errors.ts
|
|
39
|
+
var SDK_VERSION = "0.4.1";
|
|
40
|
+
var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
|
|
41
|
+
var CairnError = class extends Error {
|
|
42
|
+
/** Stable machine code for programmatic branching. */
|
|
43
|
+
code;
|
|
44
|
+
/** The human message without the appended docs/version footer. */
|
|
45
|
+
shortMessage;
|
|
46
|
+
/** Relative docs path (under the SDK docs base), if any. */
|
|
47
|
+
docsPath;
|
|
48
|
+
/** The cairn-sdk version that produced this error. */
|
|
49
|
+
version = SDK_VERSION;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
|
|
52
|
+
* declines (the default); `true` only for provably transient infra faults where nothing was signed.
|
|
53
|
+
* A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
|
|
54
|
+
*/
|
|
55
|
+
retryable;
|
|
56
|
+
constructor(shortMessage, opts = {}) {
|
|
57
|
+
const docs = opts.docsPath;
|
|
58
|
+
super(
|
|
59
|
+
[shortMessage, docs ? `Docs: ${DOCS_BASE}${docs}` : "", `Version: cairn-sdk@${SDK_VERSION}`].filter(Boolean).join("\n"),
|
|
60
|
+
{ cause: opts.cause }
|
|
61
|
+
);
|
|
62
|
+
this.name = new.target.name;
|
|
63
|
+
this.code = opts.code ?? "UNKNOWN";
|
|
64
|
+
this.shortMessage = shortMessage;
|
|
65
|
+
this.docsPath = docs;
|
|
66
|
+
this.retryable = opts.retryable ?? false;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
|
|
70
|
+
* returns the DEEPEST cause (the root). Mirrors viem's `BaseError.walk()`.
|
|
71
|
+
*/
|
|
72
|
+
walk(fn) {
|
|
73
|
+
let current = this;
|
|
74
|
+
let last = this;
|
|
75
|
+
while (current != null) {
|
|
76
|
+
if (fn && fn(current)) return current;
|
|
77
|
+
last = current;
|
|
78
|
+
current = current?.cause;
|
|
79
|
+
}
|
|
80
|
+
return fn ? null : last;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var HttpError = class extends CairnError {
|
|
84
|
+
status;
|
|
85
|
+
url;
|
|
86
|
+
body;
|
|
87
|
+
constructor(status, url, body) {
|
|
88
|
+
super(`HTTP ${status} for ${url}${body ? `: ${String(body).slice(0, 200)}` : ""}`, { code: "HTTP_ERROR" });
|
|
89
|
+
this.status = status;
|
|
90
|
+
this.url = url;
|
|
91
|
+
this.body = body;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/http.ts
|
|
96
|
+
var DEFAULT_MAX_BYTES = 16 * 1024 * 1024;
|
|
97
|
+
var ERR_TEXT_CAP = 8 * 1024;
|
|
98
|
+
async function readCapped(res, maxBytes) {
|
|
99
|
+
const cl = Number(res.headers.get("content-length"));
|
|
100
|
+
if (Number.isFinite(cl) && cl > maxBytes) throw new HttpError(res.status, res.url, `response too large (content-length ${cl} > ${maxBytes})`);
|
|
101
|
+
const body = res.body;
|
|
102
|
+
if (!body || typeof body.getReader !== "function") {
|
|
103
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
104
|
+
if (buf.byteLength > maxBytes) throw new HttpError(res.status, res.url, `response too large (${buf.byteLength} > ${maxBytes})`);
|
|
105
|
+
return buf;
|
|
106
|
+
}
|
|
107
|
+
const reader = body.getReader();
|
|
108
|
+
const chunks = [];
|
|
109
|
+
let total = 0;
|
|
110
|
+
for (; ; ) {
|
|
111
|
+
const { done, value } = await reader.read();
|
|
112
|
+
if (done) break;
|
|
113
|
+
if (value) {
|
|
114
|
+
total += value.byteLength;
|
|
115
|
+
if (total > maxBytes) {
|
|
116
|
+
try {
|
|
117
|
+
await reader.cancel();
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
throw new HttpError(res.status, res.url, `response exceeded ${maxBytes} bytes`);
|
|
121
|
+
}
|
|
122
|
+
chunks.push(value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const out = new Uint8Array(total);
|
|
126
|
+
let off = 0;
|
|
127
|
+
for (const c of chunks) {
|
|
128
|
+
out.set(c, off);
|
|
129
|
+
off += c.byteLength;
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
var Http = class {
|
|
134
|
+
baseUrl;
|
|
135
|
+
_fetch;
|
|
136
|
+
timeoutMs;
|
|
137
|
+
maxBytes;
|
|
138
|
+
headers;
|
|
139
|
+
retries;
|
|
140
|
+
constructor(opts) {
|
|
141
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
142
|
+
const f = opts.fetch ?? globalThis.fetch;
|
|
143
|
+
if (!f) throw new Error("No fetch available \u2014 pass `fetch` in the SDK options.");
|
|
144
|
+
this._fetch = opts.fetch ? opts.fetch : f.bind(globalThis);
|
|
145
|
+
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
146
|
+
this.maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
147
|
+
this.headers = opts.headers ?? {};
|
|
148
|
+
this.retries = Math.min(10, Math.max(0, Math.floor(opts.retries ?? 0)));
|
|
149
|
+
}
|
|
150
|
+
/** Build an absolute URL from a path + optional query params. */
|
|
151
|
+
url(path, query) {
|
|
152
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
153
|
+
const u = new URL(this.baseUrl + p);
|
|
154
|
+
const basePath = new URL(this.baseUrl + "/").pathname;
|
|
155
|
+
if (basePath !== "/" && !(u.pathname + "/").startsWith(basePath)) {
|
|
156
|
+
throw new Error(`illegal path '${path}' \u2014 escapes base ${basePath}`);
|
|
157
|
+
}
|
|
158
|
+
if (query) {
|
|
159
|
+
for (const [k, v] of Object.entries(query)) {
|
|
160
|
+
if (v !== void 0 && v !== null) u.searchParams.set(k, String(v));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return u.toString();
|
|
164
|
+
}
|
|
165
|
+
async raw(method, path, opts) {
|
|
166
|
+
const url = this.url(path, opts?.query);
|
|
167
|
+
const ctrl = new AbortController();
|
|
168
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
169
|
+
try {
|
|
170
|
+
const res = await this._fetch(url, {
|
|
171
|
+
method,
|
|
172
|
+
signal: ctrl.signal,
|
|
173
|
+
headers: {
|
|
174
|
+
...opts?.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
175
|
+
...this.headers,
|
|
176
|
+
...opts?.headers ?? {}
|
|
177
|
+
},
|
|
178
|
+
body: opts?.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
179
|
+
});
|
|
180
|
+
return res;
|
|
181
|
+
} finally {
|
|
182
|
+
clearTimeout(timer);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// A malformed 2xx body must surface as a TYPED HttpError, not a leaked SyntaxError (B10: dApp
|
|
186
|
+
// code branches on `instanceof CairnError`; a raw parse error escaped that contract).
|
|
187
|
+
parseJson(res, text, url) {
|
|
188
|
+
try {
|
|
189
|
+
return JSON.parse(text);
|
|
190
|
+
} catch (e) {
|
|
191
|
+
throw new HttpError(res.status, url, `invalid JSON body: ${text.slice(0, 120)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async getJson(path, query) {
|
|
195
|
+
const url = this.url(path, query);
|
|
196
|
+
for (let attempt = 0; ; attempt++) {
|
|
197
|
+
try {
|
|
198
|
+
const res = await this.raw("GET", path, { query });
|
|
199
|
+
if (!res.ok) {
|
|
200
|
+
if (!(res.status >= 500 && attempt < this.retries)) throw new HttpError(res.status, url, await safeText(res));
|
|
201
|
+
res.body?.cancel().catch(() => {
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
return this.parseJson(res, new TextDecoder().decode(await readCapped(res, this.maxBytes)), url);
|
|
205
|
+
}
|
|
206
|
+
} catch (e) {
|
|
207
|
+
if (e instanceof HttpError && e.status < 500) throw e;
|
|
208
|
+
if (attempt >= this.retries) throw e;
|
|
209
|
+
}
|
|
210
|
+
await new Promise((r) => setTimeout(r, Math.floor(Math.random() * Math.min(4e3, 250 * 2 ** attempt))));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async postJson(path, body, headers) {
|
|
214
|
+
const url = this.url(path);
|
|
215
|
+
const res = await this.raw("POST", path, { body, headers });
|
|
216
|
+
if (!res.ok) throw new HttpError(res.status, url, await safeText(res));
|
|
217
|
+
return this.parseJson(res, new TextDecoder().decode(await readCapped(res, this.maxBytes)), url);
|
|
218
|
+
}
|
|
219
|
+
/** GET raw bytes (for content retrieval). Returns null on 404. */
|
|
220
|
+
async getBytes(path) {
|
|
221
|
+
const res = await this.raw("GET", path);
|
|
222
|
+
if (res.status === 404) return null;
|
|
223
|
+
if (!res.ok) throw new HttpError(res.status, this.url(path), await safeText(res));
|
|
224
|
+
return { bytes: await readCapped(res, this.maxBytes), headers: res.headers };
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
async function safeText(res) {
|
|
228
|
+
try {
|
|
229
|
+
return new TextDecoder().decode(await readCapped(res, ERR_TEXT_CAP));
|
|
230
|
+
} catch {
|
|
231
|
+
return "";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/registry.ts
|
|
37
236
|
var import_csd_registry2 = require("@inversealtruism/csd-registry");
|
|
38
237
|
var RegistryClient = class {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
238
|
+
http;
|
|
239
|
+
/** Accepts the SDK's hardened Http directly (the Cairn facade path) or the legacy
|
|
240
|
+
* { baseUrl, fetch } options (kept for direct constructors; they now get the same
|
|
241
|
+
* hardened transport, built internally). */
|
|
242
|
+
constructor(src) {
|
|
243
|
+
this.http = src instanceof Http ? src : new Http({ baseUrl: src.baseUrl, fetch: src.fetch });
|
|
42
244
|
}
|
|
43
245
|
/** Discover ranked content/pin gateways (GET /registry/gateways). */
|
|
44
246
|
gateways() {
|
|
45
|
-
return
|
|
247
|
+
return this.http.getJson("/registry/gateways");
|
|
46
248
|
}
|
|
47
249
|
/** Discover ranked libp2p peers (GET /registry/peers). */
|
|
48
250
|
peers() {
|
|
49
|
-
return
|
|
251
|
+
return this.http.getJson("/registry/peers");
|
|
50
252
|
}
|
|
51
253
|
/**
|
|
52
254
|
* Resolve a handle → identity (GET /identity/:handle). Returns null if unresolved.
|
|
@@ -58,12 +260,22 @@ var RegistryClient = class {
|
|
|
58
260
|
* source (the wallet's namespv union cure). Treat `verified` here as a hint, not a guarantee.
|
|
59
261
|
*/
|
|
60
262
|
resolveName(handle) {
|
|
61
|
-
return
|
|
263
|
+
return this.getOr404Null(`/identity/${encodeURIComponent(handle)}`);
|
|
62
264
|
}
|
|
63
265
|
/** Reverse-resolve an address → identity (GET /address/:addr/identity).
|
|
64
266
|
* ⚠ Same indexer-trust caveat as resolveName — `verified` is the indexer's claim, not a client proof. */
|
|
65
267
|
reverseName(address) {
|
|
66
|
-
return
|
|
268
|
+
return this.getOr404Null(`/address/${encodeURIComponent(address)}/identity`);
|
|
269
|
+
}
|
|
270
|
+
// MF-12: 404 → null (the preserved csd-registry contract for both name resolvers); every other
|
|
271
|
+
// failure rethrows the typed HttpError/CairnError the hardened Http raises.
|
|
272
|
+
async getOr404Null(path) {
|
|
273
|
+
try {
|
|
274
|
+
return await this.http.getJson(path);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
if (e instanceof HttpError && e.status === 404) return null;
|
|
277
|
+
return Promise.reject(e);
|
|
278
|
+
}
|
|
67
279
|
}
|
|
68
280
|
/** The deterministic, client-side resolvers (recompute from raw ChainRecord[]). */
|
|
69
281
|
get fromRecords() {
|
package/dist/registry.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as _inversealtruism_csd_registry from '@inversealtruism/csd-registry';
|
|
2
|
+
import { RankedGateway, RankedPeer, ResolvedIdentity } from '@inversealtruism/csd-registry';
|
|
2
3
|
export { BuiltRecord, ChainRecord, DOMAINS, RankedGateway, RankedPeer, ResolveOpts, ResolvedIdentity, buildGatewayRecord, buildIdentityCommit, buildIdentityReveal, buildPeerRecord, epochOf, fromRecords, verifyGateway, verifyIdentitySig, verifyPeer } from '@inversealtruism/csd-registry';
|
|
3
|
-
import { F as FetchLike } from './http-C9C4L4hz.cjs';
|
|
4
|
+
import { H as Http, F as FetchLike } from './http-C9C4L4hz.cjs';
|
|
4
5
|
|
|
5
6
|
interface RegistryClientOptions {
|
|
6
7
|
/** Indexer base URL exposing /registry/* + /identity/* (e.g. https://cairn-substrate.com/indexer). */
|
|
@@ -8,12 +9,15 @@ interface RegistryClientOptions {
|
|
|
8
9
|
fetch?: FetchLike;
|
|
9
10
|
}
|
|
10
11
|
declare class RegistryClient {
|
|
11
|
-
private readonly
|
|
12
|
-
|
|
12
|
+
private readonly http;
|
|
13
|
+
/** Accepts the SDK's hardened Http directly (the Cairn facade path) or the legacy
|
|
14
|
+
* { baseUrl, fetch } options (kept for direct constructors; they now get the same
|
|
15
|
+
* hardened transport, built internally). */
|
|
16
|
+
constructor(src: Http | RegistryClientOptions);
|
|
13
17
|
/** Discover ranked content/pin gateways (GET /registry/gateways). */
|
|
14
|
-
gateways(): Promise<
|
|
18
|
+
gateways(): Promise<RankedGateway[]>;
|
|
15
19
|
/** Discover ranked libp2p peers (GET /registry/peers). */
|
|
16
|
-
peers(): Promise<
|
|
20
|
+
peers(): Promise<RankedPeer[]>;
|
|
17
21
|
/**
|
|
18
22
|
* Resolve a handle → identity (GET /identity/:handle). Returns null if unresolved.
|
|
19
23
|
*
|
|
@@ -23,16 +27,17 @@ declare class RegistryClient {
|
|
|
23
27
|
* recomputing from raw records via `fromRecords.name(...)`, or (b) cross-checking a second independent
|
|
24
28
|
* source (the wallet's namespv union cure). Treat `verified` here as a hint, not a guarantee.
|
|
25
29
|
*/
|
|
26
|
-
resolveName(handle: string): Promise<
|
|
30
|
+
resolveName(handle: string): Promise<ResolvedIdentity | null>;
|
|
27
31
|
/** Reverse-resolve an address → identity (GET /address/:addr/identity).
|
|
28
32
|
* ⚠ Same indexer-trust caveat as resolveName — `verified` is the indexer's claim, not a client proof. */
|
|
29
|
-
reverseName(address: string): Promise<
|
|
33
|
+
reverseName(address: string): Promise<ResolvedIdentity | null>;
|
|
34
|
+
private getOr404Null;
|
|
30
35
|
/** The deterministic, client-side resolvers (recompute from raw ChainRecord[]). */
|
|
31
36
|
get fromRecords(): {
|
|
32
|
-
peers: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
33
|
-
gateways: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
34
|
-
name: (records: _inversealtruism_csd_registry.ChainRecord[], handle: string, opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
35
|
-
reverse: (records: _inversealtruism_csd_registry.ChainRecord[], address: string, opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
37
|
+
peers: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) => RankedPeer[];
|
|
38
|
+
gateways: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) => RankedGateway[];
|
|
39
|
+
name: (records: _inversealtruism_csd_registry.ChainRecord[], handle: string, opts: _inversealtruism_csd_registry.ResolveOpts) => ResolvedIdentity | null;
|
|
40
|
+
reverse: (records: _inversealtruism_csd_registry.ChainRecord[], address: string, opts: _inversealtruism_csd_registry.ResolveOpts) => ResolvedIdentity | null;
|
|
36
41
|
};
|
|
37
42
|
}
|
|
38
43
|
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as _inversealtruism_csd_registry from '@inversealtruism/csd-registry';
|
|
2
|
+
import { RankedGateway, RankedPeer, ResolvedIdentity } from '@inversealtruism/csd-registry';
|
|
2
3
|
export { BuiltRecord, ChainRecord, DOMAINS, RankedGateway, RankedPeer, ResolveOpts, ResolvedIdentity, buildGatewayRecord, buildIdentityCommit, buildIdentityReveal, buildPeerRecord, epochOf, fromRecords, verifyGateway, verifyIdentitySig, verifyPeer } from '@inversealtruism/csd-registry';
|
|
3
|
-
import { F as FetchLike } from './http-C9C4L4hz.js';
|
|
4
|
+
import { H as Http, F as FetchLike } from './http-C9C4L4hz.js';
|
|
4
5
|
|
|
5
6
|
interface RegistryClientOptions {
|
|
6
7
|
/** Indexer base URL exposing /registry/* + /identity/* (e.g. https://cairn-substrate.com/indexer). */
|
|
@@ -8,12 +9,15 @@ interface RegistryClientOptions {
|
|
|
8
9
|
fetch?: FetchLike;
|
|
9
10
|
}
|
|
10
11
|
declare class RegistryClient {
|
|
11
|
-
private readonly
|
|
12
|
-
|
|
12
|
+
private readonly http;
|
|
13
|
+
/** Accepts the SDK's hardened Http directly (the Cairn facade path) or the legacy
|
|
14
|
+
* { baseUrl, fetch } options (kept for direct constructors; they now get the same
|
|
15
|
+
* hardened transport, built internally). */
|
|
16
|
+
constructor(src: Http | RegistryClientOptions);
|
|
13
17
|
/** Discover ranked content/pin gateways (GET /registry/gateways). */
|
|
14
|
-
gateways(): Promise<
|
|
18
|
+
gateways(): Promise<RankedGateway[]>;
|
|
15
19
|
/** Discover ranked libp2p peers (GET /registry/peers). */
|
|
16
|
-
peers(): Promise<
|
|
20
|
+
peers(): Promise<RankedPeer[]>;
|
|
17
21
|
/**
|
|
18
22
|
* Resolve a handle → identity (GET /identity/:handle). Returns null if unresolved.
|
|
19
23
|
*
|
|
@@ -23,16 +27,17 @@ declare class RegistryClient {
|
|
|
23
27
|
* recomputing from raw records via `fromRecords.name(...)`, or (b) cross-checking a second independent
|
|
24
28
|
* source (the wallet's namespv union cure). Treat `verified` here as a hint, not a guarantee.
|
|
25
29
|
*/
|
|
26
|
-
resolveName(handle: string): Promise<
|
|
30
|
+
resolveName(handle: string): Promise<ResolvedIdentity | null>;
|
|
27
31
|
/** Reverse-resolve an address → identity (GET /address/:addr/identity).
|
|
28
32
|
* ⚠ Same indexer-trust caveat as resolveName — `verified` is the indexer's claim, not a client proof. */
|
|
29
|
-
reverseName(address: string): Promise<
|
|
33
|
+
reverseName(address: string): Promise<ResolvedIdentity | null>;
|
|
34
|
+
private getOr404Null;
|
|
30
35
|
/** The deterministic, client-side resolvers (recompute from raw ChainRecord[]). */
|
|
31
36
|
get fromRecords(): {
|
|
32
|
-
peers: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
33
|
-
gateways: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
34
|
-
name: (records: _inversealtruism_csd_registry.ChainRecord[], handle: string, opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
35
|
-
reverse: (records: _inversealtruism_csd_registry.ChainRecord[], address: string, opts: _inversealtruism_csd_registry.ResolveOpts) =>
|
|
37
|
+
peers: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) => RankedPeer[];
|
|
38
|
+
gateways: (records: _inversealtruism_csd_registry.ChainRecord[], opts: _inversealtruism_csd_registry.ResolveOpts) => RankedGateway[];
|
|
39
|
+
name: (records: _inversealtruism_csd_registry.ChainRecord[], handle: string, opts: _inversealtruism_csd_registry.ResolveOpts) => ResolvedIdentity | null;
|
|
40
|
+
reverse: (records: _inversealtruism_csd_registry.ChainRecord[], address: string, opts: _inversealtruism_csd_registry.ResolveOpts) => ResolvedIdentity | null;
|
|
36
41
|
};
|
|
37
42
|
}
|
|
38
43
|
|
package/dist/registry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inversealtruism/cairn-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
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",
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
"README.md"
|
|
60
60
|
],
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@inversealtruism/cairnx-core": "0.1.
|
|
62
|
+
"@inversealtruism/cairnx-core": "0.1.41",
|
|
63
63
|
"@inversealtruism/csd-client": "0.1.15",
|
|
64
|
-
"@inversealtruism/csd-codec": "0.1.
|
|
64
|
+
"@inversealtruism/csd-codec": "0.1.16",
|
|
65
65
|
"@inversealtruism/csd-crypto": "0.1.15",
|
|
66
|
-
"@inversealtruism/csd-light": "0.1.
|
|
67
|
-
"@inversealtruism/csd-registry": "0.1.
|
|
66
|
+
"@inversealtruism/csd-light": "0.1.19",
|
|
67
|
+
"@inversealtruism/csd-registry": "0.1.17",
|
|
68
68
|
"@inversealtruism/csd-tx": "0.1.17"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@inversealtruism/csd-siwc": "0.1.
|
|
71
|
+
"@inversealtruism/csd-siwc": "0.1.16",
|
|
72
72
|
"esbuild": "^0.27.0",
|
|
73
73
|
"playwright-core": "^1.49.0",
|
|
74
74
|
"tsup": "^8.5.1",
|
package/dist/chunk-BGJZF7S2.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// src/registry.ts
|
|
2
|
-
import {
|
|
3
|
-
discoverPeers,
|
|
4
|
-
discoverGateways,
|
|
5
|
-
resolveName,
|
|
6
|
-
reverseName,
|
|
7
|
-
fromRecords
|
|
8
|
-
} from "@inversealtruism/csd-registry";
|
|
9
|
-
import {
|
|
10
|
-
fromRecords as fromRecords2,
|
|
11
|
-
verifyPeer as verifyPeer2,
|
|
12
|
-
verifyGateway as verifyGateway2,
|
|
13
|
-
verifyIdentitySig as verifyIdentitySig2,
|
|
14
|
-
DOMAINS as DOMAINS2,
|
|
15
|
-
buildPeerRecord,
|
|
16
|
-
buildGatewayRecord,
|
|
17
|
-
buildIdentityCommit,
|
|
18
|
-
buildIdentityReveal,
|
|
19
|
-
epochOf
|
|
20
|
-
} from "@inversealtruism/csd-registry";
|
|
21
|
-
var RegistryClient = class {
|
|
22
|
-
src;
|
|
23
|
-
constructor(opts) {
|
|
24
|
-
this.src = { baseUrl: opts.baseUrl.replace(/\/+$/, ""), fetch: opts.fetch };
|
|
25
|
-
}
|
|
26
|
-
/** Discover ranked content/pin gateways (GET /registry/gateways). */
|
|
27
|
-
gateways() {
|
|
28
|
-
return discoverGateways(this.src);
|
|
29
|
-
}
|
|
30
|
-
/** Discover ranked libp2p peers (GET /registry/peers). */
|
|
31
|
-
peers() {
|
|
32
|
-
return discoverPeers(this.src);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Resolve a handle → identity (GET /identity/:handle). Returns null if unresolved.
|
|
36
|
-
*
|
|
37
|
-
* ⚠ TRUST (CAIRN-SDK-RESOLVE-VERIFIED-FOOTGUN): the returned `verified` flag is the INDEXER's assertion,
|
|
38
|
-
* NOT a client-side proof. A hostile/compromised indexer (or a MITM of the read proxy) can return
|
|
39
|
-
* `verified:true` for a wrong address. Do NOT use this directly as a payee/login target without either (a)
|
|
40
|
-
* recomputing from raw records via `fromRecords.name(...)`, or (b) cross-checking a second independent
|
|
41
|
-
* source (the wallet's namespv union cure). Treat `verified` here as a hint, not a guarantee.
|
|
42
|
-
*/
|
|
43
|
-
resolveName(handle) {
|
|
44
|
-
return resolveName(this.src, handle);
|
|
45
|
-
}
|
|
46
|
-
/** Reverse-resolve an address → identity (GET /address/:addr/identity).
|
|
47
|
-
* ⚠ Same indexer-trust caveat as resolveName — `verified` is the indexer's claim, not a client proof. */
|
|
48
|
-
reverseName(address) {
|
|
49
|
-
return reverseName(this.src, address);
|
|
50
|
-
}
|
|
51
|
-
/** The deterministic, client-side resolvers (recompute from raw ChainRecord[]). */
|
|
52
|
-
get fromRecords() {
|
|
53
|
-
return fromRecords;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export {
|
|
58
|
-
RegistryClient,
|
|
59
|
-
fromRecords2 as fromRecords,
|
|
60
|
-
verifyPeer2 as verifyPeer,
|
|
61
|
-
verifyGateway2 as verifyGateway,
|
|
62
|
-
verifyIdentitySig2 as verifyIdentitySig,
|
|
63
|
-
DOMAINS2 as DOMAINS,
|
|
64
|
-
buildPeerRecord,
|
|
65
|
-
buildGatewayRecord,
|
|
66
|
-
buildIdentityCommit,
|
|
67
|
-
buildIdentityReveal,
|
|
68
|
-
epochOf
|
|
69
|
-
};
|