@dignetwork/dig-sdk 0.0.1-alpha.99 → 0.2.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/LICENSE +21 -7
- package/README.md +412 -0
- package/dist/adapters.cjs +356 -0
- package/dist/adapters.cjs.map +1 -0
- package/dist/adapters.d.cts +20 -0
- package/dist/adapters.d.ts +20 -0
- package/dist/adapters.js +347 -0
- package/dist/adapters.js.map +1 -0
- package/dist/dev-shim-DfKRA1ok.d.cts +128 -0
- package/dist/dev-shim-DfKRA1ok.d.ts +128 -0
- package/dist/dig-client-entry-ChYxUvBn.d.cts +372 -0
- package/dist/dig-client-entry-ChYxUvBn.d.ts +372 -0
- package/dist/dig-client.cjs +443 -0
- package/dist/dig-client.cjs.map +1 -0
- package/dist/dig-client.d.cts +1 -0
- package/dist/dig-client.d.ts +1 -0
- package/dist/dig-client.js +432 -0
- package/dist/dig-client.js.map +1 -0
- package/dist/index.cjs +1186 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +502 -0
- package/dist/index.d.ts +502 -5
- package/dist/index.js +1156 -19
- package/dist/index.js.map +1 -0
- package/dist/next.cjs +369 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +23 -0
- package/dist/next.d.ts +23 -0
- package/dist/next.js +362 -0
- package/dist/next.js.map +1 -0
- package/dist/spend.cjs +14 -0
- package/dist/spend.cjs.map +1 -0
- package/dist/spend.d.cts +1 -0
- package/dist/spend.d.ts +1 -0
- package/dist/spend.js +3 -0
- package/dist/spend.js.map +1 -0
- package/dist/vite.cjs +381 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +35 -0
- package/dist/vite.d.ts +35 -0
- package/dist/vite.js +375 -0
- package/dist/vite.js.map +1 -0
- package/package.json +87 -59
- package/vendor/PROVENANCE.md +102 -0
- package/vendor/dig_client.d.ts +150 -0
- package/vendor/dig_client.mjs +805 -0
- package/vendor/dig_client_bg.wasm +0 -0
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts +0 -163
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +0 -1
- package/dist/DataIntegrityTree/DataIntegrityTree.js +0 -707
- package/dist/DataIntegrityTree/DataLayerError.d.ts +0 -6
- package/dist/DataIntegrityTree/DataLayerError.d.ts.map +0 -1
- package/dist/DataIntegrityTree/DataLayerError.js +0 -17
- package/dist/DataIntegrityTree/index.d.ts +0 -2
- package/dist/DataIntegrityTree/index.d.ts.map +0 -1
- package/dist/DataIntegrityTree/index.js +0 -17
- package/dist/DigNetwork/ContentServer.d.ts +0 -31
- package/dist/DigNetwork/ContentServer.d.ts.map +0 -1
- package/dist/DigNetwork/ContentServer.js +0 -176
- package/dist/DigNetwork/DigChallenge.d.ts +0 -82
- package/dist/DigNetwork/DigChallenge.d.ts.map +0 -1
- package/dist/DigNetwork/DigChallenge.js +0 -144
- package/dist/DigNetwork/DigNetwork.d.ts +0 -14
- package/dist/DigNetwork/DigNetwork.d.ts.map +0 -1
- package/dist/DigNetwork/DigNetwork.js +0 -169
- package/dist/DigNetwork/DigPeer.d.ts +0 -24
- package/dist/DigNetwork/DigPeer.d.ts.map +0 -1
- package/dist/DigNetwork/DigPeer.js +0 -118
- package/dist/DigNetwork/IncentiveServer.d.ts +0 -13
- package/dist/DigNetwork/IncentiveServer.d.ts.map +0 -1
- package/dist/DigNetwork/IncentiveServer.js +0 -76
- package/dist/DigNetwork/PropagationServer.d.ts +0 -81
- package/dist/DigNetwork/PropagationServer.d.ts.map +0 -1
- package/dist/DigNetwork/PropagationServer.js +0 -563
- package/dist/DigNetwork/index.d.ts +0 -4
- package/dist/DigNetwork/index.d.ts.map +0 -1
- package/dist/DigNetwork/index.js +0 -19
- package/dist/blockchain/DataStore.d.ts +0 -67
- package/dist/blockchain/DataStore.d.ts.map +0 -1
- package/dist/blockchain/DataStore.js +0 -413
- package/dist/blockchain/DataStoreSerializer.d.ts +0 -52
- package/dist/blockchain/DataStoreSerializer.d.ts.map +0 -1
- package/dist/blockchain/DataStoreSerializer.js +0 -109
- package/dist/blockchain/FullNodePeer.d.ts +0 -31
- package/dist/blockchain/FullNodePeer.d.ts.map +0 -1
- package/dist/blockchain/FullNodePeer.js +0 -295
- package/dist/blockchain/ServerCoin.d.ts +0 -29
- package/dist/blockchain/ServerCoin.d.ts.map +0 -1
- package/dist/blockchain/ServerCoin.js +0 -324
- package/dist/blockchain/Wallet.d.ts +0 -28
- package/dist/blockchain/Wallet.d.ts.map +0 -1
- package/dist/blockchain/Wallet.js +0 -253
- package/dist/blockchain/coins.d.ts +0 -6
- package/dist/blockchain/coins.d.ts.map +0 -1
- package/dist/blockchain/coins.js +0 -102
- package/dist/blockchain/index.d.ts +0 -8
- package/dist/blockchain/index.d.ts.map +0 -1
- package/dist/blockchain/index.js +0 -36
- package/dist/index.d.ts.map +0 -1
- package/dist/prompts.d.ts +0 -21
- package/dist/prompts.d.ts.map +0 -1
- package/dist/prompts.js +0 -149
- package/dist/types.d.ts +0 -64
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/utils/ContentScanner.d.ts +0 -63
- package/dist/utils/ContentScanner.d.ts.map +0 -1
- package/dist/utils/ContentScanner.js +0 -175
- package/dist/utils/Environment.d.ts +0 -18
- package/dist/utils/Environment.d.ts.map +0 -1
- package/dist/utils/Environment.js +0 -85
- package/dist/utils/FileCache.d.ts +0 -11
- package/dist/utils/FileCache.d.ts.map +0 -1
- package/dist/utils/FileCache.js +0 -58
- package/dist/utils/FileTransfer.d.ts +0 -47
- package/dist/utils/FileTransfer.d.ts.map +0 -1
- package/dist/utils/FileTransfer.js +0 -209
- package/dist/utils/NconfManager.d.ts +0 -11
- package/dist/utils/NconfManager.d.ts.map +0 -1
- package/dist/utils/NconfManager.js +0 -56
- package/dist/utils/StoreArchiveManager.d.ts +0 -45
- package/dist/utils/StoreArchiveManager.d.ts.map +0 -1
- package/dist/utils/StoreArchiveManager.js +0 -153
- package/dist/utils/asyncPool.d.ts +0 -9
- package/dist/utils/asyncPool.d.ts.map +0 -1
- package/dist/utils/asyncPool.js +0 -23
- package/dist/utils/config.d.ts +0 -68
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js +0 -223
- package/dist/utils/connectionUtils.d.ts +0 -10
- package/dist/utils/connectionUtils.d.ts.map +0 -1
- package/dist/utils/connectionUtils.js +0 -18
- package/dist/utils/credentialsUtils.d.ts +0 -8
- package/dist/utils/credentialsUtils.d.ts.map +0 -1
- package/dist/utils/credentialsUtils.js +0 -122
- package/dist/utils/directoryUtils.d.ts +0 -9
- package/dist/utils/directoryUtils.d.ts.map +0 -1
- package/dist/utils/directoryUtils.js +0 -110
- package/dist/utils/encryption.d.ts +0 -8
- package/dist/utils/encryption.d.ts.map +0 -1
- package/dist/utils/encryption.js +0 -55
- package/dist/utils/hashUtils.d.ts +0 -8
- package/dist/utils/hashUtils.d.ts.map +0 -1
- package/dist/utils/hashUtils.js +0 -44
- package/dist/utils/index.d.ts +0 -14
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -29
- package/dist/utils/merkle.d.ts +0 -2
- package/dist/utils/merkle.d.ts.map +0 -1
- package/dist/utils/merkle.js +0 -28
- package/dist/utils/network.d.ts +0 -2
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js +0 -54
- package/dist/utils/spinnerUtils.d.ts +0 -2
- package/dist/utils/spinnerUtils.d.ts.map +0 -1
- package/dist/utils/spinnerUtils.js +0 -47
- package/dist/utils/ssl.d.ts +0 -5
- package/dist/utils/ssl.d.ts.map +0 -1
- package/dist/utils/ssl.js +0 -50
- package/dist/utils/validationUtils.d.ts +0 -9
- package/dist/utils/validationUtils.d.ts.map +0 -1
- package/dist/utils/validationUtils.js +0 -55
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
4
|
+
// src/methods.ts
|
|
5
|
+
var WALLET_METHODS = [
|
|
6
|
+
"chip0002_connect",
|
|
7
|
+
"chip0002_chainId",
|
|
8
|
+
"chip0002_getPublicKeys",
|
|
9
|
+
"chip0002_getAssetCoins",
|
|
10
|
+
"chip0002_getAssetBalance",
|
|
11
|
+
"chip0002_signCoinSpends",
|
|
12
|
+
"chip0002_signMessage",
|
|
13
|
+
"chia_getAddress",
|
|
14
|
+
"chia_signMessageByAddress",
|
|
15
|
+
"chia_takeOffer"
|
|
16
|
+
];
|
|
17
|
+
var SIGN_METHODS = [
|
|
18
|
+
"chia_signMessageByAddress",
|
|
19
|
+
"chip0002_signMessage"
|
|
20
|
+
];
|
|
21
|
+
var DEFAULT_CHAIN = "chia:mainnet";
|
|
22
|
+
|
|
23
|
+
// src/errors.ts
|
|
24
|
+
var DIG_SDK_ERROR_CODES = Object.freeze({
|
|
25
|
+
// ---- provider / connect (provider/chia-provider.ts, provider/*) ----
|
|
26
|
+
/** WalletConnect was requested/needed but no `walletConnect` options were supplied. */
|
|
27
|
+
WC_OPTIONS_REQUIRED: "WC_OPTIONS_REQUIRED",
|
|
28
|
+
/** `mode: "injected"` (or the injected leg of `auto`) found no usable `window.chia`. */
|
|
29
|
+
NO_INJECTED_WALLET: "NO_INJECTED_WALLET",
|
|
30
|
+
/** The optional `@walletconnect/sign-client` peer dependency is not installed/usable. */
|
|
31
|
+
WC_DEPENDENCY_MISSING: "WC_DEPENDENCY_MISSING",
|
|
32
|
+
/** The active wallet session/transport does not grant the requested method. */
|
|
33
|
+
METHOD_NOT_SUPPORTED: "METHOD_NOT_SUPPORTED",
|
|
34
|
+
/** A wallet RPC timed out (e.g. Sage did not respond within the per-request timeout). */
|
|
35
|
+
WALLET_TIMEOUT: "WALLET_TIMEOUT",
|
|
36
|
+
/** The wallet returned no public keys / no key to sign with. */
|
|
37
|
+
WALLET_NO_KEYS: "WALLET_NO_KEYS",
|
|
38
|
+
// ---- read-crypto / RPC (dig-client.ts, loader.ts) ----
|
|
39
|
+
/** A content read needs a confirmed on-chain root and none was supplied/derivable. */
|
|
40
|
+
ROOT_REQUIRED: "ROOT_REQUIRED",
|
|
41
|
+
/** The resource did not decrypt+authenticate under this URN (wrong key/salt, or a decoy). */
|
|
42
|
+
DECRYPT_FAILED: "DECRYPT_FAILED",
|
|
43
|
+
/** The dig RPC could not be reached (network/transport failure). */
|
|
44
|
+
RPC_TRANSPORT: "RPC_TRANSPORT",
|
|
45
|
+
/** The dig RPC responded with an HTTP error or a JSON-RPC `error` object. */
|
|
46
|
+
RPC_ERROR: "RPC_ERROR",
|
|
47
|
+
/** The dig RPC returned a malformed / inconsistent payload (e.g. chunk-length mismatch). */
|
|
48
|
+
RPC_MALFORMED_RESPONSE: "RPC_MALFORMED_RESPONSE",
|
|
49
|
+
/** The vendored read-crypto wasm failed its SRI integrity check — fail closed. */
|
|
50
|
+
WASM_INTEGRITY: "WASM_INTEGRITY",
|
|
51
|
+
/** The read-crypto wasm could not be loaded (fetch/resolve failure). */
|
|
52
|
+
WASM_LOAD_FAILED: "WASM_LOAD_FAILED",
|
|
53
|
+
// ---- paywall / spends (paywall.ts) ----
|
|
54
|
+
/** The canonical chip35 wasm builder for this operation is unavailable (never hand-rolled). */
|
|
55
|
+
SPEND_BUILDER_UNAVAILABLE: "SPEND_BUILDER_UNAVAILABLE",
|
|
56
|
+
/** No secure random source was available to generate a payment nonce. */
|
|
57
|
+
NO_SECURE_RANDOM: "NO_SECURE_RANDOM",
|
|
58
|
+
// ---- deploy / adapters (adapters/run.ts, adapters/deploy.ts) ----
|
|
59
|
+
/** The `digstore` binary could not be spawned (not installed / not on PATH). */
|
|
60
|
+
DIGSTORE_NOT_FOUND: "DIGSTORE_NOT_FOUND",
|
|
61
|
+
/** `digstore deploy` exited non-zero. */
|
|
62
|
+
DEPLOY_FAILED: "DEPLOY_FAILED",
|
|
63
|
+
/** `digstore deploy --json` output could not be parsed into a capsule result. */
|
|
64
|
+
DEPLOY_OUTPUT_UNPARSEABLE: "DEPLOY_OUTPUT_UNPARSEABLE",
|
|
65
|
+
// ---- argument validation (shared) ----
|
|
66
|
+
/** An argument was malformed (e.g. a non-hex string, a bad URN, mutually-exclusive options). */
|
|
67
|
+
INVALID_ARGUMENT: "INVALID_ARGUMENT"
|
|
68
|
+
});
|
|
69
|
+
var DIG_SDK_ERROR_BRAND = "__dignetwork_dig_sdk_error__";
|
|
70
|
+
var DigSdkError = class _DigSdkError extends Error {
|
|
71
|
+
constructor(code, message, context = {}, options = {}) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "DigSdkError";
|
|
74
|
+
this.code = code;
|
|
75
|
+
this.context = context;
|
|
76
|
+
if (options.cause !== void 0) {
|
|
77
|
+
this.cause = options.cause;
|
|
78
|
+
}
|
|
79
|
+
Object.defineProperty(this, DIG_SDK_ERROR_BRAND, { value: true, enumerable: false });
|
|
80
|
+
Object.setPrototypeOf(this, _DigSdkError.prototype);
|
|
81
|
+
}
|
|
82
|
+
/** A JSON-friendly view of the error: `{ code, message, context }`. */
|
|
83
|
+
toJSON() {
|
|
84
|
+
return { code: this.code, message: this.message, context: this.context };
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function isDigSdkError(e, code) {
|
|
88
|
+
const branded = e instanceof DigSdkError || typeof e === "object" && e !== null && e[DIG_SDK_ERROR_BRAND] === true;
|
|
89
|
+
return branded && (code === void 0 || e.code === code);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/provider/injected.ts
|
|
93
|
+
function getInjectedProvider() {
|
|
94
|
+
const g = globalThis;
|
|
95
|
+
return typeof g !== "undefined" ? g.chia : void 0;
|
|
96
|
+
}
|
|
97
|
+
function isInjectedAvailable(opts = {}) {
|
|
98
|
+
const p = getInjectedProvider();
|
|
99
|
+
if (!p) return false;
|
|
100
|
+
if (opts.anyChia) return typeof p.request === "function";
|
|
101
|
+
return !!p.isDIG;
|
|
102
|
+
}
|
|
103
|
+
var INJECTED_TOPIC = "injected";
|
|
104
|
+
var InjectedTransport = class {
|
|
105
|
+
constructor(provider, chain = DEFAULT_CHAIN) {
|
|
106
|
+
this.backend = "injected";
|
|
107
|
+
this.topic = INJECTED_TOPIC;
|
|
108
|
+
this.provider = provider;
|
|
109
|
+
this.chain = chain;
|
|
110
|
+
}
|
|
111
|
+
/** Connect: ask the native wallet to approve this origin. Blocks until approved/rejected. */
|
|
112
|
+
async connect(eager = false) {
|
|
113
|
+
if (typeof this.provider.connect === "function") {
|
|
114
|
+
await this.provider.connect(eager);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// The native wallet implements the full canonical set (it returns Sage-shaped responses), so
|
|
118
|
+
// support is a static allowlist — no per-session negotiation as with WalletConnect.
|
|
119
|
+
supports(method) {
|
|
120
|
+
return WALLET_METHODS.includes(method);
|
|
121
|
+
}
|
|
122
|
+
async request(method, params) {
|
|
123
|
+
if (!this.supports(method)) {
|
|
124
|
+
throw new DigSdkError(
|
|
125
|
+
"METHOD_NOT_SUPPORTED",
|
|
126
|
+
`The DIG Browser wallet does not support "${method}".`,
|
|
127
|
+
{ method }
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return this.provider.request({ method, params });
|
|
131
|
+
}
|
|
132
|
+
async disconnect() {
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// src/provider/wc-retry.ts
|
|
137
|
+
function isTransientPublishError(err) {
|
|
138
|
+
const msg = (err instanceof Error ? err.message : typeof err === "string" ? err : "").toLowerCase();
|
|
139
|
+
if (!msg) return false;
|
|
140
|
+
return msg.includes("publish") || msg.includes("failed or timed out to publish") || msg.includes("websocket connection failed") || msg.includes("connection closed") || msg.includes("socket stalled") || msg.includes("request reset");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/provider/walletconnect.ts
|
|
144
|
+
var WalletConnectTransport = class _WalletConnectTransport {
|
|
145
|
+
constructor(client, session, chain, requestTimeoutMs) {
|
|
146
|
+
this.backend = "walletconnect";
|
|
147
|
+
this.client = client;
|
|
148
|
+
this.topic = session.topic;
|
|
149
|
+
this.chain = chain;
|
|
150
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Initialize SignClient, open a pairing (emitting the URI via `onUri`), and resolve to a
|
|
154
|
+
* connected transport once the user approves in Sage. Requires `@walletconnect/sign-client`.
|
|
155
|
+
*/
|
|
156
|
+
static async connect(options) {
|
|
157
|
+
const chain = options.chain ?? DEFAULT_CHAIN;
|
|
158
|
+
const timeout = options.requestTimeoutMs ?? 6e4;
|
|
159
|
+
const SignClient = await loadSignClient();
|
|
160
|
+
const client = await SignClient.init({
|
|
161
|
+
logger: "error",
|
|
162
|
+
projectId: options.projectId,
|
|
163
|
+
metadata: options.metadata
|
|
164
|
+
});
|
|
165
|
+
const { uri, approval } = await client.connect({
|
|
166
|
+
// optionalNamespaces ONLY — Sage rejects requiredNamespaces.
|
|
167
|
+
optionalNamespaces: {
|
|
168
|
+
chia: { methods: WALLET_METHODS, chains: [chain], events: [] }
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
if (uri && options.onUri) options.onUri(uri);
|
|
172
|
+
const session = await approval();
|
|
173
|
+
return new _WalletConnectTransport(client, session, chain, timeout);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Restore an existing session that grants a sign method (so message signing actually reaches
|
|
177
|
+
* Sage). Returns a transport or null if none qualifies. Requires `@walletconnect/sign-client`.
|
|
178
|
+
*/
|
|
179
|
+
static async restore(options) {
|
|
180
|
+
const chain = options.chain ?? DEFAULT_CHAIN;
|
|
181
|
+
const timeout = options.requestTimeoutMs ?? 6e4;
|
|
182
|
+
const SignClient = await loadSignClient();
|
|
183
|
+
const client = await SignClient.init({
|
|
184
|
+
logger: "error",
|
|
185
|
+
projectId: options.projectId,
|
|
186
|
+
metadata: options.metadata
|
|
187
|
+
});
|
|
188
|
+
const sessions = client.session.getAll();
|
|
189
|
+
for (let i = sessions.length - 1; i >= 0; i--) {
|
|
190
|
+
const s = sessions[i];
|
|
191
|
+
const methods = s.namespaces?.chia?.methods ?? [];
|
|
192
|
+
if (SIGN_METHODS.some((m) => methods.includes(m))) {
|
|
193
|
+
return new _WalletConnectTransport(client, s, chain, timeout);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
sessionMethods() {
|
|
199
|
+
try {
|
|
200
|
+
return this.client.session.get(this.topic)?.namespaces?.chia?.methods ?? [];
|
|
201
|
+
} catch {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// True iff the active session granted `method` (empty list = unknown ⇒ treated as granted).
|
|
206
|
+
supports(method) {
|
|
207
|
+
const m = this.sessionMethods();
|
|
208
|
+
return m.length === 0 || m.includes(method);
|
|
209
|
+
}
|
|
210
|
+
async request(method, params) {
|
|
211
|
+
if (!this.supports(method)) {
|
|
212
|
+
throw new DigSdkError(
|
|
213
|
+
"METHOD_NOT_SUPPORTED",
|
|
214
|
+
`Your wallet session does not grant "${method}". Disconnect and reconnect your wallet to refresh the session (and make sure Sage is up to date).`,
|
|
215
|
+
{ method }
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const MAX_ATTEMPTS = 3;
|
|
219
|
+
let lastErr;
|
|
220
|
+
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
|
221
|
+
try {
|
|
222
|
+
return await this.attempt(method, params);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
lastErr = e;
|
|
225
|
+
if (i < MAX_ATTEMPTS - 1 && isTransientPublishError(e)) {
|
|
226
|
+
await sleep(1200 * (i + 1));
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
throw e;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
throw lastErr;
|
|
233
|
+
}
|
|
234
|
+
attempt(method, params) {
|
|
235
|
+
let t;
|
|
236
|
+
const timeout = new Promise((_, rej) => {
|
|
237
|
+
t = setTimeout(
|
|
238
|
+
() => rej(
|
|
239
|
+
new DigSdkError(
|
|
240
|
+
"WALLET_TIMEOUT",
|
|
241
|
+
"Sage did not respond \u2014 open the Sage app and try again.",
|
|
242
|
+
{ method, timeoutMs: this.requestTimeoutMs }
|
|
243
|
+
)
|
|
244
|
+
),
|
|
245
|
+
this.requestTimeoutMs
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
return Promise.race([
|
|
249
|
+
this.client.request({ topic: this.topic, chainId: this.chain, request: { method, params } }),
|
|
250
|
+
timeout
|
|
251
|
+
]).finally(() => clearTimeout(t));
|
|
252
|
+
}
|
|
253
|
+
async disconnect() {
|
|
254
|
+
try {
|
|
255
|
+
await this.client.disconnect({
|
|
256
|
+
topic: this.topic,
|
|
257
|
+
reason: { code: 6e3, message: "bye" }
|
|
258
|
+
});
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
function sleep(ms) {
|
|
264
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
265
|
+
}
|
|
266
|
+
async function loadSignClient() {
|
|
267
|
+
try {
|
|
268
|
+
const mod = await import('@walletconnect/sign-client');
|
|
269
|
+
const SignClient = mod.default ?? mod;
|
|
270
|
+
if (!SignClient || typeof SignClient.init !== "function") {
|
|
271
|
+
throw new Error("unexpected @walletconnect/sign-client shape");
|
|
272
|
+
}
|
|
273
|
+
return SignClient;
|
|
274
|
+
} catch (e) {
|
|
275
|
+
throw new DigSdkError(
|
|
276
|
+
"WC_DEPENDENCY_MISSING",
|
|
277
|
+
"WalletConnect fallback requires the optional peer dependency '@walletconnect/sign-client'. Install it (npm i @walletconnect/sign-client) to use the WalletConnect\u2192Sage transport.",
|
|
278
|
+
{},
|
|
279
|
+
{ cause: e }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/provider/methods.ts
|
|
285
|
+
function with0x(hex) {
|
|
286
|
+
if (!hex) return hex ?? null;
|
|
287
|
+
return hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
288
|
+
}
|
|
289
|
+
function strip0x(h) {
|
|
290
|
+
return String(h ?? "").replace(/^0x/i, "").toLowerCase();
|
|
291
|
+
}
|
|
292
|
+
async function getAddress(request) {
|
|
293
|
+
const resp = await request("chia_getAddress", {});
|
|
294
|
+
if (typeof resp === "string") return resp;
|
|
295
|
+
const r = resp;
|
|
296
|
+
return r?.address ?? r?.data?.address ?? null;
|
|
297
|
+
}
|
|
298
|
+
async function getPublicKeys(request) {
|
|
299
|
+
const resp = await request("chip0002_getPublicKeys", { limit: 500, offset: 0 });
|
|
300
|
+
if (Array.isArray(resp)) return resp;
|
|
301
|
+
const r = resp;
|
|
302
|
+
return r?.publicKeys ?? r?.public_keys ?? r?.keys ?? [];
|
|
303
|
+
}
|
|
304
|
+
function normalizeSig(resp) {
|
|
305
|
+
const r = resp;
|
|
306
|
+
const publicKey = typeof r === "object" && r ? r.publicKey ?? r.public_key ?? r.pubkey ?? null : null;
|
|
307
|
+
const signature = typeof r === "string" ? r : r ? r.signature ?? r.aggregatedSignature ?? r.aggregated_signature ?? null : null;
|
|
308
|
+
return { publicKey: with0x(publicKey), signature };
|
|
309
|
+
}
|
|
310
|
+
async function signMessage(request, supports, message, address) {
|
|
311
|
+
if (supports("chia_signMessageByAddress")) {
|
|
312
|
+
return normalizeSig(await request("chia_signMessageByAddress", { message, address }));
|
|
313
|
+
}
|
|
314
|
+
const keys = await getPublicKeys(request);
|
|
315
|
+
const publicKey = keys[0];
|
|
316
|
+
if (!publicKey)
|
|
317
|
+
throw new DigSdkError("WALLET_NO_KEYS", "Wallet returned no keys to sign with.");
|
|
318
|
+
const sig = normalizeSig(await request("chip0002_signMessage", { message, publicKey }));
|
|
319
|
+
return { publicKey: sig.publicKey ?? with0x(publicKey), signature: sig.signature };
|
|
320
|
+
}
|
|
321
|
+
async function signCoinSpends(request, coinSpends) {
|
|
322
|
+
const resp = await request("chip0002_signCoinSpends", { coinSpends, partialSign: true });
|
|
323
|
+
if (typeof resp === "string") return resp;
|
|
324
|
+
const r = resp;
|
|
325
|
+
return r?.signature ?? r?.aggregatedSignature ?? r?.aggregated_signature ?? "";
|
|
326
|
+
}
|
|
327
|
+
async function takeOffer(request, supports, offer, fee = 0) {
|
|
328
|
+
if (!supports("chia_takeOffer")) {
|
|
329
|
+
throw new DigSdkError(
|
|
330
|
+
"METHOD_NOT_SUPPORTED",
|
|
331
|
+
"Your wallet session does not support taking offers. Reconnect your wallet.",
|
|
332
|
+
{ method: "chia_takeOffer" }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
return request("chia_takeOffer", { offer, fee });
|
|
336
|
+
}
|
|
337
|
+
function balanceFrom(resp) {
|
|
338
|
+
const raw = resp == null ? null : typeof resp === "object" ? resp.confirmed ?? resp.spendable ?? resp.confirmedWalletBalance ?? resp.confirmed_wallet_balance ?? resp.balance ?? resp.data?.confirmed ?? null : resp;
|
|
339
|
+
if (raw == null) return null;
|
|
340
|
+
try {
|
|
341
|
+
return BigInt(raw).toString();
|
|
342
|
+
} catch {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async function getXchBalance(request) {
|
|
347
|
+
return balanceFrom(await request("chip0002_getAssetBalance", { type: null, assetId: null }));
|
|
348
|
+
}
|
|
349
|
+
async function getCatBalance(request, assetIdHex) {
|
|
350
|
+
return balanceFrom(
|
|
351
|
+
await request("chip0002_getAssetBalance", { type: "cat", assetId: strip0x(assetIdHex) })
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
async function getXchCoins(request, limit = 100) {
|
|
355
|
+
const resp = await request("chip0002_getAssetCoins", {
|
|
356
|
+
type: null,
|
|
357
|
+
assetId: null,
|
|
358
|
+
includedLocked: false,
|
|
359
|
+
offset: 0,
|
|
360
|
+
limit
|
|
361
|
+
});
|
|
362
|
+
return Array.isArray(resp) ? resp : resp?.coins ?? [];
|
|
363
|
+
}
|
|
364
|
+
async function getCatCoins(request, assetIdHex, limit = 200) {
|
|
365
|
+
const resp = await request("chip0002_getAssetCoins", {
|
|
366
|
+
type: "cat",
|
|
367
|
+
assetId: strip0x(assetIdHex),
|
|
368
|
+
includedLocked: false,
|
|
369
|
+
offset: 0,
|
|
370
|
+
limit
|
|
371
|
+
});
|
|
372
|
+
return Array.isArray(resp) ? resp : resp?.coins ?? [];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/provider/chia-provider.ts
|
|
376
|
+
var ChiaProvider = class _ChiaProvider {
|
|
377
|
+
constructor(transport) {
|
|
378
|
+
this.transport = transport;
|
|
379
|
+
}
|
|
380
|
+
/** Which transport is backing this provider. */
|
|
381
|
+
get backend() {
|
|
382
|
+
return this.transport.backend;
|
|
383
|
+
}
|
|
384
|
+
/** The connected session descriptor. */
|
|
385
|
+
get session() {
|
|
386
|
+
return {
|
|
387
|
+
backend: this.transport.backend,
|
|
388
|
+
chain: this.transport.chain,
|
|
389
|
+
topic: this.transport.topic,
|
|
390
|
+
address: this.cachedAddress ?? null
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
/** True iff a method is granted by the active session/transport. */
|
|
394
|
+
supports(method) {
|
|
395
|
+
return this.transport.supports(method);
|
|
396
|
+
}
|
|
397
|
+
/** Escape hatch: issue a raw CHIP-0002 request through the active transport. */
|
|
398
|
+
request(method, params = {}) {
|
|
399
|
+
return this.transport.request(method, params);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Connect a wallet using the selection policy. With `mode: "auto"` (default) it prefers an
|
|
403
|
+
* injected DIG wallet and falls back to WalletConnect.
|
|
404
|
+
*/
|
|
405
|
+
static async connect(options = {}) {
|
|
406
|
+
const mode = options.mode ?? "auto";
|
|
407
|
+
const chain = options.chain ?? DEFAULT_CHAIN;
|
|
408
|
+
const tryInjected = async () => {
|
|
409
|
+
if (!isInjectedAvailable({ anyChia: options.acceptAnyInjected })) return null;
|
|
410
|
+
const provider = getInjectedProvider();
|
|
411
|
+
const transport = new InjectedTransport(provider, chain);
|
|
412
|
+
await transport.connect();
|
|
413
|
+
return new _ChiaProvider(transport);
|
|
414
|
+
};
|
|
415
|
+
const tryWalletConnect = async () => {
|
|
416
|
+
if (!options.walletConnect) {
|
|
417
|
+
throw new DigSdkError(
|
|
418
|
+
"WC_OPTIONS_REQUIRED",
|
|
419
|
+
"WalletConnect options are required to connect via WalletConnect (pass { walletConnect: { projectId, metadata, onUri } }).",
|
|
420
|
+
{ mode }
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
const transport = await WalletConnectTransport.connect({
|
|
424
|
+
...options.walletConnect,
|
|
425
|
+
chain
|
|
426
|
+
});
|
|
427
|
+
return new _ChiaProvider(transport);
|
|
428
|
+
};
|
|
429
|
+
if (mode === "injected") {
|
|
430
|
+
const injected = await tryInjected();
|
|
431
|
+
if (!injected) {
|
|
432
|
+
throw new DigSdkError(
|
|
433
|
+
"NO_INJECTED_WALLET",
|
|
434
|
+
"No injected DIG wallet found. Open this page in the DIG Browser, or use mode 'auto'.",
|
|
435
|
+
{ mode, acceptAnyInjected: !!options.acceptAnyInjected }
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
return injected;
|
|
439
|
+
}
|
|
440
|
+
if (mode === "walletconnect") return tryWalletConnect();
|
|
441
|
+
return await tryInjected() ?? await tryWalletConnect();
|
|
442
|
+
}
|
|
443
|
+
/** Wrap an already-constructed transport (advanced / restored sessions). */
|
|
444
|
+
static fromTransport(transport) {
|
|
445
|
+
return new _ChiaProvider(transport);
|
|
446
|
+
}
|
|
447
|
+
// ---- normalized CHIP-0002 surface -------------------------------------------------------------
|
|
448
|
+
/** The wallet's receive address (cached after first read). */
|
|
449
|
+
async getAddress() {
|
|
450
|
+
if (this.cachedAddress === void 0) {
|
|
451
|
+
this.cachedAddress = await getAddress((m, p) => this.transport.request(m, p));
|
|
452
|
+
}
|
|
453
|
+
return this.cachedAddress;
|
|
454
|
+
}
|
|
455
|
+
/** The wallet's (synthetic) public keys. */
|
|
456
|
+
getPublicKeys() {
|
|
457
|
+
return getPublicKeys((m, p) => this.transport.request(m, p));
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Sign a UTF-8 message with the wallet BLS key. `address` defaults to the wallet's own address.
|
|
461
|
+
* Returns `{ publicKey, signature }`.
|
|
462
|
+
*/
|
|
463
|
+
async signMessage(message, address) {
|
|
464
|
+
const addr = address ?? await this.getAddress() ?? "";
|
|
465
|
+
return signMessage(
|
|
466
|
+
(m, p) => this.transport.request(m, p),
|
|
467
|
+
(m) => this.transport.supports(m),
|
|
468
|
+
message,
|
|
469
|
+
addr
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
/** Sign raw CHIP-0035 coin spends (partialSign). Returns the aggregated signature hex. */
|
|
473
|
+
signCoinSpends(coinSpends) {
|
|
474
|
+
return signCoinSpends((m, p) => this.transport.request(m, p), coinSpends);
|
|
475
|
+
}
|
|
476
|
+
/** Accept a Chia offer string (e.g. an NFT offer). */
|
|
477
|
+
takeOffer(offer, fee = 0) {
|
|
478
|
+
return takeOffer(
|
|
479
|
+
(m, p) => this.transport.request(m, p),
|
|
480
|
+
(m) => this.transport.supports(m),
|
|
481
|
+
offer,
|
|
482
|
+
fee
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
/** Spendable XCH balance (mojos, string) or null. */
|
|
486
|
+
getXchBalance() {
|
|
487
|
+
return getXchBalance((m, p) => this.transport.request(m, p));
|
|
488
|
+
}
|
|
489
|
+
/** Spendable balance (base units, string) for a CAT `assetIdHex` (the tail hash), or null. */
|
|
490
|
+
getCatBalance(assetIdHex) {
|
|
491
|
+
return getCatBalance((m, p) => this.transport.request(m, p), assetIdHex);
|
|
492
|
+
}
|
|
493
|
+
/** Unspent XCH coins for funding a spend. */
|
|
494
|
+
getXchCoins(limit) {
|
|
495
|
+
return getXchCoins((m, p) => this.transport.request(m, p), limit);
|
|
496
|
+
}
|
|
497
|
+
/** Unspent CAT coins for `assetIdHex`. */
|
|
498
|
+
getCatCoins(assetIdHex, limit) {
|
|
499
|
+
return getCatCoins((m, p) => this.transport.request(m, p), assetIdHex, limit);
|
|
500
|
+
}
|
|
501
|
+
/** Disconnect the wallet (best-effort). */
|
|
502
|
+
disconnect() {
|
|
503
|
+
return this.transport.disconnect();
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
function connectWallet(options) {
|
|
507
|
+
return ChiaProvider.connect(options);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/paywall.ts
|
|
511
|
+
function strip0x2(hex) {
|
|
512
|
+
return hex.replace(/^0x/i, "").toLowerCase();
|
|
513
|
+
}
|
|
514
|
+
function hexToBytes(hex) {
|
|
515
|
+
const h = strip0x2(hex);
|
|
516
|
+
if (h.length % 2 !== 0 || /[^0-9a-f]/.test(h)) {
|
|
517
|
+
throw new DigSdkError("INVALID_ARGUMENT", `invalid hex string: ${hex}`, { value: hex });
|
|
518
|
+
}
|
|
519
|
+
const out = new Uint8Array(h.length / 2);
|
|
520
|
+
for (let i = 0; i < out.length; i++) out[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
|
|
521
|
+
return out;
|
|
522
|
+
}
|
|
523
|
+
function bytesToHex(bytes) {
|
|
524
|
+
let s = "";
|
|
525
|
+
for (const b of bytes) s += b.toString(16).padStart(2, "0");
|
|
526
|
+
return s;
|
|
527
|
+
}
|
|
528
|
+
async function randomNonce() {
|
|
529
|
+
const out = new Uint8Array(32);
|
|
530
|
+
const webcrypto = globalThis.crypto;
|
|
531
|
+
if (webcrypto?.getRandomValues) {
|
|
532
|
+
webcrypto.getRandomValues(out);
|
|
533
|
+
return out;
|
|
534
|
+
}
|
|
535
|
+
const nodeCrypto = await import('crypto');
|
|
536
|
+
if (!nodeCrypto.webcrypto?.getRandomValues) {
|
|
537
|
+
throw new DigSdkError(
|
|
538
|
+
"NO_SECURE_RANDOM",
|
|
539
|
+
"No secure random source available to generate a payment nonce."
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
nodeCrypto.webcrypto.getRandomValues(out);
|
|
543
|
+
return out;
|
|
544
|
+
}
|
|
545
|
+
var Paywall = class {
|
|
546
|
+
constructor(provider, options = {}) {
|
|
547
|
+
this.provider = provider;
|
|
548
|
+
this.injectedSpends = options.spends;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Resolve the canonical monetization spends (injected, or lazily imported + `init()`ed). Memoized.
|
|
552
|
+
* This is the ONLY source of coin-spend construction in the Paywall — there is no fallback that
|
|
553
|
+
* hand-rolls a spend.
|
|
554
|
+
*/
|
|
555
|
+
spends() {
|
|
556
|
+
if (this.injectedSpends) {
|
|
557
|
+
if (typeof this.injectedSpends.init === "function") this.injectedSpends.init();
|
|
558
|
+
return Promise.resolve(this.injectedSpends);
|
|
559
|
+
}
|
|
560
|
+
if (!this.spendsReady) {
|
|
561
|
+
this.spendsReady = (async () => {
|
|
562
|
+
const mod = await import(
|
|
563
|
+
/* @vite-ignore */
|
|
564
|
+
'@dignetwork/chip35-dl-coin-wasm'
|
|
565
|
+
);
|
|
566
|
+
if (typeof mod.init === "function") mod.init();
|
|
567
|
+
return mod;
|
|
568
|
+
})().catch((e) => {
|
|
569
|
+
this.spendsReady = void 0;
|
|
570
|
+
throw e;
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
return this.spendsReady;
|
|
574
|
+
}
|
|
575
|
+
/** The wallet's first synthetic public key, as bytes (the buyer key the spends are built against). */
|
|
576
|
+
async buyerKey() {
|
|
577
|
+
const keys = await this.provider.getPublicKeys();
|
|
578
|
+
const key = keys?.[0];
|
|
579
|
+
if (!key)
|
|
580
|
+
throw new DigSdkError(
|
|
581
|
+
"WALLET_NO_KEYS",
|
|
582
|
+
"Wallet returned no public keys to build the payment against."
|
|
583
|
+
);
|
|
584
|
+
return hexToBytes(key);
|
|
585
|
+
}
|
|
586
|
+
/** Resolve the 32-byte unlock nonce: explicit hex, else derived from `memo`, else random. */
|
|
587
|
+
async resolveNonce(spends, args) {
|
|
588
|
+
if (args.nonce) return hexToBytes(args.nonce);
|
|
589
|
+
if (args.memo) {
|
|
590
|
+
if (typeof spends.paymentNonce !== "function") {
|
|
591
|
+
throw new DigSdkError(
|
|
592
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
593
|
+
"Cannot derive a nonce from `memo`: the chip35 wasm `paymentNonce` is unavailable.",
|
|
594
|
+
{ builder: "paymentNonce" }
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
return spends.paymentNonce(new TextEncoder().encode(args.memo));
|
|
598
|
+
}
|
|
599
|
+
return randomNonce();
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Charge the buyer (the connected wallet) `amount` to pay the dapp `owner`, then push the
|
|
603
|
+
* wasm-built coin spends to the wallet for signing. Returns the wallet signature + the receipt.
|
|
604
|
+
* Builds via the canonical wasm `buildPayment` (XCH) or `buildCatPayment` (CAT) — never hand-rolled.
|
|
605
|
+
*/
|
|
606
|
+
async requestPayment(args) {
|
|
607
|
+
const spends = await this.spends();
|
|
608
|
+
const ownerPh = hexToBytes(args.owner);
|
|
609
|
+
const amount = BigInt(args.amount);
|
|
610
|
+
const nonce = await this.resolveNonce(spends, args);
|
|
611
|
+
const buyerKey = await this.buyerKey();
|
|
612
|
+
let built;
|
|
613
|
+
if (args.assetId) {
|
|
614
|
+
if (typeof spends.buildCatPayment !== "function") {
|
|
615
|
+
throw new DigSdkError(
|
|
616
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
617
|
+
"chip35 wasm `buildCatPayment` is unavailable \u2014 cannot build a CAT payment (the Paywall never hand-rolls spends).",
|
|
618
|
+
{ builder: "buildCatPayment" }
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
const cats = await this.provider.getCatCoins(strip0x2(args.assetId), args.coinLimit);
|
|
622
|
+
built = spends.buildCatPayment(buyerKey, cats, ownerPh, amount, nonce);
|
|
623
|
+
} else {
|
|
624
|
+
if (typeof spends.buildPayment !== "function") {
|
|
625
|
+
throw new DigSdkError(
|
|
626
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
627
|
+
"chip35 wasm `buildPayment` is unavailable \u2014 cannot build an XCH payment (the Paywall never hand-rolls spends).",
|
|
628
|
+
{ builder: "buildPayment" }
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
const coins = await this.provider.getXchCoins(args.coinLimit);
|
|
632
|
+
built = spends.buildPayment(buyerKey, coins, ownerPh, amount, nonce, BigInt(args.fee ?? 0));
|
|
633
|
+
}
|
|
634
|
+
const signature = await this.provider.signCoinSpends(built.coinSpends);
|
|
635
|
+
return {
|
|
636
|
+
signature,
|
|
637
|
+
receipt: built.receipt,
|
|
638
|
+
coinSpends: built.coinSpends,
|
|
639
|
+
nonce: bytesToHex(nonce)
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Verify an observed on-chain payment unlocks the paywall (pay-to-unlock). Delegates to the wasm
|
|
644
|
+
* `verifyPaymentReceipt`; returns its `{ ok, error? }` verdict. `ok:true` grants access.
|
|
645
|
+
*/
|
|
646
|
+
async verifyReceipt(args) {
|
|
647
|
+
const spends = await this.spends();
|
|
648
|
+
if (typeof spends.verifyPaymentReceipt !== "function") {
|
|
649
|
+
throw new DigSdkError(
|
|
650
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
651
|
+
"chip35 wasm `verifyPaymentReceipt` is unavailable.",
|
|
652
|
+
{ builder: "verifyPaymentReceipt" }
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
const asset = args.asset ?? { xch: true };
|
|
656
|
+
const requiredAsset = "assetId" in asset && asset.assetId ? { assetId: hexToBytes(asset.assetId) } : { xch: true };
|
|
657
|
+
const requireNonce = args.nonce ? hexToBytes(args.nonce) : null;
|
|
658
|
+
return spends.verifyPaymentReceipt(
|
|
659
|
+
args.observed,
|
|
660
|
+
hexToBytes(args.owner),
|
|
661
|
+
BigInt(args.minAmount),
|
|
662
|
+
requiredAsset,
|
|
663
|
+
requireNonce
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Prove the `owner` holds access: gate on a specific NFT (`nft` launcher id) via the wasm
|
|
668
|
+
* `proveNftOwnership`, or on collection/creator membership (`collection` DID) via
|
|
669
|
+
* `proveCollectionMembership`. Returns `{ ok, proof?, error? }`. The caller still confirms the
|
|
670
|
+
* proof's coin is unspent on-chain for liveness.
|
|
671
|
+
*/
|
|
672
|
+
async proveAccess(args) {
|
|
673
|
+
if (args.nft && args.collection) {
|
|
674
|
+
throw new DigSdkError(
|
|
675
|
+
"INVALID_ARGUMENT",
|
|
676
|
+
"proveAccess: pass either `nft` or `collection`, not both.",
|
|
677
|
+
{ value: "nft+collection" }
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
const spends = await this.spends();
|
|
681
|
+
const owner = hexToBytes(args.owner);
|
|
682
|
+
if (args.collection) {
|
|
683
|
+
if (typeof spends.proveCollectionMembership !== "function") {
|
|
684
|
+
throw new DigSdkError(
|
|
685
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
686
|
+
"chip35 wasm `proveCollectionMembership` is unavailable.",
|
|
687
|
+
{ builder: "proveCollectionMembership" }
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
return spends.proveCollectionMembership(args.parentSpend, owner, hexToBytes(args.collection));
|
|
691
|
+
}
|
|
692
|
+
if (typeof spends.proveNftOwnership !== "function") {
|
|
693
|
+
throw new DigSdkError(
|
|
694
|
+
"SPEND_BUILDER_UNAVAILABLE",
|
|
695
|
+
"chip35 wasm `proveNftOwnership` is unavailable.",
|
|
696
|
+
{ builder: "proveNftOwnership" }
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
const requiredNft = args.nft ? hexToBytes(args.nft) : null;
|
|
700
|
+
return spends.proveNftOwnership(args.parentSpend, owner, requiredNft);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
// src/loader.ts
|
|
705
|
+
var DIG_CLIENT_WASM_SHA256 = "ff486be806f908a2a90780e499a04dbd34e10e3b97be0470cb9ee841a1e49e77";
|
|
706
|
+
var _config = {};
|
|
707
|
+
var _ready = null;
|
|
708
|
+
function configureWasm(config) {
|
|
709
|
+
_config = { ...config };
|
|
710
|
+
_ready = null;
|
|
711
|
+
}
|
|
712
|
+
var isNode = typeof process !== "undefined" && !!process.versions?.node;
|
|
713
|
+
async function sha256Hex(bytes) {
|
|
714
|
+
if (isNode) {
|
|
715
|
+
const { createHash } = await import('crypto');
|
|
716
|
+
const view = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : new Uint8Array(
|
|
717
|
+
bytes.buffer,
|
|
718
|
+
bytes.byteOffset,
|
|
719
|
+
bytes.byteLength
|
|
720
|
+
);
|
|
721
|
+
return createHash("sha256").update(view).digest("hex");
|
|
722
|
+
}
|
|
723
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
724
|
+
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
725
|
+
}
|
|
726
|
+
function assertIntegrity(hex) {
|
|
727
|
+
if (_config.skipIntegrity) return;
|
|
728
|
+
if (hex !== DIG_CLIENT_WASM_SHA256) {
|
|
729
|
+
throw new DigSdkError(
|
|
730
|
+
"WASM_INTEGRITY",
|
|
731
|
+
`dig-client wasm integrity check failed \u2014 refusing to run unverified crypto (expected ${DIG_CLIENT_WASM_SHA256}, got ${hex}).`,
|
|
732
|
+
{ expected: DIG_CLIENT_WASM_SHA256, actual: hex }
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function loadNode() {
|
|
737
|
+
const { readFile } = await import('fs/promises');
|
|
738
|
+
const { fileURLToPath, pathToFileURL } = await import('url');
|
|
739
|
+
const path = await import('path');
|
|
740
|
+
const here = path.dirname(fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
741
|
+
const vendorDir = path.resolve(here, "..", "vendor");
|
|
742
|
+
const wasmPath = path.join(vendorDir, "dig_client_bg.wasm");
|
|
743
|
+
const gluePath = path.join(vendorDir, "dig_client.mjs");
|
|
744
|
+
const buf = await readFile(wasmPath);
|
|
745
|
+
const bytes = new Uint8Array(buf.byteLength);
|
|
746
|
+
bytes.set(buf);
|
|
747
|
+
return { glueHref: pathToFileURL(gluePath).href, bytes };
|
|
748
|
+
}
|
|
749
|
+
async function loadBrowser() {
|
|
750
|
+
const glueHref = _config.glueUrl ?? new URL("../vendor/dig_client.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))).href;
|
|
751
|
+
let bytes;
|
|
752
|
+
if (_config.wasmBytes) {
|
|
753
|
+
bytes = _config.wasmBytes;
|
|
754
|
+
} else {
|
|
755
|
+
const wasmUrl = _config.wasmUrl ?? new URL("../vendor/dig_client_bg.wasm", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))).href;
|
|
756
|
+
const res = await fetch(wasmUrl);
|
|
757
|
+
if (!res.ok)
|
|
758
|
+
throw new DigSdkError("WASM_LOAD_FAILED", `dig-client wasm fetch failed (${res.status})`, {
|
|
759
|
+
httpStatus: res.status,
|
|
760
|
+
wasmUrl
|
|
761
|
+
});
|
|
762
|
+
bytes = await res.arrayBuffer();
|
|
763
|
+
}
|
|
764
|
+
return { glueHref, bytes };
|
|
765
|
+
}
|
|
766
|
+
function loadDigClientWasm() {
|
|
767
|
+
if (_ready) return _ready;
|
|
768
|
+
_ready = (async () => {
|
|
769
|
+
const { glueHref, bytes } = isNode ? await loadNode() : await loadBrowser();
|
|
770
|
+
assertIntegrity(await sha256Hex(bytes));
|
|
771
|
+
const mod = await import(
|
|
772
|
+
/* @vite-ignore */
|
|
773
|
+
glueHref
|
|
774
|
+
);
|
|
775
|
+
await mod.default({ module_or_path: bytes });
|
|
776
|
+
return mod;
|
|
777
|
+
})().catch((e) => {
|
|
778
|
+
_ready = null;
|
|
779
|
+
throw e;
|
|
780
|
+
});
|
|
781
|
+
return _ready;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// src/urn.ts
|
|
785
|
+
var URN_RE = /^urn:dig:chia:([0-9a-fA-F]{64})(?::([0-9a-fA-F]{64}))?\/(.+?)(?:\?salt=([0-9a-fA-F]+))?$/;
|
|
786
|
+
function parseUrn(raw) {
|
|
787
|
+
const s = String(raw ?? "").trim();
|
|
788
|
+
const m = URN_RE.exec(s);
|
|
789
|
+
if (!m) {
|
|
790
|
+
throw new DigSdkError(
|
|
791
|
+
"INVALID_ARGUMENT",
|
|
792
|
+
"Not a valid dig URN (expected urn:dig:chia:<store-id>[:<root>]/<path>[?salt=<hex>]).",
|
|
793
|
+
{ value: s, expected: "urn:dig:chia:<store-id>[:<root>]/<path>[?salt=<hex>]" }
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
return {
|
|
797
|
+
storeId: m[1].toLowerCase(),
|
|
798
|
+
root: m[2] ? m[2].toLowerCase() : null,
|
|
799
|
+
resourceKey: m[3],
|
|
800
|
+
salt: m[4] ? m[4].toLowerCase() : null
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
function isUrn(raw) {
|
|
804
|
+
try {
|
|
805
|
+
parseUrn(raw);
|
|
806
|
+
return true;
|
|
807
|
+
} catch {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
function reconstructUrn(storeId, resourceKey) {
|
|
812
|
+
const key = resourceKey && resourceKey.length > 0 ? resourceKey : "index.html";
|
|
813
|
+
return `urn:dig:chia:${storeId.toLowerCase()}/${key}`;
|
|
814
|
+
}
|
|
815
|
+
function reconstructUrnWithRoot(storeId, root, resourceKey) {
|
|
816
|
+
const key = resourceKey && resourceKey.length > 0 ? resourceKey : "index.html";
|
|
817
|
+
return `urn:dig:chia:${storeId.toLowerCase()}:${root.toLowerCase()}/${key}`;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/dig-client.ts
|
|
821
|
+
var DEFAULT_RPC = "https://rpc.dig.net";
|
|
822
|
+
var RPC_CHUNK_BYTES = 3 * 1024 * 1024;
|
|
823
|
+
function b64ToBytes(b64) {
|
|
824
|
+
if (typeof atob === "function") {
|
|
825
|
+
const bin = atob(b64);
|
|
826
|
+
const out = new Uint8Array(bin.length);
|
|
827
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
828
|
+
return out;
|
|
829
|
+
}
|
|
830
|
+
return new Uint8Array(globalThis.Buffer.from(b64, "base64"));
|
|
831
|
+
}
|
|
832
|
+
var DigClient = class {
|
|
833
|
+
constructor(options = {}) {
|
|
834
|
+
this.rpc = options.rpc ?? DEFAULT_RPC;
|
|
835
|
+
this.fetchImpl = options.fetch ?? (typeof fetch === "function" ? fetch.bind(globalThis) : undefinedFetch());
|
|
836
|
+
}
|
|
837
|
+
/** Load (and SRI-verify) the read-crypto wasm. Exposed for callers that want the raw functions. */
|
|
838
|
+
async wasm() {
|
|
839
|
+
return loadDigClientWasm();
|
|
840
|
+
}
|
|
841
|
+
/** `retrieval_key = SHA-256(canonical rootless URN)`, lowercase hex. */
|
|
842
|
+
async retrievalKey(storeId, resourceKey) {
|
|
843
|
+
return (await this.wasm()).retrievalKey(storeId, resourceKey);
|
|
844
|
+
}
|
|
845
|
+
/** Derive the per-URN AES-256-GCM-SIV key, lowercase hex. `salt` for a private store. */
|
|
846
|
+
async deriveKey(storeId, resourceKey, salt) {
|
|
847
|
+
return (await this.wasm()).deriveKey(storeId, resourceKey, salt ?? void 0);
|
|
848
|
+
}
|
|
849
|
+
/** Verify served `ciphertext` is included under `root` via the base64 merkle `proof`. */
|
|
850
|
+
async verifyInclusion(ciphertext, proof, root) {
|
|
851
|
+
return (await this.wasm()).verifyInclusion(ciphertext, proof, root);
|
|
852
|
+
}
|
|
853
|
+
/** Reconstruct the canonical rootless URN whose SHA-256 is the retrieval key. */
|
|
854
|
+
async reconstructUrn(storeId, resourceKey) {
|
|
855
|
+
return (await this.wasm()).reconstructUrn(storeId, resourceKey);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Derive, client-side, the two root-independent keys a URN maps to (retrieval + decryption).
|
|
859
|
+
* Nothing is sent to the network — pure local derivation via the wasm.
|
|
860
|
+
*/
|
|
861
|
+
async deriveUrnKeys(input) {
|
|
862
|
+
const parsed = parseUrn(input.urn);
|
|
863
|
+
const wasm = await this.wasm();
|
|
864
|
+
const effSalt = input.salt ?? parsed.salt ?? void 0;
|
|
865
|
+
return {
|
|
866
|
+
storeId: parsed.storeId,
|
|
867
|
+
root: parsed.root,
|
|
868
|
+
resourceKey: parsed.resourceKey,
|
|
869
|
+
salt: effSalt ?? null,
|
|
870
|
+
retrievalKey: wasm.retrievalKey(parsed.storeId, parsed.resourceKey),
|
|
871
|
+
decryptionKey: wasm.deriveKey(parsed.storeId, parsed.resourceKey, effSalt)
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Fetch + verify + decrypt one resource by URN. `root` is the on-chain generation root to verify
|
|
876
|
+
* against (resolved by the caller from the chain); when omitted, the root embedded in the URN is
|
|
877
|
+
* used. Returns the bytes plus advisory `verified`/`decrypted` flags. NEVER throws "not found"
|
|
878
|
+
* (presence is unknowable) — it throws only on a transport failure.
|
|
879
|
+
*/
|
|
880
|
+
async read(input, opts = {}) {
|
|
881
|
+
const parsed = parseUrn(input.urn);
|
|
882
|
+
const effSalt = input.salt ?? parsed.salt ?? null;
|
|
883
|
+
const effRoot = input.root ?? parsed.root ?? null;
|
|
884
|
+
if (!effRoot) {
|
|
885
|
+
throw new DigSdkError(
|
|
886
|
+
"ROOT_REQUIRED",
|
|
887
|
+
"a confirmed on-chain root is required to read content (pass { root } or use a root-pinned URN)",
|
|
888
|
+
{ urn: input.urn }
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
return this.readResource(
|
|
892
|
+
{ storeId: parsed.storeId, resourceKey: parsed.resourceKey, root: effRoot, salt: effSalt },
|
|
893
|
+
opts
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
/** As `read`, but decoding the plaintext to a UTF-8 string when it decrypts (else throws). */
|
|
897
|
+
async readText(input, opts = {}) {
|
|
898
|
+
const r = await this.read(input, opts);
|
|
899
|
+
if (!r.decrypted) {
|
|
900
|
+
throw new DigSdkError(
|
|
901
|
+
"DECRYPT_FAILED",
|
|
902
|
+
"resource did not decrypt under this URN \u2014 wrong store/key/salt, or a decoy response",
|
|
903
|
+
{ urn: input.urn }
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
return new TextDecoder().decode(r.bytes);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Read by explicit (storeId, resourceKey, root, salt) rather than a URN string. The oblivious
|
|
910
|
+
* download primitive the URN read is built on.
|
|
911
|
+
*/
|
|
912
|
+
async readResource(input, opts = {}) {
|
|
913
|
+
const rpc = opts.rpc ?? this.rpc;
|
|
914
|
+
const wasm = await this.wasm();
|
|
915
|
+
const rk = wasm.retrievalKey(input.storeId, input.resourceKey);
|
|
916
|
+
const { ciphertext, proof, chunkLens } = await this.fetchCiphertext(
|
|
917
|
+
input.storeId,
|
|
918
|
+
rk,
|
|
919
|
+
input.root,
|
|
920
|
+
rpc
|
|
921
|
+
);
|
|
922
|
+
let verified = false;
|
|
923
|
+
try {
|
|
924
|
+
verified = !!wasm.verifyInclusion(ciphertext, proof, input.root);
|
|
925
|
+
} catch {
|
|
926
|
+
verified = false;
|
|
927
|
+
}
|
|
928
|
+
const keyHex = wasm.deriveKey(input.storeId, input.resourceKey, input.salt ?? void 0);
|
|
929
|
+
try {
|
|
930
|
+
const bytes = decryptResourceChunks(wasm, keyHex, ciphertext, chunkLens);
|
|
931
|
+
return {
|
|
932
|
+
storeId: input.storeId,
|
|
933
|
+
root: input.root,
|
|
934
|
+
resourceKey: input.resourceKey,
|
|
935
|
+
salt: input.salt ?? null,
|
|
936
|
+
bytes,
|
|
937
|
+
verified,
|
|
938
|
+
decrypted: true
|
|
939
|
+
};
|
|
940
|
+
} catch {
|
|
941
|
+
return {
|
|
942
|
+
storeId: input.storeId,
|
|
943
|
+
root: input.root,
|
|
944
|
+
resourceKey: input.resourceKey,
|
|
945
|
+
salt: input.salt ?? null,
|
|
946
|
+
bytes: ciphertext,
|
|
947
|
+
verified,
|
|
948
|
+
decrypted: false
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Read a collection's public, owner-independent facts (creator DID, item count, uniform royalty)
|
|
954
|
+
* from the dig RPC (`dig.getCollection`). The collection's item set is its NFT launcher ids — the
|
|
955
|
+
* authoritative, owner-independent anchor the mint produced (a DID-attributed NFT is hinted to its
|
|
956
|
+
* OWNER at mint, not to the creator DID, so launcher ids — not the DID — are the read key). Pass
|
|
957
|
+
* the optional `did` to have it echoed back and recorded as the declared creator.
|
|
958
|
+
*
|
|
959
|
+
* No wallet, no read-crypto wasm — a plain JSON-RPC read. Throws a coded {@link DigSdkError} on a
|
|
960
|
+
* transport/RPC failure (never a "not found": an empty/partly-confirmed set just resolves to fewer
|
|
961
|
+
* items).
|
|
962
|
+
*
|
|
963
|
+
* @example
|
|
964
|
+
* const meta = await dig.getCollection({ launcherIds: ["ab…", "cd…"], did: "ef…" });
|
|
965
|
+
* console.log(meta.resolved_count, meta.royalty_basis_points);
|
|
966
|
+
*/
|
|
967
|
+
async getCollection(input, opts = {}) {
|
|
968
|
+
const rpc = opts.rpc ?? this.rpc;
|
|
969
|
+
const params = { launcher_ids: input.launcherIds };
|
|
970
|
+
if (input.did) params.did = input.did;
|
|
971
|
+
const r = await this.rpcCall(rpc, "dig.getCollection", params);
|
|
972
|
+
if (!r)
|
|
973
|
+
throw new DigSdkError(
|
|
974
|
+
"RPC_MALFORMED_RESPONSE",
|
|
975
|
+
"The content network returned no collection facts for this request.",
|
|
976
|
+
{ rpcMethod: "dig.getCollection" }
|
|
977
|
+
);
|
|
978
|
+
return r;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Read a deterministic, paginated page of a collection's items (`dig.listCollectionItems`), each
|
|
982
|
+
* resolved to its CURRENT on-chain state — current owner, royalty, and CHIP-0007 metadata — by the
|
|
983
|
+
* RPC walking the singleton lineage forward to the live tip (so the owner is never the stale
|
|
984
|
+
* mint-time owner). Items come back in the input launcher-id order. `limit` is clamped to the
|
|
985
|
+
* server cap (200); `offset` defaults to 0.
|
|
986
|
+
*
|
|
987
|
+
* Throws a coded {@link DigSdkError} on a transport/RPC failure.
|
|
988
|
+
*
|
|
989
|
+
* @example
|
|
990
|
+
* let page = await dig.listCollectionItems({ launcherIds, limit: 50 });
|
|
991
|
+
* for (const item of page.items) console.log(item.launcher_id, item.owner_puzzle_hash);
|
|
992
|
+
* // page.next_offset is null on the last page.
|
|
993
|
+
*/
|
|
994
|
+
async listCollectionItems(input, opts = {}) {
|
|
995
|
+
const rpc = opts.rpc ?? this.rpc;
|
|
996
|
+
const params = { launcher_ids: input.launcherIds };
|
|
997
|
+
if (input.offset !== void 0) params.offset = input.offset;
|
|
998
|
+
if (input.limit !== void 0) params.limit = input.limit;
|
|
999
|
+
const r = await this.rpcCall(rpc, "dig.listCollectionItems", params);
|
|
1000
|
+
if (!r)
|
|
1001
|
+
throw new DigSdkError(
|
|
1002
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1003
|
+
"The content network returned no collection items for this request.",
|
|
1004
|
+
{ rpcMethod: "dig.listCollectionItems" }
|
|
1005
|
+
);
|
|
1006
|
+
return r;
|
|
1007
|
+
}
|
|
1008
|
+
// Stream the FULL ciphertext for a resource from the RPC by retrieval key, reassembling 3-MiB
|
|
1009
|
+
// chunks. A null result is a TRANSPORT failure, never a presence judgment.
|
|
1010
|
+
async fetchCiphertext(storeId, rk, root, rpc) {
|
|
1011
|
+
let offset = 0;
|
|
1012
|
+
let total = null;
|
|
1013
|
+
let buf = null;
|
|
1014
|
+
let proof = "";
|
|
1015
|
+
let chunkLens = null;
|
|
1016
|
+
for (; ; ) {
|
|
1017
|
+
const r = await this.rpcCall(rpc, "dig.getContent", {
|
|
1018
|
+
store_id: storeId,
|
|
1019
|
+
root,
|
|
1020
|
+
retrieval_key: rk,
|
|
1021
|
+
offset,
|
|
1022
|
+
length: RPC_CHUNK_BYTES
|
|
1023
|
+
});
|
|
1024
|
+
if (!r)
|
|
1025
|
+
throw new DigSdkError(
|
|
1026
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1027
|
+
"The content network returned no data for this request.",
|
|
1028
|
+
{ rpcMethod: "dig.getContent" }
|
|
1029
|
+
);
|
|
1030
|
+
if (total === null) {
|
|
1031
|
+
total = r.total_length >>> 0;
|
|
1032
|
+
buf = new Uint8Array(total);
|
|
1033
|
+
}
|
|
1034
|
+
if (chunkLens === null && Array.isArray(r.chunk_lens)) {
|
|
1035
|
+
chunkLens = r.chunk_lens.map((n) => n >>> 0);
|
|
1036
|
+
}
|
|
1037
|
+
const chunk = b64ToBytes(r.ciphertext ?? "");
|
|
1038
|
+
const at = r.offset >>> 0;
|
|
1039
|
+
buf.set(chunk.subarray(0, Math.max(0, Math.min(chunk.length, total - at))), at);
|
|
1040
|
+
if (r.inclusion_proof) proof = r.inclusion_proof;
|
|
1041
|
+
if (r.complete || r.next_offset == null) break;
|
|
1042
|
+
offset = r.next_offset >>> 0;
|
|
1043
|
+
}
|
|
1044
|
+
return { ciphertext: buf ?? new Uint8Array(0), proof, chunkLens };
|
|
1045
|
+
}
|
|
1046
|
+
// One JSON-RPC 2.0 call. Throws a coded DigSdkError on transport failure (RPC_TRANSPORT) or a
|
|
1047
|
+
// JSON-RPC/HTTP error (RPC_ERROR, carrying rpcMethod/httpStatus/rpcCode context); returns `result`.
|
|
1048
|
+
async rpcCall(rpc, method, params) {
|
|
1049
|
+
let res;
|
|
1050
|
+
try {
|
|
1051
|
+
res = await this.fetchImpl(rpc, {
|
|
1052
|
+
method: "POST",
|
|
1053
|
+
headers: { "content-type": "application/json" },
|
|
1054
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params })
|
|
1055
|
+
});
|
|
1056
|
+
} catch (e) {
|
|
1057
|
+
throw new DigSdkError(
|
|
1058
|
+
"RPC_TRANSPORT",
|
|
1059
|
+
"Could not reach the content network. Check your connection and try again.",
|
|
1060
|
+
{ rpcMethod: method },
|
|
1061
|
+
{ cause: e }
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
if (!res.ok)
|
|
1065
|
+
throw new DigSdkError("RPC_ERROR", `dig RPC ${method} failed (${res.status})`, {
|
|
1066
|
+
rpcMethod: method,
|
|
1067
|
+
httpStatus: res.status
|
|
1068
|
+
});
|
|
1069
|
+
const json = await res.json();
|
|
1070
|
+
if (json && json.error)
|
|
1071
|
+
throw new DigSdkError(
|
|
1072
|
+
"RPC_ERROR",
|
|
1073
|
+
`dig RPC ${method}: ${json.error.message ?? "error"}`,
|
|
1074
|
+
{ rpcMethod: method, rpcCode: json.error.code }
|
|
1075
|
+
);
|
|
1076
|
+
return json ? json.result ?? null : null;
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
function decryptResourceChunks(wasm, keyHex, ciphertext, chunkLens) {
|
|
1080
|
+
const lens = chunkLens && chunkLens.length ? chunkLens : [ciphertext.length];
|
|
1081
|
+
const total = lens.reduce((a, n) => a + n, 0);
|
|
1082
|
+
if (total !== ciphertext.length) {
|
|
1083
|
+
throw new DigSdkError(
|
|
1084
|
+
"RPC_MALFORMED_RESPONSE",
|
|
1085
|
+
"served ciphertext length does not match chunk lengths",
|
|
1086
|
+
{ rpcMethod: "dig.getContent", expected: String(total), actual: String(ciphertext.length) }
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
if (lens.length === 1) return wasm.decryptChunk(keyHex, ciphertext);
|
|
1090
|
+
const parts = [];
|
|
1091
|
+
let p = 0;
|
|
1092
|
+
for (const len of lens) {
|
|
1093
|
+
parts.push(wasm.decryptChunk(keyHex, ciphertext.subarray(p, p + len)));
|
|
1094
|
+
p += len;
|
|
1095
|
+
}
|
|
1096
|
+
const out = new Uint8Array(parts.reduce((a, x) => a + x.length, 0));
|
|
1097
|
+
let q = 0;
|
|
1098
|
+
for (const part of parts) {
|
|
1099
|
+
out.set(part, q);
|
|
1100
|
+
q += part.length;
|
|
1101
|
+
}
|
|
1102
|
+
return out;
|
|
1103
|
+
}
|
|
1104
|
+
function undefinedFetch() {
|
|
1105
|
+
return (() => {
|
|
1106
|
+
throw new DigSdkError(
|
|
1107
|
+
"INVALID_ARGUMENT",
|
|
1108
|
+
"No global fetch available. Pass { fetch } to DigClient (Node < 18 needs a fetch polyfill)."
|
|
1109
|
+
);
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// src/capabilities.ts
|
|
1114
|
+
var SDK_VERSION = "0.2.0" ;
|
|
1115
|
+
var MODULES = Object.freeze([
|
|
1116
|
+
{
|
|
1117
|
+
name: "ChiaProvider",
|
|
1118
|
+
summary: "Unified Chia wallet surface \u2014 prefers the injected DIG Browser wallet, falls back to WalletConnect\u2192Sage.",
|
|
1119
|
+
entry: "@dignetwork/dig-sdk"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
name: "DigClient",
|
|
1123
|
+
summary: "Read-crypto: derive URN keys, verify inclusion against an on-chain root, and decrypt content from the dig RPC.",
|
|
1124
|
+
entry: "@dignetwork/dig-sdk"
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
name: "Paywall",
|
|
1128
|
+
summary: "Pay-to-unlock helper composing ChiaProvider with the canonical chip35 monetization spends (payment / receipt / NFT+collection gating).",
|
|
1129
|
+
entry: "@dignetwork/dig-sdk"
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "spend",
|
|
1133
|
+
summary: "The canonical CHIP-0035 spend builder (@dignetwork/chip35-dl-coin-wasm), re-exported verbatim.",
|
|
1134
|
+
entry: "@dignetwork/dig-sdk/spend"
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
name: "adapters",
|
|
1138
|
+
summary: "Framework deploy glue (Vite + Next): dev window.chia shim and `digstore deploy` runner.",
|
|
1139
|
+
entry: "@dignetwork/dig-sdk/adapters"
|
|
1140
|
+
}
|
|
1141
|
+
]);
|
|
1142
|
+
function capabilities() {
|
|
1143
|
+
return {
|
|
1144
|
+
name: "@dignetwork/dig-sdk",
|
|
1145
|
+
version: SDK_VERSION,
|
|
1146
|
+
modules: MODULES,
|
|
1147
|
+
walletMethods: [...WALLET_METHODS],
|
|
1148
|
+
signMethods: [...SIGN_METHODS],
|
|
1149
|
+
transports: ["injected", "walletconnect"],
|
|
1150
|
+
chains: [DEFAULT_CHAIN],
|
|
1151
|
+
defaultRpc: DEFAULT_RPC,
|
|
1152
|
+
readCryptoWasmSha256: DIG_CLIENT_WASM_SHA256,
|
|
1153
|
+
errorCodes: Object.values(DIG_SDK_ERROR_CODES)
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
var describe = capabilities;
|
|
1157
|
+
|
|
1158
|
+
exports.ChiaProvider = ChiaProvider;
|
|
1159
|
+
exports.DEFAULT_CHAIN = DEFAULT_CHAIN;
|
|
1160
|
+
exports.DEFAULT_RPC = DEFAULT_RPC;
|
|
1161
|
+
exports.DIG_CLIENT_WASM_SHA256 = DIG_CLIENT_WASM_SHA256;
|
|
1162
|
+
exports.DIG_SDK_ERROR_CODES = DIG_SDK_ERROR_CODES;
|
|
1163
|
+
exports.DigClient = DigClient;
|
|
1164
|
+
exports.DigSdkError = DigSdkError;
|
|
1165
|
+
exports.INJECTED_TOPIC = INJECTED_TOPIC;
|
|
1166
|
+
exports.InjectedTransport = InjectedTransport;
|
|
1167
|
+
exports.Paywall = Paywall;
|
|
1168
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
1169
|
+
exports.SIGN_METHODS = SIGN_METHODS;
|
|
1170
|
+
exports.WALLET_METHODS = WALLET_METHODS;
|
|
1171
|
+
exports.WalletConnectTransport = WalletConnectTransport;
|
|
1172
|
+
exports.capabilities = capabilities;
|
|
1173
|
+
exports.configureWasm = configureWasm;
|
|
1174
|
+
exports.connectWallet = connectWallet;
|
|
1175
|
+
exports.describe = describe;
|
|
1176
|
+
exports.getInjectedProvider = getInjectedProvider;
|
|
1177
|
+
exports.isDigSdkError = isDigSdkError;
|
|
1178
|
+
exports.isInjectedAvailable = isInjectedAvailable;
|
|
1179
|
+
exports.isTransientPublishError = isTransientPublishError;
|
|
1180
|
+
exports.isUrn = isUrn;
|
|
1181
|
+
exports.loadDigClientWasm = loadDigClientWasm;
|
|
1182
|
+
exports.parseUrn = parseUrn;
|
|
1183
|
+
exports.reconstructUrn = reconstructUrn;
|
|
1184
|
+
exports.reconstructUrnWithRoot = reconstructUrnWithRoot;
|
|
1185
|
+
//# sourceMappingURL=index.cjs.map
|
|
1186
|
+
//# sourceMappingURL=index.cjs.map
|