@dignetwork/dig-sdk 0.1.0 → 0.2.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/README.md +159 -11
- package/dist/adapters.cjs +56 -15
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.d.cts +2 -2
- package/dist/adapters.d.ts +2 -2
- package/dist/adapters.js +56 -15
- package/dist/adapters.js.map +1 -1
- package/dist/{dev-shim-Bgw8X2E9.d.cts → dev-shim-DfKRA1ok.d.cts} +13 -3
- package/dist/{dev-shim-Bgw8X2E9.d.ts → dev-shim-DfKRA1ok.d.ts} +13 -3
- package/dist/{dig-client-entry-BIzuZ7Rs.d.cts → dig-client-entry-Bc95rd_t.d.cts} +120 -7
- package/dist/{dig-client-entry-BIzuZ7Rs.d.ts → dig-client-entry-Bc95rd_t.d.ts} +120 -7
- package/dist/dig-client.cjs +163 -43
- package/dist/dig-client.cjs.map +1 -1
- package/dist/dig-client.d.cts +1 -1
- package/dist/dig-client.d.ts +1 -1
- package/dist/dig-client.js +163 -43
- package/dist/dig-client.js.map +1 -1
- package/dist/index.cjs +495 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -3
- package/dist/index.d.ts +313 -3
- package/dist/index.js +489 -57
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +58 -15
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +58 -15
- package/dist/next.js.map +1 -1
- package/dist/vite.cjs +58 -15
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +58 -15
- package/dist/vite.js.map +1 -1
- package/package.json +5 -6
- package/vendor/PROVENANCE.md +0 -102
- package/vendor/dig_client.d.ts +0 -150
- package/vendor/dig_client.mjs +0 -805
- package/vendor/dig_client_bg.wasm +0 -0
package/dist/index.js
CHANGED
|
@@ -17,6 +17,75 @@ var SIGN_METHODS = [
|
|
|
17
17
|
];
|
|
18
18
|
var DEFAULT_CHAIN = "chia:mainnet";
|
|
19
19
|
|
|
20
|
+
// src/errors.ts
|
|
21
|
+
var DIG_SDK_ERROR_CODES = Object.freeze({
|
|
22
|
+
// ---- provider / connect (provider/chia-provider.ts, provider/*) ----
|
|
23
|
+
/** WalletConnect was requested/needed but no `walletConnect` options were supplied. */
|
|
24
|
+
WC_OPTIONS_REQUIRED: "WC_OPTIONS_REQUIRED",
|
|
25
|
+
/** `mode: "injected"` (or the injected leg of `auto`) found no usable `window.chia`. */
|
|
26
|
+
NO_INJECTED_WALLET: "NO_INJECTED_WALLET",
|
|
27
|
+
/** The optional `@walletconnect/sign-client` peer dependency is not installed/usable. */
|
|
28
|
+
WC_DEPENDENCY_MISSING: "WC_DEPENDENCY_MISSING",
|
|
29
|
+
/** The active wallet session/transport does not grant the requested method. */
|
|
30
|
+
METHOD_NOT_SUPPORTED: "METHOD_NOT_SUPPORTED",
|
|
31
|
+
/** A wallet RPC timed out (e.g. Sage did not respond within the per-request timeout). */
|
|
32
|
+
WALLET_TIMEOUT: "WALLET_TIMEOUT",
|
|
33
|
+
/** The wallet returned no public keys / no key to sign with. */
|
|
34
|
+
WALLET_NO_KEYS: "WALLET_NO_KEYS",
|
|
35
|
+
// ---- read-crypto / RPC (dig-client.ts, loader.ts) ----
|
|
36
|
+
/** A content read needs a confirmed on-chain root and none was supplied/derivable. */
|
|
37
|
+
ROOT_REQUIRED: "ROOT_REQUIRED",
|
|
38
|
+
/** The resource did not decrypt+authenticate under this URN (wrong key/salt, or a decoy). */
|
|
39
|
+
DECRYPT_FAILED: "DECRYPT_FAILED",
|
|
40
|
+
/** The dig RPC could not be reached (network/transport failure). */
|
|
41
|
+
RPC_TRANSPORT: "RPC_TRANSPORT",
|
|
42
|
+
/** The dig RPC responded with an HTTP error or a JSON-RPC `error` object. */
|
|
43
|
+
RPC_ERROR: "RPC_ERROR",
|
|
44
|
+
/** The dig RPC returned a malformed / inconsistent payload (e.g. chunk-length mismatch). */
|
|
45
|
+
RPC_MALFORMED_RESPONSE: "RPC_MALFORMED_RESPONSE",
|
|
46
|
+
/** The read-crypto wasm failed its SRI integrity check — fail closed. */
|
|
47
|
+
WASM_INTEGRITY: "WASM_INTEGRITY",
|
|
48
|
+
/** The read-crypto wasm could not be loaded (fetch/resolve failure). */
|
|
49
|
+
WASM_LOAD_FAILED: "WASM_LOAD_FAILED",
|
|
50
|
+
// ---- paywall / spends (paywall.ts) ----
|
|
51
|
+
/** The canonical chip35 wasm builder for this operation is unavailable (never hand-rolled). */
|
|
52
|
+
SPEND_BUILDER_UNAVAILABLE: "SPEND_BUILDER_UNAVAILABLE",
|
|
53
|
+
/** No secure random source was available to generate a payment nonce. */
|
|
54
|
+
NO_SECURE_RANDOM: "NO_SECURE_RANDOM",
|
|
55
|
+
// ---- deploy / adapters (adapters/run.ts, adapters/deploy.ts) ----
|
|
56
|
+
/** The `digstore` binary could not be spawned (not installed / not on PATH). */
|
|
57
|
+
DIGSTORE_NOT_FOUND: "DIGSTORE_NOT_FOUND",
|
|
58
|
+
/** `digstore deploy` exited non-zero. */
|
|
59
|
+
DEPLOY_FAILED: "DEPLOY_FAILED",
|
|
60
|
+
/** `digstore deploy --json` output could not be parsed into a capsule result. */
|
|
61
|
+
DEPLOY_OUTPUT_UNPARSEABLE: "DEPLOY_OUTPUT_UNPARSEABLE",
|
|
62
|
+
// ---- argument validation (shared) ----
|
|
63
|
+
/** An argument was malformed (e.g. a non-hex string, a bad URN, mutually-exclusive options). */
|
|
64
|
+
INVALID_ARGUMENT: "INVALID_ARGUMENT"
|
|
65
|
+
});
|
|
66
|
+
var DIG_SDK_ERROR_BRAND = "__dignetwork_dig_sdk_error__";
|
|
67
|
+
var DigSdkError = class _DigSdkError extends Error {
|
|
68
|
+
constructor(code, message, context = {}, options = {}) {
|
|
69
|
+
super(message);
|
|
70
|
+
this.name = "DigSdkError";
|
|
71
|
+
this.code = code;
|
|
72
|
+
this.context = context;
|
|
73
|
+
if (options.cause !== void 0) {
|
|
74
|
+
this.cause = options.cause;
|
|
75
|
+
}
|
|
76
|
+
Object.defineProperty(this, DIG_SDK_ERROR_BRAND, { value: true, enumerable: false });
|
|
77
|
+
Object.setPrototypeOf(this, _DigSdkError.prototype);
|
|
78
|
+
}
|
|
79
|
+
/** A JSON-friendly view of the error: `{ code, message, context }`. */
|
|
80
|
+
toJSON() {
|
|
81
|
+
return { code: this.code, message: this.message, context: this.context };
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
function isDigSdkError(e, code) {
|
|
85
|
+
const branded = e instanceof DigSdkError || typeof e === "object" && e !== null && e[DIG_SDK_ERROR_BRAND] === true;
|
|
86
|
+
return branded && (code === void 0 || e.code === code);
|
|
87
|
+
}
|
|
88
|
+
|
|
20
89
|
// src/provider/injected.ts
|
|
21
90
|
function getInjectedProvider() {
|
|
22
91
|
const g = globalThis;
|
|
@@ -49,7 +118,11 @@ var InjectedTransport = class {
|
|
|
49
118
|
}
|
|
50
119
|
async request(method, params) {
|
|
51
120
|
if (!this.supports(method)) {
|
|
52
|
-
throw new
|
|
121
|
+
throw new DigSdkError(
|
|
122
|
+
"METHOD_NOT_SUPPORTED",
|
|
123
|
+
`The DIG Browser wallet does not support "${method}".`,
|
|
124
|
+
{ method }
|
|
125
|
+
);
|
|
53
126
|
}
|
|
54
127
|
return this.provider.request({ method, params });
|
|
55
128
|
}
|
|
@@ -133,8 +206,10 @@ var WalletConnectTransport = class _WalletConnectTransport {
|
|
|
133
206
|
}
|
|
134
207
|
async request(method, params) {
|
|
135
208
|
if (!this.supports(method)) {
|
|
136
|
-
throw new
|
|
137
|
-
|
|
209
|
+
throw new DigSdkError(
|
|
210
|
+
"METHOD_NOT_SUPPORTED",
|
|
211
|
+
`Your wallet session does not grant "${method}". Disconnect and reconnect your wallet to refresh the session (and make sure Sage is up to date).`,
|
|
212
|
+
{ method }
|
|
138
213
|
);
|
|
139
214
|
}
|
|
140
215
|
const MAX_ATTEMPTS = 3;
|
|
@@ -157,7 +232,13 @@ var WalletConnectTransport = class _WalletConnectTransport {
|
|
|
157
232
|
let t;
|
|
158
233
|
const timeout = new Promise((_, rej) => {
|
|
159
234
|
t = setTimeout(
|
|
160
|
-
() => rej(
|
|
235
|
+
() => rej(
|
|
236
|
+
new DigSdkError(
|
|
237
|
+
"WALLET_TIMEOUT",
|
|
238
|
+
"Sage did not respond \u2014 open the Sage app and try again.",
|
|
239
|
+
{ method, timeoutMs: this.requestTimeoutMs }
|
|
240
|
+
)
|
|
241
|
+
),
|
|
161
242
|
this.requestTimeoutMs
|
|
162
243
|
);
|
|
163
244
|
});
|
|
@@ -187,9 +268,12 @@ async function loadSignClient() {
|
|
|
187
268
|
throw new Error("unexpected @walletconnect/sign-client shape");
|
|
188
269
|
}
|
|
189
270
|
return SignClient;
|
|
190
|
-
} catch {
|
|
191
|
-
throw new
|
|
192
|
-
"
|
|
271
|
+
} catch (e) {
|
|
272
|
+
throw new DigSdkError(
|
|
273
|
+
"WC_DEPENDENCY_MISSING",
|
|
274
|
+
"WalletConnect fallback requires the optional peer dependency '@walletconnect/sign-client'. Install it (npm i @walletconnect/sign-client) to use the WalletConnect\u2192Sage transport.",
|
|
275
|
+
{},
|
|
276
|
+
{ cause: e }
|
|
193
277
|
);
|
|
194
278
|
}
|
|
195
279
|
}
|
|
@@ -226,7 +310,8 @@ async function signMessage(request, supports, message, address) {
|
|
|
226
310
|
}
|
|
227
311
|
const keys = await getPublicKeys(request);
|
|
228
312
|
const publicKey = keys[0];
|
|
229
|
-
if (!publicKey)
|
|
313
|
+
if (!publicKey)
|
|
314
|
+
throw new DigSdkError("WALLET_NO_KEYS", "Wallet returned no keys to sign with.");
|
|
230
315
|
const sig = normalizeSig(await request("chip0002_signMessage", { message, publicKey }));
|
|
231
316
|
return { publicKey: sig.publicKey ?? with0x(publicKey), signature: sig.signature };
|
|
232
317
|
}
|
|
@@ -238,7 +323,11 @@ async function signCoinSpends(request, coinSpends) {
|
|
|
238
323
|
}
|
|
239
324
|
async function takeOffer(request, supports, offer, fee = 0) {
|
|
240
325
|
if (!supports("chia_takeOffer")) {
|
|
241
|
-
throw new
|
|
326
|
+
throw new DigSdkError(
|
|
327
|
+
"METHOD_NOT_SUPPORTED",
|
|
328
|
+
"Your wallet session does not support taking offers. Reconnect your wallet.",
|
|
329
|
+
{ method: "chia_takeOffer" }
|
|
330
|
+
);
|
|
242
331
|
}
|
|
243
332
|
return request("chia_takeOffer", { offer, fee });
|
|
244
333
|
}
|
|
@@ -322,8 +411,10 @@ var ChiaProvider = class _ChiaProvider {
|
|
|
322
411
|
};
|
|
323
412
|
const tryWalletConnect = async () => {
|
|
324
413
|
if (!options.walletConnect) {
|
|
325
|
-
throw new
|
|
326
|
-
"
|
|
414
|
+
throw new DigSdkError(
|
|
415
|
+
"WC_OPTIONS_REQUIRED",
|
|
416
|
+
"WalletConnect options are required to connect via WalletConnect (pass { walletConnect: { projectId, metadata, onUri } }).",
|
|
417
|
+
{ mode }
|
|
327
418
|
);
|
|
328
419
|
}
|
|
329
420
|
const transport = await WalletConnectTransport.connect({
|
|
@@ -335,8 +426,10 @@ var ChiaProvider = class _ChiaProvider {
|
|
|
335
426
|
if (mode === "injected") {
|
|
336
427
|
const injected = await tryInjected();
|
|
337
428
|
if (!injected) {
|
|
338
|
-
throw new
|
|
339
|
-
"
|
|
429
|
+
throw new DigSdkError(
|
|
430
|
+
"NO_INJECTED_WALLET",
|
|
431
|
+
"No injected DIG wallet found. Open this page in the DIG Browser, or use mode 'auto'.",
|
|
432
|
+
{ mode, acceptAnyInjected: !!options.acceptAnyInjected }
|
|
340
433
|
);
|
|
341
434
|
}
|
|
342
435
|
return injected;
|
|
@@ -411,8 +504,202 @@ function connectWallet(options) {
|
|
|
411
504
|
return ChiaProvider.connect(options);
|
|
412
505
|
}
|
|
413
506
|
|
|
507
|
+
// src/paywall.ts
|
|
508
|
+
function strip0x2(hex) {
|
|
509
|
+
return hex.replace(/^0x/i, "").toLowerCase();
|
|
510
|
+
}
|
|
511
|
+
function hexToBytes(hex) {
|
|
512
|
+
const h = strip0x2(hex);
|
|
513
|
+
if (h.length % 2 !== 0 || /[^0-9a-f]/.test(h)) {
|
|
514
|
+
throw new DigSdkError("INVALID_ARGUMENT", `invalid hex string: ${hex}`, { value: hex });
|
|
515
|
+
}
|
|
516
|
+
const out = new Uint8Array(h.length / 2);
|
|
517
|
+
for (let i = 0; i < out.length; i++) out[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
|
|
518
|
+
return out;
|
|
519
|
+
}
|
|
520
|
+
function bytesToHex(bytes) {
|
|
521
|
+
let s = "";
|
|
522
|
+
for (const b of bytes) s += b.toString(16).padStart(2, "0");
|
|
523
|
+
return s;
|
|
524
|
+
}
|
|
525
|
+
async function randomNonce() {
|
|
526
|
+
const out = new Uint8Array(32);
|
|
527
|
+
const webcrypto = globalThis.crypto;
|
|
528
|
+
if (webcrypto?.getRandomValues) {
|
|
529
|
+
webcrypto.getRandomValues(out);
|
|
530
|
+
return out;
|
|
531
|
+
}
|
|
532
|
+
const nodeCrypto = await import('crypto');
|
|
533
|
+
if (!nodeCrypto.webcrypto?.getRandomValues) {
|
|
534
|
+
throw new DigSdkError(
|
|
535
|
+
"NO_SECURE_RANDOM",
|
|
536
|
+
"No secure random source available to generate a payment nonce."
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
nodeCrypto.webcrypto.getRandomValues(out);
|
|
540
|
+
return out;
|
|
541
|
+
}
|
|
542
|
+
var Paywall = class {
|
|
543
|
+
constructor(provider, options = {}) {
|
|
544
|
+
this.provider = provider;
|
|
545
|
+
this.injectedSpends = options.spends;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Resolve the canonical monetization spends (injected, or lazily imported + `init()`ed). Memoized.
|
|
549
|
+
* This is the ONLY source of coin-spend construction in the Paywall — there is no fallback that
|
|
550
|
+
* hand-rolls a spend.
|
|
551
|
+
*/
|
|
552
|
+
spends() {
|
|
553
|
+
if (this.injectedSpends) {
|
|
554
|
+
if (typeof this.injectedSpends.init === "function") this.injectedSpends.init();
|
|
555
|
+
return Promise.resolve(this.injectedSpends);
|
|
556
|
+
}
|
|
557
|
+
if (!this.spendsReady) {
|
|
558
|
+
this.spendsReady = (async () => {
|
|
559
|
+
const mod = await import(
|
|
560
|
+
/* @vite-ignore */
|
|
561
|
+
'@dignetwork/chip35-dl-coin-wasm'
|
|
562
|
+
);
|
|
563
|
+
if (typeof mod.init === "function") mod.init();
|
|
564
|
+
return mod;
|
|
565
|
+
})().catch((e) => {
|
|
566
|
+
this.spendsReady = void 0;
|
|
567
|
+
throw e;
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return this.spendsReady;
|
|
571
|
+
}
|
|
572
|
+
/** The wallet's first synthetic public key, as bytes (the buyer key the spends are built against). */
|
|
573
|
+
async buyerKey() {
|
|
574
|
+
const keys = await this.provider.getPublicKeys();
|
|
575
|
+
const key = keys?.[0];
|
|
576
|
+
if (!key)
|
|
577
|
+
throw new DigSdkError(
|
|
578
|
+
"WALLET_NO_KEYS",
|
|
579
|
+
"Wallet returned no public keys to build the payment against."
|
|
580
|
+
);
|
|
581
|
+
return hexToBytes(key);
|
|
582
|
+
}
|
|
583
|
+
/** Resolve the 32-byte unlock nonce: explicit hex, else derived from `memo`, else random. */
|
|
584
|
+
async resolveNonce(spends, args) {
|
|
585
|
+
if (args.nonce) return hexToBytes(args.nonce);
|
|
586
|
+
if (args.memo) {
|
|
587
|
+
if (typeof spends.paymentNonce !== "function") {
|
|
588
|
+
throw new DigSdkError(
|
|
589
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
590
|
+
"Cannot derive a nonce from `memo`: the chip35 wasm `paymentNonce` is unavailable.",
|
|
591
|
+
{ builder: "paymentNonce" }
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
return spends.paymentNonce(new TextEncoder().encode(args.memo));
|
|
595
|
+
}
|
|
596
|
+
return randomNonce();
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Charge the buyer (the connected wallet) `amount` to pay the dapp `owner`, then push the
|
|
600
|
+
* wasm-built coin spends to the wallet for signing. Returns the wallet signature + the receipt.
|
|
601
|
+
* Builds via the canonical wasm `buildPayment` (XCH) or `buildCatPayment` (CAT) — never hand-rolled.
|
|
602
|
+
*/
|
|
603
|
+
async requestPayment(args) {
|
|
604
|
+
const spends = await this.spends();
|
|
605
|
+
const ownerPh = hexToBytes(args.owner);
|
|
606
|
+
const amount = BigInt(args.amount);
|
|
607
|
+
const nonce = await this.resolveNonce(spends, args);
|
|
608
|
+
const buyerKey = await this.buyerKey();
|
|
609
|
+
let built;
|
|
610
|
+
if (args.assetId) {
|
|
611
|
+
if (typeof spends.buildCatPayment !== "function") {
|
|
612
|
+
throw new DigSdkError(
|
|
613
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
614
|
+
"chip35 wasm `buildCatPayment` is unavailable \u2014 cannot build a CAT payment (the Paywall never hand-rolls spends).",
|
|
615
|
+
{ builder: "buildCatPayment" }
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
const cats = await this.provider.getCatCoins(strip0x2(args.assetId), args.coinLimit);
|
|
619
|
+
built = spends.buildCatPayment(buyerKey, cats, ownerPh, amount, nonce);
|
|
620
|
+
} else {
|
|
621
|
+
if (typeof spends.buildPayment !== "function") {
|
|
622
|
+
throw new DigSdkError(
|
|
623
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
624
|
+
"chip35 wasm `buildPayment` is unavailable \u2014 cannot build an XCH payment (the Paywall never hand-rolls spends).",
|
|
625
|
+
{ builder: "buildPayment" }
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
const coins = await this.provider.getXchCoins(args.coinLimit);
|
|
629
|
+
built = spends.buildPayment(buyerKey, coins, ownerPh, amount, nonce, BigInt(args.fee ?? 0));
|
|
630
|
+
}
|
|
631
|
+
const signature = await this.provider.signCoinSpends(built.coinSpends);
|
|
632
|
+
return {
|
|
633
|
+
signature,
|
|
634
|
+
receipt: built.receipt,
|
|
635
|
+
coinSpends: built.coinSpends,
|
|
636
|
+
nonce: bytesToHex(nonce)
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Verify an observed on-chain payment unlocks the paywall (pay-to-unlock). Delegates to the wasm
|
|
641
|
+
* `verifyPaymentReceipt`; returns its `{ ok, error? }` verdict. `ok:true` grants access.
|
|
642
|
+
*/
|
|
643
|
+
async verifyReceipt(args) {
|
|
644
|
+
const spends = await this.spends();
|
|
645
|
+
if (typeof spends.verifyPaymentReceipt !== "function") {
|
|
646
|
+
throw new DigSdkError(
|
|
647
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
648
|
+
"chip35 wasm `verifyPaymentReceipt` is unavailable.",
|
|
649
|
+
{ builder: "verifyPaymentReceipt" }
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
const asset = args.asset ?? { xch: true };
|
|
653
|
+
const requiredAsset = "assetId" in asset && asset.assetId ? { assetId: hexToBytes(asset.assetId) } : { xch: true };
|
|
654
|
+
const requireNonce = args.nonce ? hexToBytes(args.nonce) : null;
|
|
655
|
+
return spends.verifyPaymentReceipt(
|
|
656
|
+
args.observed,
|
|
657
|
+
hexToBytes(args.owner),
|
|
658
|
+
BigInt(args.minAmount),
|
|
659
|
+
requiredAsset,
|
|
660
|
+
requireNonce
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Prove the `owner` holds access: gate on a specific NFT (`nft` launcher id) via the wasm
|
|
665
|
+
* `proveNftOwnership`, or on collection/creator membership (`collection` DID) via
|
|
666
|
+
* `proveCollectionMembership`. Returns `{ ok, proof?, error? }`. The caller still confirms the
|
|
667
|
+
* proof's coin is unspent on-chain for liveness.
|
|
668
|
+
*/
|
|
669
|
+
async proveAccess(args) {
|
|
670
|
+
if (args.nft && args.collection) {
|
|
671
|
+
throw new DigSdkError(
|
|
672
|
+
"INVALID_ARGUMENT",
|
|
673
|
+
"proveAccess: pass either `nft` or `collection`, not both.",
|
|
674
|
+
{ value: "nft+collection" }
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
const spends = await this.spends();
|
|
678
|
+
const owner = hexToBytes(args.owner);
|
|
679
|
+
if (args.collection) {
|
|
680
|
+
if (typeof spends.proveCollectionMembership !== "function") {
|
|
681
|
+
throw new DigSdkError(
|
|
682
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
683
|
+
"chip35 wasm `proveCollectionMembership` is unavailable.",
|
|
684
|
+
{ builder: "proveCollectionMembership" }
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
return spends.proveCollectionMembership(args.parentSpend, owner, hexToBytes(args.collection));
|
|
688
|
+
}
|
|
689
|
+
if (typeof spends.proveNftOwnership !== "function") {
|
|
690
|
+
throw new DigSdkError(
|
|
691
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
692
|
+
"chip35 wasm `proveNftOwnership` is unavailable.",
|
|
693
|
+
{ builder: "proveNftOwnership" }
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
const requiredNft = args.nft ? hexToBytes(args.nft) : null;
|
|
697
|
+
return spends.proveNftOwnership(args.parentSpend, owner, requiredNft);
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
|
|
414
701
|
// src/loader.ts
|
|
415
|
-
var DIG_CLIENT_WASM_SHA256 = "
|
|
702
|
+
var DIG_CLIENT_WASM_SHA256 = "8c983561eabca34778abf698ca7c2fba36117f87282ca649079599ef7d1b1156";
|
|
416
703
|
var _config = {};
|
|
417
704
|
var _ready = null;
|
|
418
705
|
function configureWasm(config) {
|
|
@@ -436,49 +723,62 @@ async function sha256Hex(bytes) {
|
|
|
436
723
|
function assertIntegrity(hex) {
|
|
437
724
|
if (_config.skipIntegrity) return;
|
|
438
725
|
if (hex !== DIG_CLIENT_WASM_SHA256) {
|
|
439
|
-
throw new
|
|
440
|
-
|
|
726
|
+
throw new DigSdkError(
|
|
727
|
+
"WASM_INTEGRITY",
|
|
728
|
+
`dig-client wasm integrity check failed \u2014 refusing to run unverified crypto (expected ${DIG_CLIENT_WASM_SHA256}, got ${hex}).`,
|
|
729
|
+
{ expected: DIG_CLIENT_WASM_SHA256, actual: hex }
|
|
441
730
|
);
|
|
442
731
|
}
|
|
443
732
|
}
|
|
444
733
|
async function loadNode() {
|
|
734
|
+
const { createRequire } = await import('module');
|
|
445
735
|
const { readFile } = await import('fs/promises');
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
449
|
-
const vendorDir = path.resolve(here, "..", "vendor");
|
|
450
|
-
const wasmPath = path.join(vendorDir, "dig_client_bg.wasm");
|
|
451
|
-
const gluePath = path.join(vendorDir, "dig_client.mjs");
|
|
736
|
+
const require2 = createRequire(import.meta.url);
|
|
737
|
+
const wasmPath = require2.resolve("@dignetwork/dig-client/dig_client_bg.wasm");
|
|
452
738
|
const buf = await readFile(wasmPath);
|
|
453
739
|
const bytes = new Uint8Array(buf.byteLength);
|
|
454
740
|
bytes.set(buf);
|
|
455
|
-
|
|
741
|
+
assertIntegrity(await sha256Hex(bytes));
|
|
742
|
+
const mod = await import('@dignetwork/dig-client/node');
|
|
743
|
+
return mod;
|
|
456
744
|
}
|
|
457
745
|
async function loadBrowser() {
|
|
458
|
-
const glueHref = _config.glueUrl ??
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
746
|
+
const glueHref = _config.glueUrl ?? "@dignetwork/dig-client/web";
|
|
747
|
+
const mod = await import(
|
|
748
|
+
/* @vite-ignore */
|
|
749
|
+
glueHref
|
|
750
|
+
);
|
|
751
|
+
if (typeof mod.default !== "function") {
|
|
752
|
+
throw new DigSdkError(
|
|
753
|
+
"WASM_LOAD_FAILED",
|
|
754
|
+
"dig-client web build exposed no init function (unexpected module shape)",
|
|
755
|
+
{}
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
if (_config.wasmBytes || _config.wasmUrl) {
|
|
759
|
+
let bytes;
|
|
760
|
+
if (_config.wasmBytes) {
|
|
761
|
+
bytes = _config.wasmBytes;
|
|
762
|
+
} else {
|
|
763
|
+
const wasmUrl = _config.wasmUrl;
|
|
764
|
+
const res = await fetch(wasmUrl);
|
|
765
|
+
if (!res.ok)
|
|
766
|
+
throw new DigSdkError("WASM_LOAD_FAILED", `dig-client wasm fetch failed (${res.status})`, {
|
|
767
|
+
httpStatus: res.status,
|
|
768
|
+
wasmUrl
|
|
769
|
+
});
|
|
770
|
+
bytes = await res.arrayBuffer();
|
|
771
|
+
}
|
|
772
|
+
assertIntegrity(await sha256Hex(bytes));
|
|
773
|
+
await mod.default({ module_or_path: bytes });
|
|
462
774
|
} else {
|
|
463
|
-
|
|
464
|
-
const res = await fetch(wasmUrl);
|
|
465
|
-
if (!res.ok) throw new Error(`dig-client wasm fetch failed (${res.status})`);
|
|
466
|
-
bytes = await res.arrayBuffer();
|
|
775
|
+
await mod.default();
|
|
467
776
|
}
|
|
468
|
-
return
|
|
777
|
+
return mod;
|
|
469
778
|
}
|
|
470
779
|
function loadDigClientWasm() {
|
|
471
780
|
if (_ready) return _ready;
|
|
472
|
-
_ready = (
|
|
473
|
-
const { glueHref, bytes } = isNode ? await loadNode() : await loadBrowser();
|
|
474
|
-
assertIntegrity(await sha256Hex(bytes));
|
|
475
|
-
const mod = await import(
|
|
476
|
-
/* @vite-ignore */
|
|
477
|
-
glueHref
|
|
478
|
-
);
|
|
479
|
-
await mod.default({ module_or_path: bytes });
|
|
480
|
-
return mod;
|
|
481
|
-
})().catch((e) => {
|
|
781
|
+
_ready = (isNode ? loadNode() : loadBrowser()).catch((e) => {
|
|
482
782
|
_ready = null;
|
|
483
783
|
throw e;
|
|
484
784
|
});
|
|
@@ -491,8 +791,10 @@ function parseUrn(raw) {
|
|
|
491
791
|
const s = String(raw ?? "").trim();
|
|
492
792
|
const m = URN_RE.exec(s);
|
|
493
793
|
if (!m) {
|
|
494
|
-
throw new
|
|
495
|
-
"
|
|
794
|
+
throw new DigSdkError(
|
|
795
|
+
"INVALID_ARGUMENT",
|
|
796
|
+
"Not a valid dig URN (expected urn:dig:chia:<store-id>[:<root>]/<path>[?salt=<hex>]).",
|
|
797
|
+
{ value: s, expected: "urn:dig:chia:<store-id>[:<root>]/<path>[?salt=<hex>]" }
|
|
496
798
|
);
|
|
497
799
|
}
|
|
498
800
|
return {
|
|
@@ -584,8 +886,10 @@ var DigClient = class {
|
|
|
584
886
|
const effSalt = input.salt ?? parsed.salt ?? null;
|
|
585
887
|
const effRoot = input.root ?? parsed.root ?? null;
|
|
586
888
|
if (!effRoot) {
|
|
587
|
-
throw new
|
|
588
|
-
"
|
|
889
|
+
throw new DigSdkError(
|
|
890
|
+
"ROOT_REQUIRED",
|
|
891
|
+
"a confirmed on-chain root is required to read content (pass { root } or use a root-pinned URN)",
|
|
892
|
+
{ urn: input.urn }
|
|
589
893
|
);
|
|
590
894
|
}
|
|
591
895
|
return this.readResource(
|
|
@@ -597,8 +901,10 @@ var DigClient = class {
|
|
|
597
901
|
async readText(input, opts = {}) {
|
|
598
902
|
const r = await this.read(input, opts);
|
|
599
903
|
if (!r.decrypted) {
|
|
600
|
-
throw new
|
|
601
|
-
"
|
|
904
|
+
throw new DigSdkError(
|
|
905
|
+
"DECRYPT_FAILED",
|
|
906
|
+
"resource did not decrypt under this URN \u2014 wrong store/key/salt, or a decoy response",
|
|
907
|
+
{ urn: input.urn }
|
|
602
908
|
);
|
|
603
909
|
}
|
|
604
910
|
return new TextDecoder().decode(r.bytes);
|
|
@@ -647,6 +953,62 @@ var DigClient = class {
|
|
|
647
953
|
};
|
|
648
954
|
}
|
|
649
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Read a collection's public, owner-independent facts (creator DID, item count, uniform royalty)
|
|
958
|
+
* from the dig RPC (`dig.getCollection`). The collection's item set is its NFT launcher ids — the
|
|
959
|
+
* authoritative, owner-independent anchor the mint produced (a DID-attributed NFT is hinted to its
|
|
960
|
+
* OWNER at mint, not to the creator DID, so launcher ids — not the DID — are the read key). Pass
|
|
961
|
+
* the optional `did` to have it echoed back and recorded as the declared creator.
|
|
962
|
+
*
|
|
963
|
+
* No wallet, no read-crypto wasm — a plain JSON-RPC read. Throws a coded {@link DigSdkError} on a
|
|
964
|
+
* transport/RPC failure (never a "not found": an empty/partly-confirmed set just resolves to fewer
|
|
965
|
+
* items).
|
|
966
|
+
*
|
|
967
|
+
* @example
|
|
968
|
+
* const meta = await dig.getCollection({ launcherIds: ["ab…", "cd…"], did: "ef…" });
|
|
969
|
+
* console.log(meta.resolved_count, meta.royalty_basis_points);
|
|
970
|
+
*/
|
|
971
|
+
async getCollection(input, opts = {}) {
|
|
972
|
+
const rpc = opts.rpc ?? this.rpc;
|
|
973
|
+
const params = { launcher_ids: input.launcherIds };
|
|
974
|
+
if (input.did) params.did = input.did;
|
|
975
|
+
const r = await this.rpcCall(rpc, "dig.getCollection", params);
|
|
976
|
+
if (!r)
|
|
977
|
+
throw new DigSdkError(
|
|
978
|
+
"RPC_MALFORMED_RESPONSE",
|
|
979
|
+
"The content network returned no collection facts for this request.",
|
|
980
|
+
{ rpcMethod: "dig.getCollection" }
|
|
981
|
+
);
|
|
982
|
+
return r;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Read a deterministic, paginated page of a collection's items (`dig.listCollectionItems`), each
|
|
986
|
+
* resolved to its CURRENT on-chain state — current owner, royalty, and CHIP-0007 metadata — by the
|
|
987
|
+
* RPC walking the singleton lineage forward to the live tip (so the owner is never the stale
|
|
988
|
+
* mint-time owner). Items come back in the input launcher-id order. `limit` is clamped to the
|
|
989
|
+
* server cap (200); `offset` defaults to 0.
|
|
990
|
+
*
|
|
991
|
+
* Throws a coded {@link DigSdkError} on a transport/RPC failure.
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* let page = await dig.listCollectionItems({ launcherIds, limit: 50 });
|
|
995
|
+
* for (const item of page.items) console.log(item.launcher_id, item.owner_puzzle_hash);
|
|
996
|
+
* // page.next_offset is null on the last page.
|
|
997
|
+
*/
|
|
998
|
+
async listCollectionItems(input, opts = {}) {
|
|
999
|
+
const rpc = opts.rpc ?? this.rpc;
|
|
1000
|
+
const params = { launcher_ids: input.launcherIds };
|
|
1001
|
+
if (input.offset !== void 0) params.offset = input.offset;
|
|
1002
|
+
if (input.limit !== void 0) params.limit = input.limit;
|
|
1003
|
+
const r = await this.rpcCall(rpc, "dig.listCollectionItems", params);
|
|
1004
|
+
if (!r)
|
|
1005
|
+
throw new DigSdkError(
|
|
1006
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1007
|
+
"The content network returned no collection items for this request.",
|
|
1008
|
+
{ rpcMethod: "dig.listCollectionItems" }
|
|
1009
|
+
);
|
|
1010
|
+
return r;
|
|
1011
|
+
}
|
|
650
1012
|
// Stream the FULL ciphertext for a resource from the RPC by retrieval key, reassembling 3-MiB
|
|
651
1013
|
// chunks. A null result is a TRANSPORT failure, never a presence judgment.
|
|
652
1014
|
async fetchCiphertext(storeId, rk, root, rpc) {
|
|
@@ -663,7 +1025,12 @@ var DigClient = class {
|
|
|
663
1025
|
offset,
|
|
664
1026
|
length: RPC_CHUNK_BYTES
|
|
665
1027
|
});
|
|
666
|
-
if (!r)
|
|
1028
|
+
if (!r)
|
|
1029
|
+
throw new DigSdkError(
|
|
1030
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1031
|
+
"The content network returned no data for this request.",
|
|
1032
|
+
{ rpcMethod: "dig.getContent" }
|
|
1033
|
+
);
|
|
667
1034
|
if (total === null) {
|
|
668
1035
|
total = r.total_length >>> 0;
|
|
669
1036
|
buf = new Uint8Array(total);
|
|
@@ -680,7 +1047,8 @@ var DigClient = class {
|
|
|
680
1047
|
}
|
|
681
1048
|
return { ciphertext: buf ?? new Uint8Array(0), proof, chunkLens };
|
|
682
1049
|
}
|
|
683
|
-
// One JSON-RPC 2.0 call. Throws on transport failure or a
|
|
1050
|
+
// One JSON-RPC 2.0 call. Throws a coded DigSdkError on transport failure (RPC_TRANSPORT) or a
|
|
1051
|
+
// JSON-RPC/HTTP error (RPC_ERROR, carrying rpcMethod/httpStatus/rpcCode context); returns `result`.
|
|
684
1052
|
async rpcCall(rpc, method, params) {
|
|
685
1053
|
let res;
|
|
686
1054
|
try {
|
|
@@ -689,12 +1057,26 @@ var DigClient = class {
|
|
|
689
1057
|
headers: { "content-type": "application/json" },
|
|
690
1058
|
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params })
|
|
691
1059
|
});
|
|
692
|
-
} catch {
|
|
693
|
-
throw new
|
|
1060
|
+
} catch (e) {
|
|
1061
|
+
throw new DigSdkError(
|
|
1062
|
+
"RPC_TRANSPORT",
|
|
1063
|
+
"Could not reach the content network. Check your connection and try again.",
|
|
1064
|
+
{ rpcMethod: method },
|
|
1065
|
+
{ cause: e }
|
|
1066
|
+
);
|
|
694
1067
|
}
|
|
695
|
-
if (!res.ok)
|
|
1068
|
+
if (!res.ok)
|
|
1069
|
+
throw new DigSdkError("RPC_ERROR", `dig RPC ${method} failed (${res.status})`, {
|
|
1070
|
+
rpcMethod: method,
|
|
1071
|
+
httpStatus: res.status
|
|
1072
|
+
});
|
|
696
1073
|
const json = await res.json();
|
|
697
|
-
if (json && json.error)
|
|
1074
|
+
if (json && json.error)
|
|
1075
|
+
throw new DigSdkError(
|
|
1076
|
+
"RPC_ERROR",
|
|
1077
|
+
`dig RPC ${method}: ${json.error.message ?? "error"}`,
|
|
1078
|
+
{ rpcMethod: method, rpcCode: json.error.code }
|
|
1079
|
+
);
|
|
698
1080
|
return json ? json.result ?? null : null;
|
|
699
1081
|
}
|
|
700
1082
|
};
|
|
@@ -702,7 +1084,11 @@ function decryptResourceChunks(wasm, keyHex, ciphertext, chunkLens) {
|
|
|
702
1084
|
const lens = chunkLens && chunkLens.length ? chunkLens : [ciphertext.length];
|
|
703
1085
|
const total = lens.reduce((a, n) => a + n, 0);
|
|
704
1086
|
if (total !== ciphertext.length) {
|
|
705
|
-
throw new
|
|
1087
|
+
throw new DigSdkError(
|
|
1088
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1089
|
+
"served ciphertext length does not match chunk lengths",
|
|
1090
|
+
{ rpcMethod: "dig.getContent", expected: String(total), actual: String(ciphertext.length) }
|
|
1091
|
+
);
|
|
706
1092
|
}
|
|
707
1093
|
if (lens.length === 1) return wasm.decryptChunk(keyHex, ciphertext);
|
|
708
1094
|
const parts = [];
|
|
@@ -721,12 +1107,58 @@ function decryptResourceChunks(wasm, keyHex, ciphertext, chunkLens) {
|
|
|
721
1107
|
}
|
|
722
1108
|
function undefinedFetch() {
|
|
723
1109
|
return (() => {
|
|
724
|
-
throw new
|
|
1110
|
+
throw new DigSdkError(
|
|
1111
|
+
"INVALID_ARGUMENT",
|
|
725
1112
|
"No global fetch available. Pass { fetch } to DigClient (Node < 18 needs a fetch polyfill)."
|
|
726
1113
|
);
|
|
727
1114
|
});
|
|
728
1115
|
}
|
|
729
1116
|
|
|
730
|
-
|
|
1117
|
+
// src/capabilities.ts
|
|
1118
|
+
var SDK_VERSION = "0.2.1" ;
|
|
1119
|
+
var MODULES = Object.freeze([
|
|
1120
|
+
{
|
|
1121
|
+
name: "ChiaProvider",
|
|
1122
|
+
summary: "Unified Chia wallet surface \u2014 prefers the injected DIG Browser wallet, falls back to WalletConnect\u2192Sage.",
|
|
1123
|
+
entry: "@dignetwork/dig-sdk"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
name: "DigClient",
|
|
1127
|
+
summary: "Read-crypto: derive URN keys, verify inclusion against an on-chain root, and decrypt content from the dig RPC.",
|
|
1128
|
+
entry: "@dignetwork/dig-sdk"
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
name: "Paywall",
|
|
1132
|
+
summary: "Pay-to-unlock helper composing ChiaProvider with the canonical chip35 monetization spends (payment / receipt / NFT+collection gating).",
|
|
1133
|
+
entry: "@dignetwork/dig-sdk"
|
|
1134
|
+
},
|
|
1135
|
+
{
|
|
1136
|
+
name: "spend",
|
|
1137
|
+
summary: "The canonical CHIP-0035 spend builder (@dignetwork/chip35-dl-coin-wasm), re-exported verbatim.",
|
|
1138
|
+
entry: "@dignetwork/dig-sdk/spend"
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
name: "adapters",
|
|
1142
|
+
summary: "Framework deploy glue (Vite + Next): dev window.chia shim and `digstore deploy` runner.",
|
|
1143
|
+
entry: "@dignetwork/dig-sdk/adapters"
|
|
1144
|
+
}
|
|
1145
|
+
]);
|
|
1146
|
+
function capabilities() {
|
|
1147
|
+
return {
|
|
1148
|
+
name: "@dignetwork/dig-sdk",
|
|
1149
|
+
version: SDK_VERSION,
|
|
1150
|
+
modules: MODULES,
|
|
1151
|
+
walletMethods: [...WALLET_METHODS],
|
|
1152
|
+
signMethods: [...SIGN_METHODS],
|
|
1153
|
+
transports: ["injected", "walletconnect"],
|
|
1154
|
+
chains: [DEFAULT_CHAIN],
|
|
1155
|
+
defaultRpc: DEFAULT_RPC,
|
|
1156
|
+
readCryptoWasmSha256: DIG_CLIENT_WASM_SHA256,
|
|
1157
|
+
errorCodes: Object.values(DIG_SDK_ERROR_CODES)
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
var describe = capabilities;
|
|
1161
|
+
|
|
1162
|
+
export { ChiaProvider, DEFAULT_CHAIN, DEFAULT_RPC, DIG_CLIENT_WASM_SHA256, DIG_SDK_ERROR_CODES, DigClient, DigSdkError, INJECTED_TOPIC, InjectedTransport, Paywall, SDK_VERSION, SIGN_METHODS, WALLET_METHODS, WalletConnectTransport, capabilities, configureWasm, connectWallet, describe, getInjectedProvider, isDigSdkError, isInjectedAvailable, isTransientPublishError, isUrn, loadDigClientWasm, parseUrn, reconstructUrn, reconstructUrnWithRoot };
|
|
731
1163
|
//# sourceMappingURL=index.js.map
|
|
732
1164
|
//# sourceMappingURL=index.js.map
|