@dstorage-tech/dstorage-sdk 0.0.4
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 -0
- package/README.md +530 -0
- package/dist/KeypairEncryptionAdapter-AE75YC4W-AOWNSH2M.mjs +9 -0
- package/dist/KeypairEncryptionAdapter-AE75YC4W-BAVHRNNJ.mjs +1 -0
- package/dist/KeypairEncryptionAdapter-AE75YC4W-BEYO4RUO.mjs +1 -0
- package/dist/KeypairEncryptionAdapter-AE75YC4W-VAOH6AAL.mjs +9 -0
- package/dist/KeypairEncryptionAdapter-XUKCLRFU-6ERIZN2M.mjs +1 -0
- package/dist/KeypairEncryptionAdapter-XUKCLRFU-AYDAZ2TZ.mjs +9 -0
- package/dist/KeypairEncryptionAdapter-XUKCLRFU-ERPYK5S4.mjs +8 -0
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-6DFVUVD6.mjs +1 -0
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-O5AJPX42.mjs +1 -0
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-SI6TBLTQ.mjs +9 -0
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-WEPFOTSJ.mjs +9 -0
- package/dist/MnemonicEncryptionAdapter-RCHUETBP-DZPBGQG6.mjs +8 -0
- package/dist/MnemonicEncryptionAdapter-RCHUETBP-ELAMJMMO.mjs +1 -0
- package/dist/MnemonicEncryptionAdapter-RCHUETBP-M7NHGSHO.mjs +9 -0
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-2YZ64B4A.mjs +1 -0
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-DCEGC2NX.mjs +1 -0
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-QEGGYPFJ.mjs +13 -0
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-ZYUBUYUI.mjs +13 -0
- package/dist/PasswordEncryptionAdapter-ECHND672-3DEFO6FP.mjs +13 -0
- package/dist/PasswordEncryptionAdapter-ECHND672-MUTHAMZY.mjs +12 -0
- package/dist/PasswordEncryptionAdapter-ECHND672-XVBPHPPT.mjs +1 -0
- package/dist/browser.d.mts +2418 -0
- package/dist/browser.mjs +5175 -0
- package/dist/chunk-25I6ZXUC.mjs +9403 -0
- package/dist/chunk-4X5K43JF.mjs +62 -0
- package/dist/chunk-4YMF57VY.mjs +1 -0
- package/dist/chunk-5MZ7FPPY.mjs +1 -0
- package/dist/chunk-5P4EW2YL.mjs +1 -0
- package/dist/chunk-5QOKJEH3.mjs +8 -0
- package/dist/chunk-5RW7SGA7.mjs +1 -0
- package/dist/chunk-62RSKZ6T.mjs +118 -0
- package/dist/chunk-6IAQVMSM.mjs +102 -0
- package/dist/chunk-BBJCQFWP.mjs +275 -0
- package/dist/chunk-BWLEAAFW.mjs +2599 -0
- package/dist/chunk-EYF3263P.mjs +2049 -0
- package/dist/chunk-FJ7LSZOW.mjs +5537 -0
- package/dist/chunk-GUYENY5N.mjs +1 -0
- package/dist/chunk-HDD6SUU4.mjs +276 -0
- package/dist/chunk-JMPRZK5D.mjs +62 -0
- package/dist/chunk-L5QD6GHB.mjs +101 -0
- package/dist/chunk-O37NHERH.mjs +17 -0
- package/dist/chunk-OLGVVM5Y.mjs +102 -0
- package/dist/chunk-PKHRAYFD.mjs +1 -0
- package/dist/chunk-PLAOCKSS.mjs +101 -0
- package/dist/chunk-QKA2DCR6.mjs +118 -0
- package/dist/chunk-RPSRFFXN.mjs +275 -0
- package/dist/chunk-TESUOXRJ.mjs +1 -0
- package/dist/chunk-TMLXCRJU.mjs +1 -0
- package/dist/chunk-TNRKN4LB.mjs +1 -0
- package/dist/chunk-TSZ37JDY.mjs +2596 -0
- package/dist/chunk-U3MS6KMF.mjs +1 -0
- package/dist/chunk-UBALMYIY.mjs +2049 -0
- package/dist/chunk-UDYXMII2.mjs +121 -0
- package/dist/chunk-UJCSKKID.mjs +30 -0
- package/dist/chunk-UOOF4V2Y.mjs +1 -0
- package/dist/chunk-VDZ7F7MP.mjs +1329 -0
- package/dist/chunk-X4LEBNK6.mjs +276 -0
- package/dist/chunk-Z2TH6U4C.mjs +3 -0
- package/dist/chunk-Z6DUAI5B.mjs +121 -0
- package/dist/chunk-ZEPZ4QDD.mjs +1 -0
- package/dist/chunk-ZGUY5EIR.mjs +1 -0
- package/dist/cjs-RMZ3L2IO.mjs +5 -0
- package/dist/contract-api-AO4RGPLT-4HRCMSCE.mjs +279 -0
- package/dist/contract-api-AO4RGPLT-ADH6ZDKC.mjs +279 -0
- package/dist/contract-api-AO4RGPLT-ENC72WCG.mjs +280 -0
- package/dist/contract-api-AO4RGPLT-PAMIPEI3.mjs +1 -0
- package/dist/contract-api-AO4RGPLT-W3RSVP5A.mjs +1 -0
- package/dist/contract-api-AO4RGPLT-WENYDV6I.mjs +1 -0
- package/dist/contract-api-TJ7JPHZA-6FUBJ6DS.mjs +279 -0
- package/dist/contract-api-TJ7JPHZA-ZWP3EH7D.mjs +279 -0
- package/dist/contracts/dataregistry/managed/keys/removeReference.prover +0 -0
- package/dist/contracts/dataregistry/managed/keys/removeReference.verifier +0 -0
- package/dist/contracts/dataregistry/managed/keys/storeReference.prover +0 -0
- package/dist/contracts/dataregistry/managed/keys/storeReference.verifier +0 -0
- package/dist/contracts/dataregistry/managed/keys/updateReference.prover +0 -0
- package/dist/contracts/dataregistry/managed/keys/updateReference.verifier +0 -0
- package/dist/contracts/dataregistry/managed/zkir/removeReference.bzkir +0 -0
- package/dist/contracts/dataregistry/managed/zkir/removeReference.zkir +138 -0
- package/dist/contracts/dataregistry/managed/zkir/storeReference.bzkir +0 -0
- package/dist/contracts/dataregistry/managed/zkir/storeReference.zkir +158 -0
- package/dist/contracts/dataregistry/managed/zkir/updateReference.bzkir +0 -0
- package/dist/contracts/dataregistry/managed/zkir/updateReference.zkir +190 -0
- package/dist/dataregistry-simulator-E6RTGGWT-5YEGBW7P.mjs +108 -0
- package/dist/dataregistry-simulator-E6RTGGWT-DJS4MHBD.mjs +109 -0
- package/dist/dataregistry-simulator-E6RTGGWT-QGCYR3VF.mjs +1 -0
- package/dist/dist-655VYUPJ.mjs +1 -0
- package/dist/dist-INTAFXQ7.mjs +65 -0
- package/dist/dist-MEZZWKP4.mjs +1 -0
- package/dist/dist-MOLWJ4Y7.mjs +64 -0
- package/dist/dist-UD4WRMYJ.mjs +65 -0
- package/dist/errors.d.mts +117 -0
- package/dist/errors.d.ts +117 -0
- package/dist/errors.js +2308 -0
- package/dist/errors.mjs +2278 -0
- package/dist/esm5-AGBDHMNS.mjs +1 -0
- package/dist/esm5-GFOBLUFI.mjs +350 -0
- package/dist/in-memory-private-state-NGOP37V7-DXWZE42Q.mjs +48 -0
- package/dist/in-memory-private-state-NGOP37V7-QXT3RUEH.mjs +49 -0
- package/dist/in-memory-private-state-NGOP37V7-XFJFNFCQ.mjs +1 -0
- package/dist/index.d.mts +2843 -0
- package/dist/index.d.ts +2843 -0
- package/dist/index.js +19639 -0
- package/dist/index.mjs +5177 -0
- package/package.json +87 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,2843 @@
|
|
|
1
|
+
import { PaymentAdapter, PaymentNetworkName, TokenSymbol, NetworkType, PaymentAdapterLogger, PaymentQuote, PaymentInstruction, PaymentReceipt, MidnightWalletProvider, StorageAdapterLogger, StorageAdapter, StorageProviderName, StorageUploadResult, StorageQuote, ChainAdapter, ChainProviderName, ChainAdapterLogger, ChainReference, ChainWriteResult, ChainReferenceUpdate, DataReferenceSummary, ChainQuote, WalletBalances } from './types.js';
|
|
2
|
+
export { ChainAdapter, ChainAdapterLogger, ChainProviderName, ChainQuote, ChainReference, ChainReferenceUpdate, ChainWriteResult, DataReferenceSummary, MidnightWalletProvider, NetworkType, PaymentAdapter, PaymentAdapterLogger, PaymentNetworkName, PaymentQuote, PaymentReceipt, StorageAdapter, StorageAdapterLogger, StorageProviderName, StorageQuote, StorageUploadResult, TOKENS, Token, TokenSymbol, WalletBalances } from './types.js';
|
|
3
|
+
import Arweave from 'arweave';
|
|
4
|
+
import Transaction from 'arweave/node/lib/transaction';
|
|
5
|
+
import { JWKInterface } from 'arweave/node/lib/wallet';
|
|
6
|
+
import { WalletProvider, MidnightProvider } from '@midnight-ntwrk/midnight-js-types';
|
|
7
|
+
import { WalletFacade, FacadeState } from '@midnight-ntwrk/wallet-sdk/facade';
|
|
8
|
+
import { NetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
9
|
+
export { NetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
10
|
+
export { ChainErrorCode, StorageErrorCode } from './errors.js';
|
|
11
|
+
export { MockChainAdapter, MockPaymentAdapter, MockStorageAdapter, MockStorageAdapterConfig } from './adapters/mock.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @dstorage/payment — adapters/arweave.ts
|
|
15
|
+
*
|
|
16
|
+
* Arweave payment adapter.
|
|
17
|
+
*
|
|
18
|
+
* ── Sign-then-post flow ───────────────────────────────────────────────────────
|
|
19
|
+
*
|
|
20
|
+
* On Arweave, data and fee share a single transaction object. The fee is
|
|
21
|
+
* deducted automatically when the transaction is posted — there is no
|
|
22
|
+
* separate payment channel.
|
|
23
|
+
*
|
|
24
|
+
* This adapter implements the two-phase flow supported by MetaTransaction:
|
|
25
|
+
*
|
|
26
|
+
* 1. provideUploadData(data, metadata)
|
|
27
|
+
* Called after encryption. Stores the data + metadata tags so that
|
|
28
|
+
* pay() can build the complete transaction without a separate round-trip.
|
|
29
|
+
*
|
|
30
|
+
* 2. pay(instruction, onStatus) [payment_storage step]
|
|
31
|
+
* Creates the Arweave transaction, attaches tags, and prompts the
|
|
32
|
+
* wallet for approval (ArConnect popup / JWK signing). Stores the
|
|
33
|
+
* signed transaction for the upload step to pick up.
|
|
34
|
+
*
|
|
35
|
+
* 3. ArweaveStorageAdapter.store() [store step]
|
|
36
|
+
* Detects the pre-signed transaction via consumeSignedTx() and simply
|
|
37
|
+
* posts it — no additional signing or wallet interaction needed.
|
|
38
|
+
*
|
|
39
|
+
* If provideUploadData() was not called (e.g. direct use outside MetaTransaction),
|
|
40
|
+
* pay() falls back to the pass-through behaviour and store() performs the full
|
|
41
|
+
* create → sign → post flow as before.
|
|
42
|
+
*
|
|
43
|
+
* Docs: https://docs.arweave.org/developers
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
type ArweaveWallet = JWKInterface | "use_wallet";
|
|
47
|
+
interface ArweavePaymentAdapterConfig {
|
|
48
|
+
/**
|
|
49
|
+
* Arweave gateway.
|
|
50
|
+
* Defaults to mainnet (arweave.net).
|
|
51
|
+
* Use { host: 'arweave.dev', port: 443, protocol: 'https' } for testnet.
|
|
52
|
+
* Use { host: 'localhost', port: 1984, protocol: 'http' } for arlocal.
|
|
53
|
+
*
|
|
54
|
+
* Security: always use `protocol: 'https'` (the default) in production.
|
|
55
|
+
* The SDK relies on standard OS/runtime TLS — no DNS or certificate pinning
|
|
56
|
+
* is applied. Users in adversarial network environments should enforce
|
|
57
|
+
* certificate pinning at the runtime level (e.g. a custom Node.js HTTPS
|
|
58
|
+
* agent or a trusted corporate proxy).
|
|
59
|
+
*/
|
|
60
|
+
gateway?: {
|
|
61
|
+
host: string;
|
|
62
|
+
port: number;
|
|
63
|
+
protocol: "http" | "https";
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* JWK wallet key for Node.js server-side usage.
|
|
67
|
+
* In the browser leave undefined — ArConnect is used automatically.
|
|
68
|
+
*/
|
|
69
|
+
walletKey?: Record<string, string>;
|
|
70
|
+
/**
|
|
71
|
+
* How long in ms before a quote expires.
|
|
72
|
+
* Defaults to 120_000 (2 minutes) — appropriate for Arweave's volatile pricing.
|
|
73
|
+
*/
|
|
74
|
+
quoteValidityMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Optional logger for SDK operational output.
|
|
77
|
+
*/
|
|
78
|
+
logger?: PaymentAdapterLogger;
|
|
79
|
+
}
|
|
80
|
+
/** Internal state stored between provideUploadData() and pay(). */
|
|
81
|
+
interface PendingUpload {
|
|
82
|
+
data: Uint8Array;
|
|
83
|
+
metadata: Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
/** Result stored after pay() signs the transaction, consumed by store(). */
|
|
86
|
+
interface SignedArweaveUpload {
|
|
87
|
+
tx: Transaction;
|
|
88
|
+
/** AR cost string (e.g. "0.000001234") for the upload result. */
|
|
89
|
+
arCost: string;
|
|
90
|
+
}
|
|
91
|
+
declare class ArweavePaymentAdapter implements PaymentAdapter {
|
|
92
|
+
readonly network: PaymentNetworkName;
|
|
93
|
+
readonly token: TokenSymbol;
|
|
94
|
+
readonly type: NetworkType;
|
|
95
|
+
protected arweaveClient: Arweave | null;
|
|
96
|
+
protected readonly gateway: ArweavePaymentAdapterConfig["gateway"];
|
|
97
|
+
private readonly walletKey;
|
|
98
|
+
protected readonly quoteValidityMs: number;
|
|
99
|
+
protected readonly logger: PaymentAdapterLogger | undefined;
|
|
100
|
+
protected pendingUpload: PendingUpload | null;
|
|
101
|
+
protected signedUpload: SignedArweaveUpload | null;
|
|
102
|
+
constructor(config?: ArweavePaymentAdapterConfig);
|
|
103
|
+
protected getClient(): Promise<Arweave>;
|
|
104
|
+
protected resolveWallet(): ArweaveWallet;
|
|
105
|
+
/**
|
|
106
|
+
* Store the encrypted upload payload and metadata tags so that pay() can
|
|
107
|
+
* build and sign the complete Arweave transaction in one step.
|
|
108
|
+
* Called by MetaTransaction after the encrypt step, before pay().
|
|
109
|
+
*/
|
|
110
|
+
provideUploadData(data: Uint8Array, metadata?: Record<string, string>): void;
|
|
111
|
+
/**
|
|
112
|
+
* Query the Arweave fee oracle for the real upload cost.
|
|
113
|
+
*/
|
|
114
|
+
estimateCost(dataSizeBytes: number): Promise<PaymentQuote>;
|
|
115
|
+
/**
|
|
116
|
+
* Sign-then-store flow (when provideUploadData was called):
|
|
117
|
+
* Creates the Arweave transaction with data + tags, prompts the wallet
|
|
118
|
+
* for approval (ArConnect popup or JWK signing), and stores the signed
|
|
119
|
+
* transaction for ArweaveStorageAdapter.store() to post.
|
|
120
|
+
*
|
|
121
|
+
* Pass-through fallback (when provideUploadData was NOT called):
|
|
122
|
+
* Returns a receipt acknowledging that payment is bundled with the upload.
|
|
123
|
+
* ArweaveStorageAdapter.store() performs the full create → sign → post flow.
|
|
124
|
+
*/
|
|
125
|
+
pay(instruction: PaymentInstruction, onStatus?: (message: string) => void): Promise<PaymentReceipt>;
|
|
126
|
+
/**
|
|
127
|
+
* Returns the pre-signed transaction produced by pay(), then clears it.
|
|
128
|
+
* Called by ArweaveStorageAdapter.store() to post the already-signed tx.
|
|
129
|
+
* Returns null if pay() did not sign a transaction (pass-through mode).
|
|
130
|
+
*/
|
|
131
|
+
consumeSignedUpload(): SignedArweaveUpload | null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @dstorage/payment — adapters/managed.ts
|
|
136
|
+
*
|
|
137
|
+
* Managed payment adapter — remote payment via dStorage API services.
|
|
138
|
+
*
|
|
139
|
+
* Routes payment to the correct network-specific flow based on
|
|
140
|
+
* PaymentQuote.network. All networks share the same endpoint:
|
|
141
|
+
* POST {baseUrl}{POST_SIGN_TX_API_PATH}
|
|
142
|
+
* Currently implemented:
|
|
143
|
+
* - "arweave": remote Arweave signing via REST API
|
|
144
|
+
* - "arweave_bundler": remote ANS-104 bundled-upload signing via REST API
|
|
145
|
+
* - "midnight": remote Midnight transaction balancing/signing via REST API
|
|
146
|
+
*
|
|
147
|
+
* ── Arweave flow ──────────────────────────────────────────────────────────────
|
|
148
|
+
*
|
|
149
|
+
* Instead of signing the Arweave transaction locally (ArConnect or JWK),
|
|
150
|
+
* this adapter constructs the Arweave transaction, computes the Merkle tree
|
|
151
|
+
* (data_root) locally, then sends a stripped transaction JSON — containing
|
|
152
|
+
* only metadata, data_root, and data_size but NOT the raw file bytes — to a
|
|
153
|
+
* remote REST API. The server holds a funded Arweave account, signs the
|
|
154
|
+
* stripped transaction, and returns the signature and id. The file content
|
|
155
|
+
* never leaves the client.
|
|
156
|
+
*
|
|
157
|
+
* POST {baseUrl}{POST_SIGN_TX_API_PATH}
|
|
158
|
+
* → { txData: object, network: string, userId: string }
|
|
159
|
+
* txData — Arweave transaction JSON with data stripped (tx.toJSON()
|
|
160
|
+
* after clearing tx.data; data_root + data_size preserved).
|
|
161
|
+
* network — Arweave network identifier (e.g. "arweave", "arlocal").
|
|
162
|
+
* userId — caller identity forwarded to the server.
|
|
163
|
+
* ← { txId: string, signature: string, publicKey: string, txAmount: string, ... }
|
|
164
|
+
* txId — valid 43-char base64url Arweave transaction id.
|
|
165
|
+
* signature — base64url RSA-PSS signature.
|
|
166
|
+
* publicKey — server wallet's RSA modulus n (base64url).
|
|
167
|
+
* The adapter calls tx.setSignature({ id, signature, owner }).
|
|
168
|
+
*
|
|
169
|
+
* ── Integration (Arweave) ─────────────────────────────────────────────────────
|
|
170
|
+
*
|
|
171
|
+
* ManagedPaymentAdapter extends ArweavePaymentAdapter and slots into the
|
|
172
|
+
* same sign-then-post flow used by ArweaveStorageAdapter:
|
|
173
|
+
*
|
|
174
|
+
* MetaTransaction:
|
|
175
|
+
* provideUploadData(data, metadata) ← stores data + tags
|
|
176
|
+
* pay(instruction, onStatus) ← routes by instruction.network, creates tx,
|
|
177
|
+
* sends JSON to server, applies signature
|
|
178
|
+
*
|
|
179
|
+
* ArweaveStorageAdapter.store():
|
|
180
|
+
* consumeSignedUpload() ← picks up the pre-signed tx
|
|
181
|
+
* postWithRetry(arweave, tx) ← broadcasts to Arweave network
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
interface ManagedPaymentAdapterConfig extends Omit<ArweavePaymentAdapterConfig, "walletKey"> {
|
|
185
|
+
/** Which network this adapter is used for */
|
|
186
|
+
network: PaymentNetworkName;
|
|
187
|
+
/** Whether this covers a storage network fee or a chain transaction fee */
|
|
188
|
+
type: NetworkType;
|
|
189
|
+
/**
|
|
190
|
+
* Base URL of the remote signing server (no trailing slash).
|
|
191
|
+
* Example: "https://api.my-server.com"
|
|
192
|
+
*/
|
|
193
|
+
signingServerUrl: string;
|
|
194
|
+
/**
|
|
195
|
+
* Bearer token sent as the `Authorization` header to authenticate with the signing server.
|
|
196
|
+
* Must be a non-empty, non-whitespace string — the constructor throws immediately on
|
|
197
|
+
* an empty value so a misconfigured caller (e.g. unresolved env var) fails fast
|
|
198
|
+
* rather than silently sending unauthenticated requests to the signing service.
|
|
199
|
+
*/
|
|
200
|
+
authToken: string;
|
|
201
|
+
/**
|
|
202
|
+
* Maximum time in milliseconds to wait for the signing server to respond before
|
|
203
|
+
* aborting the request and throwing. Defaults to 30 000 ms (30 s).
|
|
204
|
+
* Pass `0` to disable the timeout entirely (not recommended for production).
|
|
205
|
+
*/
|
|
206
|
+
requestTimeoutMs?: number;
|
|
207
|
+
}
|
|
208
|
+
declare class ManagedPaymentAdapter extends ArweavePaymentAdapter {
|
|
209
|
+
readonly network: PaymentNetworkName;
|
|
210
|
+
readonly type: NetworkType;
|
|
211
|
+
private readonly signingServerUrl;
|
|
212
|
+
private readonly authToken;
|
|
213
|
+
private readonly requestTimeoutMs;
|
|
214
|
+
private readonly ownerPublicKey;
|
|
215
|
+
/**
|
|
216
|
+
* Strip a RSA-4096 modulus suffix from a compound auth token
|
|
217
|
+
* (<credential>.<base64url_683_chars>), returning only the credential.
|
|
218
|
+
* A plain token (no '.' or wrong suffix length) is returned unchanged.
|
|
219
|
+
* This lets ArweaveBundlerStorageAdapter compound tokens be passed directly
|
|
220
|
+
* to any adapter that uses ManagedPaymentAdapter without breaking authentication.
|
|
221
|
+
*
|
|
222
|
+
* lastIndexOf is intentional: the credential part may itself contain dots
|
|
223
|
+
* (e.g. a JWT), so we always split at the *last* dot to reach the modulus.
|
|
224
|
+
*/
|
|
225
|
+
private static _parseAuthToken;
|
|
226
|
+
constructor(config: ManagedPaymentAdapterConfig);
|
|
227
|
+
/**
|
|
228
|
+
* Query the Arweave fee oracle for the real upload cost.
|
|
229
|
+
*/
|
|
230
|
+
estimateCost(dataSizeBytes: number): Promise<PaymentQuote>;
|
|
231
|
+
/**
|
|
232
|
+
* Routes payment to the correct network-specific handler based on quote.network.
|
|
233
|
+
*
|
|
234
|
+
* The Arweave path falls back to the base-class pass-through if
|
|
235
|
+
* provideUploadData() was not called. An unrecognised network throws.
|
|
236
|
+
*/
|
|
237
|
+
pay(instruction: PaymentInstruction, onStatus?: (message: string) => void): Promise<PaymentReceipt>;
|
|
238
|
+
/**
|
|
239
|
+
* Returns a WalletProvider-compatible object for the Midnight chain whose
|
|
240
|
+
* `balanceTx()` is fulfilled by the managed signing server instead of a
|
|
241
|
+
* local wallet. The caller supplies the public keys (from whichever source
|
|
242
|
+
* they have — HD derivation, a server endpoint, etc.); the SDK only handles
|
|
243
|
+
* the signing-server round-trip.
|
|
244
|
+
*
|
|
245
|
+
* The returned object satisfies the @midnight-ntwrk/midnight-js-types
|
|
246
|
+
* WalletProvider interface via structural typing — no Midnight package
|
|
247
|
+
* import is required from the caller's side.
|
|
248
|
+
*
|
|
249
|
+
* @param coinPublicKey Midnight coin public key (hex) for the ZK fee circuit.
|
|
250
|
+
* @param encryptionPublicKey Midnight encryption public key (hex).
|
|
251
|
+
* @param onReceipt Optional callback invoked with the PaymentReceipt
|
|
252
|
+
* after each successful balanceTx call. Used internally
|
|
253
|
+
* by MidnightChainAdapter to capture receipt metadata;
|
|
254
|
+
* external callers can omit it.
|
|
255
|
+
*/
|
|
256
|
+
createMidnightWalletProvider(coinPublicKey: string, encryptionPublicKey: string, onReceipt?: (receipt: PaymentReceipt) => void): MidnightWalletProvider;
|
|
257
|
+
/**
|
|
258
|
+
* Arweave remote-signing flow:
|
|
259
|
+
* 1. Creates the Arweave transaction locally (data + tags, no local signing).
|
|
260
|
+
* 2. Calls prepareChunks() to compute data_root (Merkle root) locally.
|
|
261
|
+
* 3. Strips the raw data from the transaction before serialising — only the
|
|
262
|
+
* data_root and data_size (not the actual bytes) are sent to the server.
|
|
263
|
+
* 4. POSTs the stripped transaction JSON to the signing server.
|
|
264
|
+
* 5. Applies the returned id, signature, and owner to the transaction.
|
|
265
|
+
* 6. Restores the raw data so the chunked uploader can post it directly to
|
|
266
|
+
* the Arweave gateway — the server never sees the file content.
|
|
267
|
+
*
|
|
268
|
+
* Falls back to the base-class pass-through if provideUploadData() was not called.
|
|
269
|
+
*/
|
|
270
|
+
private _payArweave;
|
|
271
|
+
/**
|
|
272
|
+
* Midnight payment flow:
|
|
273
|
+
* POSTs the fee amount to the dStorage API service, which holds a funded
|
|
274
|
+
* Midnight account and submits the chain transaction on behalf of the user.
|
|
275
|
+
*
|
|
276
|
+
* POST {baseUrl}{POST_SIGN_TX_API_PATH}
|
|
277
|
+
* → { txData: string (hex-serialized UnboundTransaction), network: string, userId: string }
|
|
278
|
+
* ← { txId: string, signature: string (hex-serialized FinalizedTransaction), ... }
|
|
279
|
+
*
|
|
280
|
+
* The hex-serialized FinalizedTransaction is returned in PaymentReceipt.signedTx
|
|
281
|
+
* for the chain adapter to deserialize and pass to submitTx().
|
|
282
|
+
*/
|
|
283
|
+
private _payMidnight;
|
|
284
|
+
/**
|
|
285
|
+
* Arweave Bundler
|
|
286
|
+
*/
|
|
287
|
+
private _payArweaveBundler;
|
|
288
|
+
/**
|
|
289
|
+
* Managed mock flow:
|
|
290
|
+
* Sends a minimal request to the signing server with the literal network
|
|
291
|
+
* identifier "TEST" — the server treats this as a sandbox/test flow with no
|
|
292
|
+
* real funds involved. The SDK-side network name is "managedmock" to follow
|
|
293
|
+
* the lowercase naming convention; the server-side string is always "TEST".
|
|
294
|
+
*/
|
|
295
|
+
private _payManagedMock;
|
|
296
|
+
/**
|
|
297
|
+
* Shared HTTP helper: POSTs a transaction payload to the signing server and
|
|
298
|
+
* returns the parsed SignTxResponse.
|
|
299
|
+
*
|
|
300
|
+
* - Arweave: txJson is the Arweave tx JSON object (from tx.toJSON()); the server
|
|
301
|
+
* signs it and returns the signature + owner in the response fields.
|
|
302
|
+
* - Midnight: txJson is the hex-serialized UnboundTransaction; the server balances
|
|
303
|
+
* and signs it, returning the hex-serialized FinalizedTransaction in the
|
|
304
|
+
* `signature` response field.
|
|
305
|
+
*
|
|
306
|
+
* Throws on network errors or non-2xx HTTP responses.
|
|
307
|
+
*/
|
|
308
|
+
private _sendSignTxRequest;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @dstorage/storage — adapters/arweave.ts
|
|
313
|
+
*
|
|
314
|
+
* Real Arweave storage adapter.
|
|
315
|
+
* Uploads encrypted blobs to the Arweave permaweb — pay once, store forever.
|
|
316
|
+
*
|
|
317
|
+
* ── Runtime environments ──────────────────────────────────────────────────────
|
|
318
|
+
*
|
|
319
|
+
* Browser (ArConnect):
|
|
320
|
+
* const adapter = new ArweaveStorageAdapter();
|
|
321
|
+
* // Requires the ArConnect extension: https://arconnect.io
|
|
322
|
+
*
|
|
323
|
+
* Node.js (JWK wallet file):
|
|
324
|
+
* const adapter = new ArweaveStorageAdapter({
|
|
325
|
+
* walletKey: JSON.parse(fs.readFileSync('wallet.json', 'utf8')),
|
|
326
|
+
* });
|
|
327
|
+
*
|
|
328
|
+
* ── Testnet ───────────────────────────────────────────────────────────────────
|
|
329
|
+
*
|
|
330
|
+
* const adapter = new ArweaveStorageAdapter({
|
|
331
|
+
* gateway: { host: 'arweave.dev', port: 443, protocol: 'https' },
|
|
332
|
+
* });
|
|
333
|
+
*
|
|
334
|
+
* ── Peer dependency ───────────────────────────────────────────────────────────
|
|
335
|
+
* npm install arweave
|
|
336
|
+
*
|
|
337
|
+
* ── Notes ─────────────────────────────────────────────────────────────────────
|
|
338
|
+
*
|
|
339
|
+
* • Arweave transactions are optimistic: a 202 response means accepted, not
|
|
340
|
+
* confirmed. Confirmation (inclusion in a block) typically takes 2–20 minutes.
|
|
341
|
+
* Set waitForConfirmation: true to block until the tx is on-chain.
|
|
342
|
+
*
|
|
343
|
+
* • For large files or high-volume uploads, consider Irys (https://irys.xyz)
|
|
344
|
+
* which bundles many transactions together for cheaper and near-instant
|
|
345
|
+
* finality. An IrysStorageAdapter can be added alongside this one.
|
|
346
|
+
*
|
|
347
|
+
* • storageId (txId) is PUBLIC on Arweave. Data security relies entirely on
|
|
348
|
+
* the XChaCha20-Poly1305 encryption applied by @dstorage/crypto before reaching here.
|
|
349
|
+
*/
|
|
350
|
+
|
|
351
|
+
interface ArweaveGatewayConfig {
|
|
352
|
+
host: string;
|
|
353
|
+
port: number;
|
|
354
|
+
protocol: "http" | "https";
|
|
355
|
+
}
|
|
356
|
+
interface ArweaveAdapterConfig {
|
|
357
|
+
/**
|
|
358
|
+
* Arweave gateway to broadcast transactions to.
|
|
359
|
+
* Defaults to mainnet (arweave.net:443).
|
|
360
|
+
*
|
|
361
|
+
* Testnet: { host: 'arweave.dev', port: 443, protocol: 'https' }
|
|
362
|
+
*
|
|
363
|
+
* Security: always use `protocol: 'https'` (the default) in production.
|
|
364
|
+
* The SDK relies on standard OS/runtime TLS — no DNS or certificate pinning
|
|
365
|
+
* is applied. Users in adversarial network environments should enforce
|
|
366
|
+
* certificate pinning at the runtime level (e.g. a custom Node.js HTTPS
|
|
367
|
+
* agent or a trusted corporate proxy).
|
|
368
|
+
*/
|
|
369
|
+
gateway?: ArweaveGatewayConfig;
|
|
370
|
+
/**
|
|
371
|
+
* JWK wallet key for Node.js server-side usage.
|
|
372
|
+
* Leave undefined in the browser — ArConnect is used automatically.
|
|
373
|
+
*
|
|
374
|
+
* Obtain a free wallet at https://arweave.app or generate via arweave-js:
|
|
375
|
+
* const jwk = await Arweave.init({}).wallets.generate();
|
|
376
|
+
*/
|
|
377
|
+
walletKey?: Record<string, string>;
|
|
378
|
+
/**
|
|
379
|
+
* Base URL of a local ManagedPaymentAdapter signing server.
|
|
380
|
+
* When provided, the adapter uses ManagedPaymentAdapter (remote signing)
|
|
381
|
+
* instead of the default ArweavePaymentAdapter (local signing).
|
|
382
|
+
* Example: "http://localhost:3000"
|
|
383
|
+
*/
|
|
384
|
+
signingServerUrl?: string;
|
|
385
|
+
/**
|
|
386
|
+
* Bearer token sent as the `Authorization` header to authenticate with the signing server.
|
|
387
|
+
* Required when `signingServerUrl` is provided.
|
|
388
|
+
*/
|
|
389
|
+
authToken?: string;
|
|
390
|
+
/**
|
|
391
|
+
* How many times to retry a failed transaction post before throwing.
|
|
392
|
+
* Uses a simple linear back-off: 1 s, 2 s, 3 s…
|
|
393
|
+
* Defaults to 3.
|
|
394
|
+
*/
|
|
395
|
+
maxRetries?: number;
|
|
396
|
+
/**
|
|
397
|
+
* If true, poll Arweave until the transaction is confirmed (block included)
|
|
398
|
+
* before returning from store(). Confirmation typically takes 2–20 minutes.
|
|
399
|
+
*
|
|
400
|
+
* Defaults to false (optimistic — returns as soon as the gateway accepts
|
|
401
|
+
* the transaction with HTTP 200 or 202).
|
|
402
|
+
*/
|
|
403
|
+
waitForConfirmation?: boolean;
|
|
404
|
+
/**
|
|
405
|
+
* Polling interval in ms while waiting for confirmation.
|
|
406
|
+
* Defaults to 30_000 (30 seconds).
|
|
407
|
+
*/
|
|
408
|
+
confirmationPollMs?: number;
|
|
409
|
+
/**
|
|
410
|
+
* Maximum time in ms to wait for confirmation before throwing a timeout error.
|
|
411
|
+
* Defaults to 1_200_000 (20 minutes).
|
|
412
|
+
*/
|
|
413
|
+
confirmationTimeoutMs?: number;
|
|
414
|
+
/**
|
|
415
|
+
* When true, skip the BLAKE3 content-hash check on retrieve.
|
|
416
|
+
* By default (false) the adapter fetches the transaction metadata and verifies
|
|
417
|
+
* that the `X-Content-Hash` tag recorded at upload time matches the retrieved
|
|
418
|
+
* bytes. Set to true only if you trust the gateway entirely or are using an
|
|
419
|
+
* Arweave node that does not expose the transaction metadata endpoint.
|
|
420
|
+
*/
|
|
421
|
+
skipIntegrityCheck?: boolean;
|
|
422
|
+
/**
|
|
423
|
+
* Maximum number of bytes allowed in a single retrieve() call.
|
|
424
|
+
* The adapter rejects the download before materialising the blob if the
|
|
425
|
+
* Arweave transaction metadata reports a larger `data_size`, and always
|
|
426
|
+
* rejects after loading if the actual byte count exceeds this value.
|
|
427
|
+
* Defaults to 268_435_456 (256 MB).
|
|
428
|
+
*/
|
|
429
|
+
maxRetrieveSizeBytes?: number;
|
|
430
|
+
/**
|
|
431
|
+
* Optional logger for SDK operational output.
|
|
432
|
+
* Pass `logger: console` to see all output, or inject your own logger.
|
|
433
|
+
* Omit to suppress all SDK log output.
|
|
434
|
+
*/
|
|
435
|
+
logger?: StorageAdapterLogger;
|
|
436
|
+
}
|
|
437
|
+
declare class ArweaveStorageAdapter implements StorageAdapter {
|
|
438
|
+
readonly name: StorageProviderName;
|
|
439
|
+
readonly providerName: string;
|
|
440
|
+
paymentAdapter: PaymentAdapter;
|
|
441
|
+
private readonly gateway;
|
|
442
|
+
private readonly maxRetries;
|
|
443
|
+
private readonly shouldWaitForConfirm;
|
|
444
|
+
private readonly confirmationPollMs;
|
|
445
|
+
private readonly confirmationTimeoutMs;
|
|
446
|
+
private readonly skipIntegrityCheck;
|
|
447
|
+
private readonly maxRetrieveSizeBytes;
|
|
448
|
+
protected readonly logger: StorageAdapterLogger | undefined;
|
|
449
|
+
private arweaveClient;
|
|
450
|
+
constructor(config?: ArweaveAdapterConfig);
|
|
451
|
+
private getClient;
|
|
452
|
+
store(data: Uint8Array, metadata?: Record<string, string>): Promise<StorageUploadResult>;
|
|
453
|
+
retrieve(id: string): Promise<{
|
|
454
|
+
bytes: Uint8Array;
|
|
455
|
+
tags: Record<string, string>;
|
|
456
|
+
}>;
|
|
457
|
+
estimateCost(dataSizeBytes: number): Promise<StorageQuote>;
|
|
458
|
+
/**
|
|
459
|
+
* Upload a signed transaction using arweave-js getUploader().
|
|
460
|
+
*
|
|
461
|
+
* getUploader() sends just the tx header to /tx, then streams each 256 KB
|
|
462
|
+
* data slice to the /chunk endpoint. This avoids the ~12 MB HTTP body limit
|
|
463
|
+
* of transactions.post() and supports arbitrarily large transactions.
|
|
464
|
+
*
|
|
465
|
+
* Failed slices are retried individually up to maxRetries times with linear
|
|
466
|
+
* back-off, so a transient network error won't restart the entire upload.
|
|
467
|
+
*/
|
|
468
|
+
private uploadWithChunker;
|
|
469
|
+
private pollUntilConfirmed;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @dstorage/storage — adapters/arweave-bundler.ts
|
|
474
|
+
*
|
|
475
|
+
* Arweave Bundler storage adapter — ANS-104 bundled uploads with server-side signing.
|
|
476
|
+
*
|
|
477
|
+
* ── Upload flow (no client-side Arweave wallet needed) ────────────────────────
|
|
478
|
+
*
|
|
479
|
+
* 1. Client creates an ANS-104 data item locally with the already-encrypted data.
|
|
480
|
+
* 2. Computes the 48-byte deep_hash locally — the ANS-104 signing digest.
|
|
481
|
+
* 3. Sends ONLY the hash to the dStorage API signing server.
|
|
482
|
+
* Raw file bytes never leave the client — same privacy invariant as the
|
|
483
|
+
* current managed Arweave flow where only the stripped tx JSON (data_root)
|
|
484
|
+
* goes to the server.
|
|
485
|
+
* 4. Server signs the hash with its Arweave JWK (funded Turbo Credits account).
|
|
486
|
+
* 5. Client assembles the complete signed data item locally.
|
|
487
|
+
* 6. Client POSTs the signed data item directly to the ArDrive bundler.
|
|
488
|
+
* 7. Returns with near-instant finality — txId is available immediately.
|
|
489
|
+
*
|
|
490
|
+
* ── Retrieve flow ─────────────────────────────────────────────────────────────
|
|
491
|
+
* Standard Arweave gateway fetch (identical to ArweaveStorageAdapter.retrieve).
|
|
492
|
+
*
|
|
493
|
+
* ── Peer dependency ───────────────────────────────────────────────────────────
|
|
494
|
+
* No extra install needed — @dha-team/arbundles ships as a dependency of @ardrive/turbo-sdk.
|
|
495
|
+
*
|
|
496
|
+
* ── Server requirements ───────────────────────────────────────────────────────
|
|
497
|
+
* The dStorage API server must expose (auth-protected via Bearer token):
|
|
498
|
+
* POST /api/service/sign-tx → { signature: string, txId: string, success: boolean, … }
|
|
499
|
+
* The server's Arweave wallet must have Turbo Credits funded at https://ardrive.io.
|
|
500
|
+
*
|
|
501
|
+
* ── Auth token format ─────────────────────────────────────────────────────────
|
|
502
|
+
* authToken must be in the format: <credential>.<base64url_modulus>
|
|
503
|
+
* where <base64url_modulus> is the 512-byte RSA-4096 public key modulus
|
|
504
|
+
* base64url-encoded. The adapter validates and pins the key at construction time.
|
|
505
|
+
* Re-issue the token from the signing server to obtain the current key.
|
|
506
|
+
*
|
|
507
|
+
* ── Notes ─────────────────────────────────────────────────────────────────────
|
|
508
|
+
* • The ArDrive bundler provides near-instant finality — unlike the 2–20 min Arweave L1 wait.
|
|
509
|
+
* • The server holds the funded Turbo Credits account; users need no AR tokens.
|
|
510
|
+
* • Only 48 bytes (the deep_hash) go to the server; ciphertext stays on client.
|
|
511
|
+
*/
|
|
512
|
+
|
|
513
|
+
interface ArweaveBundlerAdapterConfig {
|
|
514
|
+
/**
|
|
515
|
+
* Base URL of the dStorage API server that holds the funded Turbo Credits account.
|
|
516
|
+
* Example: "https://api.my-dstorage-server.com"
|
|
517
|
+
*/
|
|
518
|
+
signingServerUrl?: string;
|
|
519
|
+
/**
|
|
520
|
+
* Bearer token sent as the `Authorization` header to authenticate with the signing server.
|
|
521
|
+
* Required when `signingServerUrl` is provided.
|
|
522
|
+
*/
|
|
523
|
+
authToken?: string;
|
|
524
|
+
/**
|
|
525
|
+
* Arweave gateway URL used for data retrieval.
|
|
526
|
+
* Defaults to the public Arweave gateway.
|
|
527
|
+
*
|
|
528
|
+
* Security: always use an `https://` URL (the default) in production.
|
|
529
|
+
* This adapter uses `globalThis.fetch` directly — no DNS or certificate
|
|
530
|
+
* pinning is applied. Users in adversarial network environments can override
|
|
531
|
+
* `globalThis.fetch` before constructing the adapter to inject their own
|
|
532
|
+
* certificate-pinned fetch implementation.
|
|
533
|
+
*/
|
|
534
|
+
gateway?: string;
|
|
535
|
+
/**
|
|
536
|
+
* Maximum number of bytes allowed in a single retrieve() call.
|
|
537
|
+
* Rejects if the `Content-Length` response header exceeds this value, and
|
|
538
|
+
* always rejects after loading if the actual byte count exceeds it.
|
|
539
|
+
* Defaults to 268_435_456 (256 MB).
|
|
540
|
+
*/
|
|
541
|
+
maxRetrieveSizeBytes?: number;
|
|
542
|
+
/**
|
|
543
|
+
* Skip BLAKE3 content-hash verification on retrieve.
|
|
544
|
+
* Only set to true when connecting to a fully trusted gateway.
|
|
545
|
+
* Defaults to false.
|
|
546
|
+
*/
|
|
547
|
+
skipIntegrityCheck?: boolean;
|
|
548
|
+
/**
|
|
549
|
+
* Optional logger for SDK operational output.
|
|
550
|
+
*/
|
|
551
|
+
logger?: StorageAdapterLogger;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Stores encrypted data on Arweave via the ArDrive bundler (near-instant finality).
|
|
555
|
+
*
|
|
556
|
+
* Signing is delegated to the dStorage API server, which holds a funded Turbo Credits
|
|
557
|
+
* account. The client sends only a 48-byte ANS-104 deep_hash to the server — the
|
|
558
|
+
* encrypted file bytes never leave the client, preserving the same privacy invariant
|
|
559
|
+
* as the existing managed Arweave flow.
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* const adapter = new ArweaveBundlerStorageAdapter({
|
|
563
|
+
* signingServerUrl: "https://api.my-server.com",
|
|
564
|
+
* authToken: "ds_...",
|
|
565
|
+
* });
|
|
566
|
+
* const { id } = await adapter.store(encryptedBytes, { "Content-Type": "application/octet-stream" });
|
|
567
|
+
*/
|
|
568
|
+
declare class ArweaveBundlerStorageAdapter implements StorageAdapter {
|
|
569
|
+
readonly name: StorageProviderName;
|
|
570
|
+
readonly providerName = "Arweave (Bundler)";
|
|
571
|
+
readonly paymentAdapter: PaymentAdapter;
|
|
572
|
+
private readonly signingServerUrl;
|
|
573
|
+
private readonly gateway;
|
|
574
|
+
private readonly maxRetrieveSizeBytes;
|
|
575
|
+
private readonly skipIntegrityCheck;
|
|
576
|
+
protected readonly logger: StorageAdapterLogger | undefined;
|
|
577
|
+
/** RSA-4096 public key modulus (512 bytes) parsed from the auth token at construction time. */
|
|
578
|
+
private readonly ownerPublicKey;
|
|
579
|
+
constructor(config?: ArweaveBundlerAdapterConfig);
|
|
580
|
+
store(data: Uint8Array, metadata?: Record<string, string>): Promise<StorageUploadResult>;
|
|
581
|
+
retrieve(id: string): Promise<{
|
|
582
|
+
bytes: Uint8Array;
|
|
583
|
+
tags: Record<string, string>;
|
|
584
|
+
}>;
|
|
585
|
+
estimateCost(dataSizeBytes: number): Promise<StorageQuote>;
|
|
586
|
+
/**
|
|
587
|
+
* Build a minimal signer object compatible with the @dha-team/arbundles DataItem API.
|
|
588
|
+
*
|
|
589
|
+
* The only non-trivial method is sign(): it sends the deep_hash produced by
|
|
590
|
+
* the DataItem's internal ANS-104 signing procedure to the selected payment adapter.
|
|
591
|
+
* The payment adapter responds with the RSA-PSS signature over that hash (512 bytes, ANS-104 type 1).
|
|
592
|
+
* Raw file bytes never leave the client.
|
|
593
|
+
*
|
|
594
|
+
* The owner public key is parsed from the auth token at construction time — no
|
|
595
|
+
* network round-trip is needed here.
|
|
596
|
+
*/
|
|
597
|
+
private _buildSigner;
|
|
598
|
+
/**
|
|
599
|
+
* POST the 48-byte ANS-104 deep_hash to the signing server via the shared sign-tx endpoint.
|
|
600
|
+
*
|
|
601
|
+
* Uses network: "arweave_bundler" so the server routes to the bundler-specific signing path.
|
|
602
|
+
* The `dataSizeBytes` field lets the server estimate and quote the upload cost.
|
|
603
|
+
*/
|
|
604
|
+
private _signHash;
|
|
605
|
+
/**
|
|
606
|
+
* Parse the compound auth token (<credential>.<base64url_modulus>) issued by the
|
|
607
|
+
* signing server. Validates that the embedded key is exactly 512 bytes (RSA-4096).
|
|
608
|
+
* Throws at construction time if the format is wrong — fail-fast before any network call.
|
|
609
|
+
*
|
|
610
|
+
* lastIndexOf is intentional: the credential part may itself contain dots
|
|
611
|
+
* (e.g. a JWT), so we always split at the *last* dot to reach the modulus.
|
|
612
|
+
*/
|
|
613
|
+
private static _parseToken;
|
|
614
|
+
/**
|
|
615
|
+
* POST the complete signed ANS-104 data item bytes directly to the ArDrive bundler.
|
|
616
|
+
* Server Turbo Credits are consumed based on the signing key — no client wallet needed.
|
|
617
|
+
*/
|
|
618
|
+
private _uploadToBundler;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @dstorage/storage — arweave-local.ts
|
|
623
|
+
*
|
|
624
|
+
* Local Arweave testing utilities built on top of arlocal:
|
|
625
|
+
* https://github.com/textury/arlocal
|
|
626
|
+
*
|
|
627
|
+
* arlocal is a zero-configuration local Arweave gateway for integration
|
|
628
|
+
* testing. It accepts transactions without requiring real AR tokens, exposes
|
|
629
|
+
* a /mint endpoint to fund test wallets instantly, and a /mine endpoint to
|
|
630
|
+
* fast-forward block confirmation — all fully offline.
|
|
631
|
+
*
|
|
632
|
+
* ── Quick start ───────────────────────────────────────────────────────────────
|
|
633
|
+
*
|
|
634
|
+
* # 1. Start arlocal (once per dev session) — Docker is recommended:
|
|
635
|
+
* docker run -d --rm -p 1984:1984 --name arlocal textury/arlocal
|
|
636
|
+
* # alternatively, without Docker:
|
|
637
|
+
* npx arlocal
|
|
638
|
+
*
|
|
639
|
+
* # 2. In your code, use ArweaveLocalStorageAdapter instead of the real one
|
|
640
|
+
* const { adapter, walletKey, address } =
|
|
641
|
+
* await ArweaveLocalStorageAdapter.createWithTestWallet();
|
|
642
|
+
*
|
|
643
|
+
* # 3. Mint test tokens
|
|
644
|
+
* await adapter.testnet.mintTokens(address, 5_000_000_000_000n); // 5 AR
|
|
645
|
+
*
|
|
646
|
+
* # 4. Use exactly like ArweaveStorageAdapter
|
|
647
|
+
* const { id } = await adapter.store('my encrypted data');
|
|
648
|
+
* await adapter.testnet.mine(); // confirm the tx instantly
|
|
649
|
+
* const data = await adapter.retrieve(id);
|
|
650
|
+
*
|
|
651
|
+
* ── Exports ───────────────────────────────────────────────────────────────────
|
|
652
|
+
*
|
|
653
|
+
* ARWEAVE_MAINNET — gateway preset for arweave.net
|
|
654
|
+
* ARWEAVE_LOCAL — gateway preset for localhost:1984
|
|
655
|
+
* arlocalGateway(port) — build a custom-port local preset
|
|
656
|
+
* ArweaveLocalHelper — mint / mine / balance / reset helpers
|
|
657
|
+
* ArweaveLocalStorageAdapter — drop-in adapter for local testing
|
|
658
|
+
* ArweaveLocalError — typed error thrown by helper methods
|
|
659
|
+
*/
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Local arlocal gateway preset (default port 1984).
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* new ArweaveStorageAdapter({ gateway: ARWEAVE_LOCAL, walletKey: testJwk })
|
|
666
|
+
* // or:
|
|
667
|
+
* new ArweaveLocalStorageAdapter({ walletKey: testJwk })
|
|
668
|
+
*/
|
|
669
|
+
declare const ARWEAVE_LOCAL: ArweaveGatewayConfig;
|
|
670
|
+
/**
|
|
671
|
+
* Build a local arlocal gateway preset on a non-default port.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* const gw = arlocalGateway(1985);
|
|
675
|
+
* new ArweaveLocalStorageAdapter({ gateway: gw, walletKey: testJwk })
|
|
676
|
+
*/
|
|
677
|
+
declare function arlocalGateway(port?: number): ArweaveGatewayConfig;
|
|
678
|
+
interface ArweaveLocalHelperConfig {
|
|
679
|
+
/** Base URL of the arlocal instance. Defaults to 'http://localhost:1984'. */
|
|
680
|
+
url?: string;
|
|
681
|
+
}
|
|
682
|
+
interface ArweaveLocalInfo {
|
|
683
|
+
network: string;
|
|
684
|
+
version: number;
|
|
685
|
+
release: number;
|
|
686
|
+
height: number;
|
|
687
|
+
current: string;
|
|
688
|
+
peers: number;
|
|
689
|
+
queue_length: number;
|
|
690
|
+
node_state_latency: number;
|
|
691
|
+
}
|
|
692
|
+
interface ArweaveLocalBalance {
|
|
693
|
+
/** Raw balance in Winstons (1 AR = 1_000_000_000_000 Winstons). */
|
|
694
|
+
winstons: string;
|
|
695
|
+
/** Human-readable balance, e.g. "5" for 5 AR. */
|
|
696
|
+
ar: string;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Helper for controlling a running arlocal instance.
|
|
700
|
+
*
|
|
701
|
+
* Use this to fund test wallets, fast-forward block confirmations, and
|
|
702
|
+
* inspect state during integration tests.
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* const helper = new ArweaveLocalHelper();
|
|
706
|
+
* await helper.mintTokens(address, 1_000_000_000_000n); // 1 AR
|
|
707
|
+
* await helper.mine();
|
|
708
|
+
* const { ar } = await helper.getBalance(address);
|
|
709
|
+
*/
|
|
710
|
+
declare class ArweaveLocalHelper {
|
|
711
|
+
private readonly baseUrl;
|
|
712
|
+
constructor(config?: ArweaveLocalHelperConfig);
|
|
713
|
+
/**
|
|
714
|
+
* Credit a wallet address with test AR tokens.
|
|
715
|
+
*
|
|
716
|
+
* The amount is in Winstons (1 AR = 1_000_000_000_000 Winstons).
|
|
717
|
+
* Defaults to 1 AR if not specified.
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* await helper.mintTokens(address, 5_000_000_000_000n); // 5 AR
|
|
721
|
+
*/
|
|
722
|
+
mintTokens(address: string, winstons?: bigint | number): Promise<void>;
|
|
723
|
+
/**
|
|
724
|
+
* Fast-forward the arlocal blockchain by mining one or more blocks.
|
|
725
|
+
*
|
|
726
|
+
* Pending transactions only become "confirmed" after a block is mined.
|
|
727
|
+
* Call this after uploading if your test checks confirmed status
|
|
728
|
+
* (e.g. when using `waitForConfirmation: true`).
|
|
729
|
+
*
|
|
730
|
+
* @example
|
|
731
|
+
* await helper.mine(); // mine 1 block
|
|
732
|
+
* await helper.mine(3); // mine 3 blocks
|
|
733
|
+
*/
|
|
734
|
+
mine(blocks?: number): Promise<void>;
|
|
735
|
+
/**
|
|
736
|
+
* Query the AR token balance of a wallet address on arlocal.
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* const { ar, winstons } = await helper.getBalance(address);
|
|
740
|
+
* console.log(`Balance: ${ar} AR (${winstons} winstons)`);
|
|
741
|
+
*/
|
|
742
|
+
getBalance(address: string): Promise<ArweaveLocalBalance>;
|
|
743
|
+
/**
|
|
744
|
+
* Retrieve general info about the arlocal instance.
|
|
745
|
+
* Useful for confirming the server is reachable before running tests.
|
|
746
|
+
*/
|
|
747
|
+
getInfo(): Promise<ArweaveLocalInfo>;
|
|
748
|
+
/**
|
|
749
|
+
* Returns `true` if the arlocal instance is reachable, `false` otherwise.
|
|
750
|
+
*
|
|
751
|
+
* Use in `beforeAll` to skip integration tests gracefully when arlocal
|
|
752
|
+
* is not running in the local environment.
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* beforeAll(async () => {
|
|
756
|
+
* if (!(await helper.isRunning())) {
|
|
757
|
+
* console.warn('arlocal not running — skipping integration tests');
|
|
758
|
+
* }
|
|
759
|
+
* });
|
|
760
|
+
*/
|
|
761
|
+
isRunning(): Promise<boolean>;
|
|
762
|
+
/**
|
|
763
|
+
* Drop all transactions and reset arlocal state to a clean slate.
|
|
764
|
+
* Only available when arlocal is started with persistence disabled (the default).
|
|
765
|
+
*/
|
|
766
|
+
reset(): Promise<void>;
|
|
767
|
+
private get;
|
|
768
|
+
}
|
|
769
|
+
type ArweaveLocalAdapterConfig = ArweaveAdapterConfig;
|
|
770
|
+
/**
|
|
771
|
+
* A storage adapter for local Arweave integration testing using arlocal.
|
|
772
|
+
*
|
|
773
|
+
* Identical API to `ArweaveStorageAdapter` but pre-configured for a local
|
|
774
|
+
* arlocal instance. Exposes a `.testnet` helper for minting tokens, mining
|
|
775
|
+
* blocks, and inspecting state — without touching the real Arweave network.
|
|
776
|
+
*
|
|
777
|
+
* ── Requirements ──────────────────────────────────────────────────────────────
|
|
778
|
+
*
|
|
779
|
+
* Start arlocal (Docker recommended — no npm install needed):
|
|
780
|
+
* docker run -d --rm -p 1984:1984 --name arlocal textury/arlocal
|
|
781
|
+
* or, via npx (installs arlocal on demand):
|
|
782
|
+
* npx arlocal
|
|
783
|
+
*
|
|
784
|
+
* ── Usage ─────────────────────────────────────────────────────────────────────
|
|
785
|
+
*
|
|
786
|
+
* Option A — static factory (recommended for tests): auto-generates & funds wallet
|
|
787
|
+
*
|
|
788
|
+
* const { adapter, walletKey, address } =
|
|
789
|
+
* await ArweaveLocalStorageAdapter.createWithTestWallet();
|
|
790
|
+
*
|
|
791
|
+
* const ds = new DStorage({
|
|
792
|
+
* storageAdapter: adapter,
|
|
793
|
+
* chainAdapter: new MockChainAdapter(),
|
|
794
|
+
* });
|
|
795
|
+
*
|
|
796
|
+
* Option B — manual config (when you already have a wallet):
|
|
797
|
+
*
|
|
798
|
+
* const adapter = new ArweaveLocalStorageAdapter({ walletKey: myJwk });
|
|
799
|
+
* await adapter.testnet.mintTokens(address, 2_000_000_000_000n); // 2 AR
|
|
800
|
+
*
|
|
801
|
+
* ── Replacing the real adapter ────────────────────────────────────────────────
|
|
802
|
+
*
|
|
803
|
+
* // Development / CI — local arlocal
|
|
804
|
+
* storageAdapter: new ArweaveLocalStorageAdapter({ walletKey: testJwk })
|
|
805
|
+
*
|
|
806
|
+
* // Production — real Arweave mainnet
|
|
807
|
+
* storageAdapter: new ArweaveStorageAdapter({ walletKey: realJwk })
|
|
808
|
+
*/
|
|
809
|
+
declare class ArweaveLocalStorageAdapter extends ArweaveStorageAdapter {
|
|
810
|
+
readonly name: StorageProviderName;
|
|
811
|
+
readonly providerName: string;
|
|
812
|
+
/** Access arlocal control methods: mint, mine, balance, reset. */
|
|
813
|
+
readonly testnet: ArweaveLocalHelper;
|
|
814
|
+
/** Resolves when the wallet has been funded on arlocal (if walletKey was provided). */
|
|
815
|
+
private readonly _initMintPromise;
|
|
816
|
+
constructor(config?: ArweaveLocalAdapterConfig);
|
|
817
|
+
/**
|
|
818
|
+
* Extract the 683-char base64url RSA modulus suffix from a compound auth token
|
|
819
|
+
* (<credential>.<modulus>). Returns undefined for plain tokens.
|
|
820
|
+
* Mirrors the same logic in ManagedPaymentAdapter._parseAuthToken.
|
|
821
|
+
*/
|
|
822
|
+
private static _extractOwnerKey;
|
|
823
|
+
private _mintWallet;
|
|
824
|
+
private _mintManagedOwner;
|
|
825
|
+
private _mintToOwnerKey;
|
|
826
|
+
/**
|
|
827
|
+
* Factory method: generates a fresh Arweave wallet, mints test AR tokens
|
|
828
|
+
* into it, and returns a fully-configured adapter ready for testing.
|
|
829
|
+
*
|
|
830
|
+
* Requires arlocal to be running at the given URL.
|
|
831
|
+
*
|
|
832
|
+
* @param options.fundAr AR to mint into the test wallet (default: 10)
|
|
833
|
+
* @param options.gateway Override the arlocal gateway (default: localhost:1984)
|
|
834
|
+
*
|
|
835
|
+
* @example
|
|
836
|
+
* const { adapter, walletKey, address } =
|
|
837
|
+
* await ArweaveLocalStorageAdapter.createWithTestWallet({ fundAr: 5 });
|
|
838
|
+
*
|
|
839
|
+
* // Then use adapter in your DStorage instance:
|
|
840
|
+
* const ds = new DStorage({ storageAdapter: adapter, chainAdapter: new MockChainAdapter() });
|
|
841
|
+
*/
|
|
842
|
+
static createWithTestWallet(options?: {
|
|
843
|
+
fundAr?: number;
|
|
844
|
+
gateway?: ArweaveGatewayConfig;
|
|
845
|
+
}): Promise<{
|
|
846
|
+
adapter: ArweaveLocalStorageAdapter;
|
|
847
|
+
walletKey: Record<string, string>;
|
|
848
|
+
address: string;
|
|
849
|
+
}>;
|
|
850
|
+
store(data: Uint8Array, metadata?: Record<string, string>): Promise<StorageUploadResult>;
|
|
851
|
+
}
|
|
852
|
+
declare class ArweaveLocalError extends Error {
|
|
853
|
+
readonly statusCode: number;
|
|
854
|
+
constructor(message: string, statusCode: number);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
declare class DStorageError extends Error {
|
|
858
|
+
readonly code: number;
|
|
859
|
+
readonly httpStatus?: number;
|
|
860
|
+
constructor(code: number, message: string, options?: ErrorOptions & {
|
|
861
|
+
httpStatus?: number;
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
declare function isDStorageError(err: unknown): err is DStorageError;
|
|
865
|
+
declare const CryptoErrorCode: {
|
|
866
|
+
readonly WEBCRYPTO_NOT_AVAILABLE: 12000;
|
|
867
|
+
readonly BASE64URL_INVALID: 12001;
|
|
868
|
+
readonly MISSING_KEY_INPUT: 12002;
|
|
869
|
+
readonly MNEMONIC_TOO_SHORT: 12003;
|
|
870
|
+
readonly SEED_INVALID_LENGTH: 12004;
|
|
871
|
+
readonly MNEMONIC_INVALID: 12005;
|
|
872
|
+
readonly HEX_ODD_LENGTH: 12006;
|
|
873
|
+
readonly HEX_INVALID_CHARS: 12007;
|
|
874
|
+
readonly DEK_INVALID_LENGTH: 12008;
|
|
875
|
+
readonly WRAP_KEK_INVALID_LENGTH: 12009;
|
|
876
|
+
readonly UNWRAP_KEK_INVALID_LENGTH: 12010;
|
|
877
|
+
readonly ENVELOPE_EMPTY_WRAPPERS: 12011;
|
|
878
|
+
readonly XCHACHA_INVALID_STORAGE_ID_LEN: 12012;
|
|
879
|
+
readonly XCHACHA_PAYLOAD_MALFORMED: 12013;
|
|
880
|
+
readonly XCHACHA_STORAGE_ID_MALFORMED: 12014;
|
|
881
|
+
readonly MLKEM_SEED_INVALID_LENGTH: 12015;
|
|
882
|
+
readonly MLKEM_MISSING_CIPHERTEXT: 12016;
|
|
883
|
+
readonly MLKEM_UNKNOWN_ALGORITHM: 12017;
|
|
884
|
+
readonly MLKEM_UNKNOWN_VARIANT: 12018;
|
|
885
|
+
};
|
|
886
|
+
type CryptoErrorCode = (typeof CryptoErrorCode)[keyof typeof CryptoErrorCode];
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* @dstorage/crypto — types.ts
|
|
890
|
+
*
|
|
891
|
+
* Core types and interfaces for the crypto package:
|
|
892
|
+
* - EncryptionScheme — on-chain scheme identifier
|
|
893
|
+
* - CryptoScheme — interface every scheme implementation must satisfy
|
|
894
|
+
* - base64url helpers — shared encoding utilities used across scheme implementations
|
|
895
|
+
*/
|
|
896
|
+
/**
|
|
897
|
+
* Identifies the encryption algorithm used to encrypt a storageId and content.
|
|
898
|
+
* Recorded on-chain in ReferenceEntry.encryptionScheme so the SDK can dispatch
|
|
899
|
+
* the correct decryption function at read time.
|
|
900
|
+
*
|
|
901
|
+
* Values:
|
|
902
|
+
* "xchacha20poly1305-v1" — XChaCha20-Poly1305 (per-upload random DEK, wrapped in keyEnvelope); default
|
|
903
|
+
* "" — No encryption; storageId and content are stored as plaintext (public data)
|
|
904
|
+
*/
|
|
905
|
+
type EncryptionScheme = "xchacha20poly1305-v1" | "";
|
|
906
|
+
/**
|
|
907
|
+
* The result of wrapping a DEK under a provider's key material.
|
|
908
|
+
* Returned by every EncryptionAdapter.wrapDek() implementation and
|
|
909
|
+
* stored as a KeyWrapper entry inside the on-chain KeyEnvelope.
|
|
910
|
+
*
|
|
911
|
+
* Symmetric providers set algorithm/kekDerivation for their own scheme and
|
|
912
|
+
* leave kemCiphertext undefined. Asymmetric providers (ML-KEM) additionally
|
|
913
|
+
* populate kemCiphertext with the KEM ciphertext needed for decapsulation.
|
|
914
|
+
*/
|
|
915
|
+
interface WrappedDekResult {
|
|
916
|
+
/** Algorithm identifier, e.g. "xchacha20poly1305-v1" or "mlkem768-xchacha20poly1305-v1". */
|
|
917
|
+
algorithm: string;
|
|
918
|
+
/** How the KEK was derived from its source material, e.g. "hkdf-sha256-v1". */
|
|
919
|
+
kekDerivation: string;
|
|
920
|
+
/** base64url-encoded wrapped DEK ciphertext. */
|
|
921
|
+
wrappedDek: string;
|
|
922
|
+
/** base64url-encoded KEM ciphertext — present only for asymmetric providers. */
|
|
923
|
+
kemCiphertext?: string;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Interface for a symmetric encryption scheme.
|
|
927
|
+
*
|
|
928
|
+
* Implementations are instantiated from a random DEK via a static factory
|
|
929
|
+
* (e.g. XChaChaScheme.fromKey(dek)) for per-upload encryption.
|
|
930
|
+
*/
|
|
931
|
+
interface CryptoScheme {
|
|
932
|
+
/** Scheme identifier recorded on-chain. */
|
|
933
|
+
readonly schemeName: Exclude<EncryptionScheme, "">;
|
|
934
|
+
/**
|
|
935
|
+
* Encrypt raw bytes and return a self-contained serialized payload
|
|
936
|
+
* ready to be uploaded to off-chain storage.
|
|
937
|
+
*
|
|
938
|
+
* `aad` is bound into the Poly1305 auth tag and must match on decrypt.
|
|
939
|
+
* Use PAYLOAD_AAD for single-shot uploads and manifests; use chunkAad(i, n)
|
|
940
|
+
* for individual chunks so a malicious gateway cannot swap chunk order.
|
|
941
|
+
*/
|
|
942
|
+
encryptPayload(bytes: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
|
|
943
|
+
/**
|
|
944
|
+
* Deserialize and decrypt a payload previously produced by encryptPayload().
|
|
945
|
+
* Throws if the payload format is invalid, the auth tag fails, or the AAD mismatches.
|
|
946
|
+
*/
|
|
947
|
+
decryptPayload(data: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
|
|
948
|
+
/**
|
|
949
|
+
* Encrypt a 43-char base64url storage ID (32 decoded bytes) for on-chain storage.
|
|
950
|
+
* Returns a base64url-encoded encrypted form.
|
|
951
|
+
*/
|
|
952
|
+
encryptStorageId(storageId: string): Promise<string>;
|
|
953
|
+
/**
|
|
954
|
+
* Decrypt a storage ID previously encrypted by encryptStorageId().
|
|
955
|
+
* Returns the original 43-char base64url storage ID.
|
|
956
|
+
*/
|
|
957
|
+
decryptStorageId(encryptedId: string): Promise<string>;
|
|
958
|
+
}
|
|
959
|
+
/** Decode a base64url string to a Uint8Array. */
|
|
960
|
+
declare function base64urlToBytes(b64url: string): Uint8Array;
|
|
961
|
+
/** Encode a Uint8Array to a base64url string (no padding). */
|
|
962
|
+
declare function bytesToBase64url(bytes: Uint8Array): string;
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* @dstorage/crypto — keys.ts
|
|
966
|
+
* Provides seed-based key derivation utilities:
|
|
967
|
+
*
|
|
968
|
+
* - KeyDeriver: resolves a BIP-39 mnemonic or raw hex seed to raw bytes,
|
|
969
|
+
* importing seed bytes as a CryptoKey for use with deriveKek() (keyEnvelope.ts).
|
|
970
|
+
* - hexToBytes: parses a hex string into a Uint8Array.
|
|
971
|
+
*/
|
|
972
|
+
/**
|
|
973
|
+
* Resolves a BIP-39 mnemonic or raw hex seed to raw bytes.
|
|
974
|
+
* Implements EncryptionAdapter — pass an instance to DStorage config.
|
|
975
|
+
*/
|
|
976
|
+
declare class KeyDeriver {
|
|
977
|
+
private readonly input;
|
|
978
|
+
constructor(input: {
|
|
979
|
+
mnemonic?: string;
|
|
980
|
+
seedHex?: string;
|
|
981
|
+
});
|
|
982
|
+
/**
|
|
983
|
+
* Return the raw seed bytes.
|
|
984
|
+
* Import the result as a non-extractable HKDF CryptoKey before passing to deriveKek().
|
|
985
|
+
*/
|
|
986
|
+
getSeed(): Promise<Uint8Array>;
|
|
987
|
+
/** Resolves and validates the seed as a Buffer. */
|
|
988
|
+
private getSeedBuffer;
|
|
989
|
+
}
|
|
990
|
+
declare function hexToBytes(hex: string, label?: string): Uint8Array<ArrayBuffer>;
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* @dstorage/crypto — xchacha.ts
|
|
994
|
+
* Symmetric authenticated encryption using XChaCha20-Poly1305.
|
|
995
|
+
*
|
|
996
|
+
* Key derivation:
|
|
997
|
+
* seed bytes (from EncryptionAdapter)
|
|
998
|
+
* → HKDF-SHA-256 (domain-separated, optionally address-bound)
|
|
999
|
+
* → 32-byte symmetric key (KEK)
|
|
1000
|
+
* → per-upload random DEK wrapped under KEK
|
|
1001
|
+
*
|
|
1002
|
+
* Why XChaCha20-Poly1305:
|
|
1003
|
+
* - 192-bit nonce eliminates birthday-bound collision risk —
|
|
1004
|
+
* safe to generate random nonces indefinitely
|
|
1005
|
+
* - Pure bytes in / bytes out — no WebCrypto CryptoKey ceremony
|
|
1006
|
+
* - Better performance on hardware without AES acceleration (mobile, ARM, IoT)
|
|
1007
|
+
*
|
|
1008
|
+
* Why a single symmetric key instead of a KEM keypair:
|
|
1009
|
+
* A KEM step would only add value if data needed to be
|
|
1010
|
+
* encrypted for a different recipient using their public key. For single-user
|
|
1011
|
+
* self-encryption where the same party encrypts and decrypts, HKDF → XChaCha20
|
|
1012
|
+
* is simpler, has much smaller ciphertext overhead, and provides equivalent
|
|
1013
|
+
* security. If cross-user encryption is required in the future the scheme
|
|
1014
|
+
* can be extended with a KEM layer at that point.
|
|
1015
|
+
*
|
|
1016
|
+
* On-chain storageId format (JSON):
|
|
1017
|
+
* Same envelope as off-chain payloads — handles arbitrary-length string IDs.
|
|
1018
|
+
* { ciphertext: base64, nonce: base64, algorithm: "XChaCha20-Poly1305" }
|
|
1019
|
+
*
|
|
1020
|
+
* Off-chain payload format (JSON):
|
|
1021
|
+
* { ciphertext: base64, nonce: base64, algorithm: "XChaCha20-Poly1305" }
|
|
1022
|
+
*/
|
|
1023
|
+
|
|
1024
|
+
/** Encrypted payload stored off-chain (Arweave, etc.). All binary fields are base64. */
|
|
1025
|
+
interface XChaChaPayload {
|
|
1026
|
+
/** base64 — XChaCha20-Poly1305 output: ciphertext || 16-byte Poly1305 tag */
|
|
1027
|
+
ciphertext: string;
|
|
1028
|
+
/** base64 — 24-byte random nonce */
|
|
1029
|
+
nonce: string;
|
|
1030
|
+
/** Algorithm identifier */
|
|
1031
|
+
algorithm: "XChaCha20-Poly1305";
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Derive a 32-byte symmetric key for XChaCha20-Poly1305 from arbitrary seed bytes.
|
|
1035
|
+
*
|
|
1036
|
+
* Uses HKDF-SHA-256 with a fixed global salt (domain separator) and a versioned,
|
|
1037
|
+
* context-bound `info` string per RFC 5869:
|
|
1038
|
+
* - `salt` = fixed application-level extraction key ("dstorage-xchacha-v1")
|
|
1039
|
+
* - `info` = versioned label, optionally binding a wallet address
|
|
1040
|
+
*
|
|
1041
|
+
* @param seed High-entropy seed bytes (wallet signature, BIP-39 seed, hex seed, etc.)
|
|
1042
|
+
* @param context Optional wallet address or other per-context binding value.
|
|
1043
|
+
* Incorporated into `info` to bind the derived key to a specific account.
|
|
1044
|
+
*/
|
|
1045
|
+
declare function deriveSymmetricKeyFromSeed(seed: Uint8Array, context?: string): Promise<Uint8Array>;
|
|
1046
|
+
/**
|
|
1047
|
+
* Encrypt arbitrary bytes with XChaCha20-Poly1305.
|
|
1048
|
+
*
|
|
1049
|
+
* Non-deterministic: fresh random 24-byte nonce per call.
|
|
1050
|
+
*
|
|
1051
|
+
* @param key 32-byte symmetric key from deriveSymmetricKeyFromSeed()
|
|
1052
|
+
* @param data Arbitrary plaintext bytes
|
|
1053
|
+
* @param aad Additional authenticated data bound to the ciphertext (recommended)
|
|
1054
|
+
*/
|
|
1055
|
+
declare function encryptXChaCha(key: Uint8Array, data: Uint8Array, aad?: Uint8Array): Promise<XChaChaPayload>;
|
|
1056
|
+
/**
|
|
1057
|
+
* Decrypt a payload produced by encryptXChaCha().
|
|
1058
|
+
* The `aad` must match exactly what was passed to encryptXChaCha() — the Poly1305
|
|
1059
|
+
* auth tag covers the AAD, so any mismatch causes decryption to throw.
|
|
1060
|
+
*
|
|
1061
|
+
* @param key 32-byte symmetric key (must match the key used to encrypt)
|
|
1062
|
+
* @param payload XChaChaPayload from encryptXChaCha()
|
|
1063
|
+
* @param aad Must match the AAD used during encryption
|
|
1064
|
+
* @throws If Poly1305 auth tag verification fails (wrong key, tampered data, or wrong AAD)
|
|
1065
|
+
*/
|
|
1066
|
+
declare function decryptXChaCha(key: Uint8Array, payload: XChaChaPayload, aad?: Uint8Array): Promise<Uint8Array>;
|
|
1067
|
+
/**
|
|
1068
|
+
* Encrypt a 32-byte storage ID for on-chain storage.
|
|
1069
|
+
*
|
|
1070
|
+
* Output is exactly 72 bytes: [ nonce(24) | ciphertext(32) | auth-tag(16) ].
|
|
1071
|
+
*
|
|
1072
|
+
* @param key 32-byte symmetric key from deriveSymmetricKeyFromSeed()
|
|
1073
|
+
* @param storageIdBytes Raw 32-byte storage ID
|
|
1074
|
+
*/
|
|
1075
|
+
declare function encryptStorageIdXChaCha(key: Uint8Array, storageIdBytes: Uint8Array): Promise<Uint8Array>;
|
|
1076
|
+
/**
|
|
1077
|
+
* Decrypt a storage ID previously encrypted with encryptStorageIdXChaCha().
|
|
1078
|
+
* Expects exactly 72 bytes.
|
|
1079
|
+
* Throws if the Poly1305 auth tag does not match (tamper-evident).
|
|
1080
|
+
*
|
|
1081
|
+
* @param key 32-byte symmetric key (must match encryption key)
|
|
1082
|
+
* @param encryptedBytes 72-byte on-chain payload
|
|
1083
|
+
*/
|
|
1084
|
+
declare function decryptStorageIdXChaCha(key: Uint8Array, encryptedBytes: Uint8Array): Promise<Uint8Array>;
|
|
1085
|
+
/**
|
|
1086
|
+
* Serialize an XChaChaPayload to a compact JSON string.
|
|
1087
|
+
* Safe to pass to off-chain storage APIs.
|
|
1088
|
+
*/
|
|
1089
|
+
declare function serializeXChaChaPayload(payload: XChaChaPayload): string;
|
|
1090
|
+
/**
|
|
1091
|
+
* Deserialize a JSON string back to an XChaChaPayload.
|
|
1092
|
+
* Returns null if the input is invalid or missing required fields.
|
|
1093
|
+
*/
|
|
1094
|
+
declare function deserializeXChaChaPayload(raw: string): XChaChaPayload | null;
|
|
1095
|
+
/** XChaCha20-Poly1305 scheme. Key derived via HKDF-SHA-256. */
|
|
1096
|
+
declare class XChaChaScheme implements CryptoScheme {
|
|
1097
|
+
readonly schemeName: "xchacha20poly1305-v1";
|
|
1098
|
+
private readonly key;
|
|
1099
|
+
private constructor();
|
|
1100
|
+
/**
|
|
1101
|
+
* Derive a 32-byte XChaCha20-Poly1305 key from seed bytes using HKDF-SHA-256.
|
|
1102
|
+
*
|
|
1103
|
+
* @param seed High-entropy seed bytes (wallet signature, BIP-39 seed, etc.)
|
|
1104
|
+
* @param context Optional wallet address or other binding context.
|
|
1105
|
+
* Incorporated into the HKDF salt to bind the key to a specific account.
|
|
1106
|
+
*/
|
|
1107
|
+
static create(seed: Uint8Array, context?: string): Promise<XChaChaScheme>;
|
|
1108
|
+
/**
|
|
1109
|
+
* Create a scheme instance from a pre-generated key (e.g. a random DEK).
|
|
1110
|
+
* Bypasses HKDF derivation — use when the key is already available.
|
|
1111
|
+
*
|
|
1112
|
+
* @param key 32-byte symmetric key
|
|
1113
|
+
*/
|
|
1114
|
+
static fromKey(key: Uint8Array): XChaChaScheme;
|
|
1115
|
+
encryptPayload(bytes: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
|
|
1116
|
+
decryptPayload(data: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
|
|
1117
|
+
encryptStorageId(storageId: string): Promise<string>;
|
|
1118
|
+
decryptStorageId(encryptedId: string): Promise<string>;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* @dstorage/crypto — keyEnvelope.ts
|
|
1123
|
+
*
|
|
1124
|
+
* Multi-key wrapping for Data Encryption Keys (DEKs).
|
|
1125
|
+
*
|
|
1126
|
+
* Each private upload generates a fresh random DEK, which is then wrapped
|
|
1127
|
+
* (encrypted) under a Key Encryption Key (KEK) derived from the wallet seed.
|
|
1128
|
+
* The wrapped DEK and its metadata are serialised as a JSON envelope and
|
|
1129
|
+
* stored on-chain in the `keyEnvelope` field of ReferenceEntry.
|
|
1130
|
+
*
|
|
1131
|
+
* This separates the encryption key (random, unique per upload) from the
|
|
1132
|
+
* key-protecting mechanism (wallet-bound), enabling future multi-recipient
|
|
1133
|
+
* access without re-encrypting stored data — just add another wrapper entry.
|
|
1134
|
+
*
|
|
1135
|
+
* Envelope schema (private uploads only — public uploads have no envelope):
|
|
1136
|
+
* {
|
|
1137
|
+
* "v": 1,
|
|
1138
|
+
* "wrappers": [
|
|
1139
|
+
* {
|
|
1140
|
+
* "wrapKeyName": "password", // identifies the wrapping key source
|
|
1141
|
+
* "algorithm": "xchacha20poly1305-v1",
|
|
1142
|
+
* "kekDerivation": "hkdf-sha256-v1",
|
|
1143
|
+
* "wrappedDek": "<base64url 96 chars>"
|
|
1144
|
+
* }
|
|
1145
|
+
* ]
|
|
1146
|
+
* }
|
|
1147
|
+
*
|
|
1148
|
+
* The ownerSecret for private uploads is derived deterministically from the wrapped DEK:
|
|
1149
|
+
* ownerSecret = HKDF-SHA256(ikm=DEK, salt=rawStorageId, info="dstorage:owner-secret:v1")
|
|
1150
|
+
* Any holder of a valid KEK can unwrap the DEK and re-derive the ownerSecret.
|
|
1151
|
+
*
|
|
1152
|
+
* `wrappedDek` binary layout (72 bytes):
|
|
1153
|
+
* [ nonce(24) | ciphertext(32) | auth-tag(16) ]
|
|
1154
|
+
* base64url-encoded → 96 chars — identical to the on-chain storageId layout.
|
|
1155
|
+
*/
|
|
1156
|
+
|
|
1157
|
+
interface KeyWrapper extends WrappedDekResult {
|
|
1158
|
+
/** Identifies the wrapping key source (e.g. "password", "mnemonic", "mlkem768"). */
|
|
1159
|
+
wrapKeyName: string;
|
|
1160
|
+
}
|
|
1161
|
+
interface KeyEnvelope {
|
|
1162
|
+
v: 1;
|
|
1163
|
+
/**
|
|
1164
|
+
* Wrappers for the data DEK (content encryption key). Always present in a valid envelope.
|
|
1165
|
+
* The ownerSecret for ownership proofs is derived from the same DEK:
|
|
1166
|
+
* ownerSecret = HKDF-SHA256(DEK, rawStorageId, "dstorage:owner-secret:v1")
|
|
1167
|
+
* Any holder of a valid KEK can unwrap the DEK and re-derive the ownerSecret.
|
|
1168
|
+
* Public uploads have no envelope (keyEnvelope = "").
|
|
1169
|
+
*/
|
|
1170
|
+
wrappers: [KeyWrapper, ...KeyWrapper[]];
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Generate a cryptographically random 32-byte Data Encryption Key.
|
|
1174
|
+
* Uses the platform CSPRNG (`crypto.getRandomValues`) — safe in both
|
|
1175
|
+
* browser and Node.js 19+.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function generateDek(): Uint8Array;
|
|
1178
|
+
/**
|
|
1179
|
+
* Derive a 32-byte Key Encryption Key from a non-extractable HKDF CryptoKey.
|
|
1180
|
+
*
|
|
1181
|
+
* Callers must import their raw seed bytes via `crypto.subtle.importKey("raw", seed,
|
|
1182
|
+
* "HKDF", false, ["deriveBits"])` before calling this function. Accepting only
|
|
1183
|
+
* CryptoKey enforces that raw key material is never held in a JS-accessible heap
|
|
1184
|
+
* variable at this call site.
|
|
1185
|
+
*
|
|
1186
|
+
* Uses the same salt as the data encryption key ("dstorage-xchacha-v1") but a
|
|
1187
|
+
* distinct info string ("dstorage:xchacha20poly1305:kek:v1") to domain-separate
|
|
1188
|
+
* the KEK from all other keys derived from the same seed.
|
|
1189
|
+
*
|
|
1190
|
+
* @param keyMaterial Non-extractable HKDF CryptoKey imported from the seed.
|
|
1191
|
+
* @param context Optional wallet address or other binding context, incorporated
|
|
1192
|
+
* into the info string to bind the KEK to a specific account.
|
|
1193
|
+
*/
|
|
1194
|
+
declare function deriveKek(keyMaterial: CryptoKey, context?: string): Promise<Uint8Array>;
|
|
1195
|
+
/**
|
|
1196
|
+
* Wrap (encrypt) a 32-byte DEK under a KEK using XChaCha20-Poly1305.
|
|
1197
|
+
*
|
|
1198
|
+
* Reuses the same 72-byte binary layout as on-chain storageId encryption:
|
|
1199
|
+
* [ nonce(24) | ciphertext(32) | auth-tag(16) ]
|
|
1200
|
+
* base64url-encoded → 96-char string.
|
|
1201
|
+
*
|
|
1202
|
+
* @param dek 32-byte Data Encryption Key to protect
|
|
1203
|
+
* @param kek 32-byte Key Encryption Key (from deriveKek())
|
|
1204
|
+
*/
|
|
1205
|
+
declare function wrapKey(dek: Uint8Array, kek: Uint8Array): Promise<string>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Unwrap (decrypt) a wrapped DEK string back to the original 32-byte DEK.
|
|
1208
|
+
*
|
|
1209
|
+
* @param wrappedDek base64url-encoded 96-char string from wrapKey()
|
|
1210
|
+
* @param kek 32-byte Key Encryption Key (from deriveKek())
|
|
1211
|
+
*/
|
|
1212
|
+
declare function unwrapKey(wrappedDek: string, kek: Uint8Array): Promise<Uint8Array>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Derive a 32-byte owner secret from the data DEK and the raw storage ID.
|
|
1215
|
+
*
|
|
1216
|
+
* Derivation: HKDF-SHA-256(ikm=dek, salt=rawStorageId, info=OWNER_SECRET_DOMAIN)
|
|
1217
|
+
*
|
|
1218
|
+
* Security properties:
|
|
1219
|
+
* - Post-quantum resistant: HKDF-SHA-256 is purely symmetric (no elliptic-curve math).
|
|
1220
|
+
* - One-way: the DEK cannot be recovered from the ownerSecret (HKDF preimage resistance).
|
|
1221
|
+
* - Key-separated: the ownerSecret cannot be used for data encryption.
|
|
1222
|
+
* - Per-upload unique: different DEK + storageId per upload → different ownerSecret.
|
|
1223
|
+
* - Derivable: any holder of a valid KEK can unwrap the DEK and re-derive the ownerSecret.
|
|
1224
|
+
*
|
|
1225
|
+
* @param ikm 32-byte key material (DEK for private uploads; KEK for public uploads)
|
|
1226
|
+
* @param rawStorageId Raw storage network ID bytes (e.g. Arweave txId encoded as UTF-8)
|
|
1227
|
+
* @param info HKDF info / domain separator (defaults to private-upload domain)
|
|
1228
|
+
*/
|
|
1229
|
+
declare function deriveOwnerSecret(ikm: Uint8Array, rawStorageId: Uint8Array, info?: string): Promise<Uint8Array>;
|
|
1230
|
+
/**
|
|
1231
|
+
* Build a v1 key envelope wrapping the data DEK under one or more KEKs.
|
|
1232
|
+
*
|
|
1233
|
+
* Each entry wraps the same random DEK under a different KEK (one per seed
|
|
1234
|
+
* provider), allowing any of the corresponding recipients to independently
|
|
1235
|
+
* decrypt the same content without re-encryption.
|
|
1236
|
+
*
|
|
1237
|
+
* The ownerSecret for ownership proofs is derived from the same DEK:
|
|
1238
|
+
* ownerSecret = HKDF-SHA256(DEK, rawStorageId, "dstorage:owner-secret:v1")
|
|
1239
|
+
* No separate ownership key is needed.
|
|
1240
|
+
*
|
|
1241
|
+
* @param wrappers Non-empty array of `{ wrappedDek, wrapKeyName }` pairs.
|
|
1242
|
+
* `wrappedDek` is the base64url-encoded output of wrapKey().
|
|
1243
|
+
* `wrapKeyName` is a caller-chosen label (e.g. "provider-0").
|
|
1244
|
+
*
|
|
1245
|
+
* @throws if `wrappers` is empty.
|
|
1246
|
+
*/
|
|
1247
|
+
declare function buildKeyEnvelope(wrappers: Array<KeyWrapper>): KeyEnvelope;
|
|
1248
|
+
/**
|
|
1249
|
+
* Serialise a KeyEnvelope to the JSON string stored on-chain.
|
|
1250
|
+
*/
|
|
1251
|
+
declare function serializeKeyEnvelope(envelope: KeyEnvelope): string;
|
|
1252
|
+
/**
|
|
1253
|
+
* Parse and validate a JSON string from the chain.
|
|
1254
|
+
* Returns null for empty strings or malformed / unrecognised envelopes.
|
|
1255
|
+
*/
|
|
1256
|
+
declare function parseKeyEnvelope(raw: string): KeyEnvelope | null;
|
|
1257
|
+
/**
|
|
1258
|
+
* Find a wrapper by its wrapKeyName. Returns null if not found.
|
|
1259
|
+
*/
|
|
1260
|
+
declare function findWrapper(envelope: KeyEnvelope, wrapKeyName: string): KeyWrapper | null;
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* @dstorage/crypto — mlkem.ts
|
|
1264
|
+
*
|
|
1265
|
+
* Post-quantum DEK wrapping via ML-KEM (CRYSTALS-Kyber, NIST FIPS 203).
|
|
1266
|
+
*
|
|
1267
|
+
* Hybrid encryption pattern:
|
|
1268
|
+
* wrapDek: ML-KEM encapsulate(PK) → sharedSecret → HKDF → KEK → XChaCha20 wraps DEK
|
|
1269
|
+
* unwrapDek: ML-KEM decapsulate(SK, ct) → sharedSecret → HKDF → KEK → XChaCha20 unwraps DEK
|
|
1270
|
+
*
|
|
1271
|
+
* This provides post-quantum confidentiality for the DEK:
|
|
1272
|
+
* - Only the holder of the Secret Key can recover the DEK.
|
|
1273
|
+
* - Encapsulation (upload) requires only the Public Key.
|
|
1274
|
+
* - A quantum computer cannot recover sharedSecret from the KEM ciphertext alone.
|
|
1275
|
+
*
|
|
1276
|
+
* Key sizes (variant mlkem768, NIST recommended):
|
|
1277
|
+
* Public key: 1184 bytes
|
|
1278
|
+
* Secret key: 2400 bytes
|
|
1279
|
+
* Ciphertext: 1088 bytes
|
|
1280
|
+
* Shared secret: 32 bytes
|
|
1281
|
+
*/
|
|
1282
|
+
|
|
1283
|
+
type MLKemVariant = "mlkem512" | "mlkem768" | "mlkem1024";
|
|
1284
|
+
/**
|
|
1285
|
+
* Generate a random ML-KEM keypair.
|
|
1286
|
+
*
|
|
1287
|
+
* @param variant ML-KEM variant. Default: "mlkem768" (NIST recommended, 192-bit security).
|
|
1288
|
+
*/
|
|
1289
|
+
declare function mlkemGenerateKeypair(variant?: MLKemVariant): {
|
|
1290
|
+
pk: Uint8Array;
|
|
1291
|
+
sk: Uint8Array;
|
|
1292
|
+
};
|
|
1293
|
+
/**
|
|
1294
|
+
* Generate a deterministic ML-KEM keypair from a 64-byte seed (d‖z, per FIPS 203).
|
|
1295
|
+
* The same seed always produces the same keypair.
|
|
1296
|
+
*
|
|
1297
|
+
* Requires exactly 64 bytes — derive via Web Crypto HKDF deriveBits (512 bits) before calling.
|
|
1298
|
+
*
|
|
1299
|
+
* @param seed64 64-byte seed material
|
|
1300
|
+
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
1301
|
+
*/
|
|
1302
|
+
declare function mlkemGenerateKeypairFromSeed(seed64: Uint8Array, variant?: MLKemVariant): {
|
|
1303
|
+
pk: Uint8Array;
|
|
1304
|
+
sk: Uint8Array;
|
|
1305
|
+
};
|
|
1306
|
+
/**
|
|
1307
|
+
* Wrap a DEK under a ML-KEM public key.
|
|
1308
|
+
*
|
|
1309
|
+
* Encapsulates a shared secret, derives a KEK from it via HKDF, then wraps
|
|
1310
|
+
* the DEK with the same XChaCha20-Poly1305 scheme used by symmetric providers.
|
|
1311
|
+
* The KEM ciphertext is stored alongside the wrapped DEK so the holder of the
|
|
1312
|
+
* secret key can reverse the process at retrieval time.
|
|
1313
|
+
*
|
|
1314
|
+
* @param dek 32-byte Data Encryption Key to protect
|
|
1315
|
+
* @param pk ML-KEM public key
|
|
1316
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
1317
|
+
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
1318
|
+
*/
|
|
1319
|
+
declare function mlkemWrapDek(dek: Uint8Array, pk: Uint8Array, context: string, variant?: MLKemVariant): Promise<WrappedDekResult>;
|
|
1320
|
+
/**
|
|
1321
|
+
* Unwrap a DEK from a ML-KEM wrapped DEK result.
|
|
1322
|
+
*
|
|
1323
|
+
* The ML-KEM variant is read from `data.algorithm` (e.g. "mlkem768-xchacha20poly1305-v1"),
|
|
1324
|
+
* so the caller does not need to supply it — the key envelope is self-describing.
|
|
1325
|
+
*
|
|
1326
|
+
* @param data WrappedDekResult containing algorithm, kemCiphertext, and wrappedDek
|
|
1327
|
+
* @param sk ML-KEM secret key
|
|
1328
|
+
* @param context Domain-separation string bound into the KEK derivation (must match
|
|
1329
|
+
* the value used to wrap)
|
|
1330
|
+
*/
|
|
1331
|
+
declare function mlkemUnwrapDek(data: WrappedDekResult, sk: Uint8Array, context: string): Promise<Uint8Array>;
|
|
1332
|
+
|
|
1333
|
+
/** BLAKE3 hash of `bytes`, returned as a raw 32-byte Uint8Array. */
|
|
1334
|
+
declare function computeBlake3(bytes: Uint8Array): Promise<Uint8Array>;
|
|
1335
|
+
/** BLAKE3 hash of `bytes`, returned as a 64-character lowercase hex string. */
|
|
1336
|
+
declare function computeBlake3Hex(bytes: Uint8Array): Promise<string>;
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* @dstorage/chain — adapters/midnightSimulator.ts
|
|
1340
|
+
*
|
|
1341
|
+
* Midnight chain adapter backed by DataRegistrySimulator — runs the real
|
|
1342
|
+
* DataRegistry Compact circuits in-process without requiring a live network,
|
|
1343
|
+
* proof server, indexer, or wallet.
|
|
1344
|
+
*
|
|
1345
|
+
* Ownership is enforced by the real circuit (ownerSecret/ownerCommitment).
|
|
1346
|
+
* RefIds are circuit-derived (not random UUIDs). State is per-instance (no
|
|
1347
|
+
* shared module-level Map).
|
|
1348
|
+
*
|
|
1349
|
+
* ⚠️ Not for production: not decentralised, not immutable.
|
|
1350
|
+
* Replace with the real MidnightChainAdapter for production use.
|
|
1351
|
+
*/
|
|
1352
|
+
|
|
1353
|
+
declare class MidnightSimulatorChainAdapter implements ChainAdapter {
|
|
1354
|
+
readonly name: ChainProviderName;
|
|
1355
|
+
readonly providerName: string;
|
|
1356
|
+
readonly paymentAdapter: PaymentAdapter;
|
|
1357
|
+
private readonly senderPk;
|
|
1358
|
+
private simulatorPromise;
|
|
1359
|
+
private readonly logger;
|
|
1360
|
+
private blockHeight;
|
|
1361
|
+
constructor(options?: {
|
|
1362
|
+
/**
|
|
1363
|
+
* Sender public key passed to the DataRegistrySimulator.
|
|
1364
|
+
* Affects Zswap local state only — does not influence DataRegistry circuit
|
|
1365
|
+
* ownership (which is controlled by ownerSecret).
|
|
1366
|
+
* Defaults to a fixed all-zeros test key.
|
|
1367
|
+
*/
|
|
1368
|
+
senderPk?: string;
|
|
1369
|
+
logger?: ChainAdapterLogger;
|
|
1370
|
+
} & ({
|
|
1371
|
+
signingServerUrl: string;
|
|
1372
|
+
authToken: string;
|
|
1373
|
+
} | {
|
|
1374
|
+
signingServerUrl?: never;
|
|
1375
|
+
authToken?: never;
|
|
1376
|
+
}));
|
|
1377
|
+
private getSimulator;
|
|
1378
|
+
estimateCost(): Promise<ChainQuote>;
|
|
1379
|
+
writeReference(ref: ChainReference): Promise<ChainWriteResult>;
|
|
1380
|
+
readReference(refId: string): Promise<ChainReference>;
|
|
1381
|
+
listReferences(): Promise<DataReferenceSummary[]>;
|
|
1382
|
+
removeReference(refId: string, ownerSecret?: Uint8Array): Promise<void>;
|
|
1383
|
+
updateReference(refId: string, update: ChainReferenceUpdate, ownerSecret?: Uint8Array, newOwnerSecret?: Uint8Array): Promise<void>;
|
|
1384
|
+
setContractAddress(_address: string): void;
|
|
1385
|
+
getContractAddress(): string;
|
|
1386
|
+
deployDataRegistry(): Promise<string>;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/**
|
|
1390
|
+
* @dstorage/chain — adapters/httpGateway.ts
|
|
1391
|
+
*
|
|
1392
|
+
* HTTP Gateway chain adapter — delegates reference storage to a remote REST
|
|
1393
|
+
* service. Useful for testing, staging environments, or custom backends that
|
|
1394
|
+
* expose a simple HTTP API instead of a blockchain node.
|
|
1395
|
+
*/
|
|
1396
|
+
|
|
1397
|
+
interface HttpGatewayChainAdapterConfig {
|
|
1398
|
+
/** Scheme + host (+ optional port) shared by all endpoints. e.g. "http://localhost:3200" */
|
|
1399
|
+
baseUrl: string;
|
|
1400
|
+
/** Path appended to baseUrl for write (POST /{refId}) and update operations. e.g. "/api/refs" */
|
|
1401
|
+
writePath: string;
|
|
1402
|
+
/** Path appended to baseUrl for read (GET /{refId}) operations. */
|
|
1403
|
+
readPath: string;
|
|
1404
|
+
/** Path appended to baseUrl for listReferences (GET) operations. */
|
|
1405
|
+
listPath: string;
|
|
1406
|
+
/** Path appended to baseUrl for removeReference (DELETE /{refId}) operations. */
|
|
1407
|
+
deletePath: string;
|
|
1408
|
+
/**
|
|
1409
|
+
* Optional headers included in every outgoing request.
|
|
1410
|
+
* Useful for API tokens, authorization, or any other fixed headers required by
|
|
1411
|
+
* the gateway. Example: `{ "Authorization": "Bearer mytoken", "X-Api-Key": "abc" }`
|
|
1412
|
+
*/
|
|
1413
|
+
headers?: Record<string, string>;
|
|
1414
|
+
/**
|
|
1415
|
+
* Optional custom fetch implementation. Useful when the gateway uses a custom CA
|
|
1416
|
+
* or client certificate: supply an undici Agent configured with the appropriate
|
|
1417
|
+
* `ca`, `cert`, and `key` options. Defaults to `globalThis.fetch` when omitted.
|
|
1418
|
+
*/
|
|
1419
|
+
customFetch?: typeof fetch;
|
|
1420
|
+
logger?: ChainAdapterLogger;
|
|
1421
|
+
}
|
|
1422
|
+
declare class HttpGatewayChainAdapter implements ChainAdapter {
|
|
1423
|
+
readonly name: ChainProviderName;
|
|
1424
|
+
readonly providerName = "HTTP-Gateway-Chain-Adapter";
|
|
1425
|
+
private readonly logger;
|
|
1426
|
+
private readonly fetchFn;
|
|
1427
|
+
private readonly extraHeaders;
|
|
1428
|
+
private readonly writeUrl;
|
|
1429
|
+
private readonly readUrl;
|
|
1430
|
+
private readonly listUrl;
|
|
1431
|
+
private readonly deleteUrl;
|
|
1432
|
+
constructor(config: HttpGatewayChainAdapterConfig);
|
|
1433
|
+
writeReference(ref: ChainReference): Promise<ChainWriteResult>;
|
|
1434
|
+
updateReference(refId: string, update: ChainReferenceUpdate, _ownerSecret?: Uint8Array, _newOwnerSecret?: Uint8Array): Promise<void>;
|
|
1435
|
+
readReference(refId: string): Promise<ChainReference>;
|
|
1436
|
+
listReferences(): Promise<DataReferenceSummary[]>;
|
|
1437
|
+
removeReference(refId: string, ownerSecret?: Uint8Array): Promise<void>;
|
|
1438
|
+
getContractAddress(): string;
|
|
1439
|
+
estimateCost(): Promise<ChainQuote>;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* Minimal interface the adapter requires from a wallet provider passed via
|
|
1444
|
+
* walletMode: "provider". Any object implementing WalletProvider and
|
|
1445
|
+
* MidnightProvider with an accessible WalletFacade satisfies this.
|
|
1446
|
+
*/
|
|
1447
|
+
interface AdapterWalletProvider extends WalletProvider, MidnightProvider {
|
|
1448
|
+
readonly wallet: WalletFacade;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* @dstorage/chain — adapters/midnight.ts
|
|
1453
|
+
*
|
|
1454
|
+
* Midnight Network chain adapter.
|
|
1455
|
+
*
|
|
1456
|
+
* Uses DataRegistryAPI (deployContract / findDeployedContract / callTx) from
|
|
1457
|
+
* @midnight-ntwrk/midnight-js-contracts via the api.ts wrapper, so that
|
|
1458
|
+
* midnight.ts only needs to manage the wallet lifecycle and provider assembly.
|
|
1459
|
+
*
|
|
1460
|
+
* Wallet lifecycle:
|
|
1461
|
+
* - 'provider': accepts a pre-built wallet provider (Node.js CLI)
|
|
1462
|
+
* - 'connector': connect to browser wallet extension (browser dApp)
|
|
1463
|
+
*
|
|
1464
|
+
* Transaction flow (handled by DataRegistryAPI internally):
|
|
1465
|
+
* 1. Build — construct the unproven circuit call
|
|
1466
|
+
* 2. Prove — send to proof server for ZK proof generation
|
|
1467
|
+
* 3. Balance — attach DUST fees via the connected wallet
|
|
1468
|
+
* 4. Submit — broadcast to the Midnight node
|
|
1469
|
+
* 5. Confirm — wait for block inclusion
|
|
1470
|
+
*
|
|
1471
|
+
* Docs: https://docs.midnight.network/develop/tutorial/building-a-dapp
|
|
1472
|
+
*/
|
|
1473
|
+
|
|
1474
|
+
interface WalletAddresses {
|
|
1475
|
+
unshielded: string;
|
|
1476
|
+
shielded: string;
|
|
1477
|
+
dust: string;
|
|
1478
|
+
}
|
|
1479
|
+
type SUPPORTED_NETWORKS = {
|
|
1480
|
+
[K in "preprod" | "undeployed"]: EnvironmentConfiguration;
|
|
1481
|
+
};
|
|
1482
|
+
declare const NETWORKS: SUPPORTED_NETWORKS;
|
|
1483
|
+
/** Internal environment configuration passed to wallet SDK providers. */
|
|
1484
|
+
interface EnvironmentConfiguration {
|
|
1485
|
+
networkId: string;
|
|
1486
|
+
nodeHttp: string;
|
|
1487
|
+
nodeWs: string;
|
|
1488
|
+
indexerHttp: string;
|
|
1489
|
+
indexerWs: string;
|
|
1490
|
+
proofServer: string;
|
|
1491
|
+
proofServerMaxRetries?: number;
|
|
1492
|
+
}
|
|
1493
|
+
interface BaseConfig {
|
|
1494
|
+
/**
|
|
1495
|
+
* Midnight node RPC endpoint.
|
|
1496
|
+
*/
|
|
1497
|
+
nodeEndpoint?: string;
|
|
1498
|
+
nodeWsEndpoint?: string;
|
|
1499
|
+
/**
|
|
1500
|
+
* Optional logger for SDK operational output.
|
|
1501
|
+
* Pass `logger: console` to see all output, or inject your own logger.
|
|
1502
|
+
* Omit to suppress all SDK log output.
|
|
1503
|
+
*/
|
|
1504
|
+
logger?: ChainAdapterLogger;
|
|
1505
|
+
/**
|
|
1506
|
+
* Midnight indexer HTTP (GraphQL) endpoint for state queries.
|
|
1507
|
+
*/
|
|
1508
|
+
indexerEndpoint?: string;
|
|
1509
|
+
/**
|
|
1510
|
+
* Midnight indexer WebSocket endpoint for real-time subscriptions.
|
|
1511
|
+
*/
|
|
1512
|
+
indexerWsEndpoint?: string;
|
|
1513
|
+
/**
|
|
1514
|
+
* Proof server URL.
|
|
1515
|
+
*/
|
|
1516
|
+
proofServerEndpoint: string;
|
|
1517
|
+
/**
|
|
1518
|
+
* Number of times to retry a proof-server circuit call on failure before
|
|
1519
|
+
* giving up. Uses exponential backoff (1 s, 2 s, 4 s, …).
|
|
1520
|
+
* Defaults to 3. Set to 1 to disable retries.
|
|
1521
|
+
*/
|
|
1522
|
+
proofServerMaxRetries?: number;
|
|
1523
|
+
/**
|
|
1524
|
+
* On-chain address of an already-deployed DataRegistry contract.
|
|
1525
|
+
* If omitted, sdk.init() will deploy a new contract and return its address.
|
|
1526
|
+
*/
|
|
1527
|
+
contractAddress?: string;
|
|
1528
|
+
/**
|
|
1529
|
+
* Target network. Controls wallet networkId, address format, and fee overhead.
|
|
1530
|
+
*/
|
|
1531
|
+
network: NetworkId;
|
|
1532
|
+
/**
|
|
1533
|
+
* Base URL of the dStorage managed payment signing server (no trailing slash).
|
|
1534
|
+
* When provided, transaction balancing is delegated to the server instead of
|
|
1535
|
+
* the local wallet.
|
|
1536
|
+
*/
|
|
1537
|
+
signingServerUrl?: string;
|
|
1538
|
+
/**
|
|
1539
|
+
* Bearer token sent as the `Authorization` header to authenticate with the signing server.
|
|
1540
|
+
* Required when `signingServerUrl` is provided.
|
|
1541
|
+
*/
|
|
1542
|
+
authToken?: string;
|
|
1543
|
+
}
|
|
1544
|
+
type MidnightChainAdapterConfig = BaseConfig & ({
|
|
1545
|
+
/**
|
|
1546
|
+
* Provider mode: the caller builds, starts, syncs, and passes in a wallet provider.
|
|
1547
|
+
* The adapter uses it directly without managing any wallet lifecycle.
|
|
1548
|
+
* Use this mode for Node.js CLI apps (e.g., the dStorage console demo).
|
|
1549
|
+
*/
|
|
1550
|
+
walletMode: "provider";
|
|
1551
|
+
/**
|
|
1552
|
+
* A fully initialised wallet provider (started and synced before passing in).
|
|
1553
|
+
* Must implement AdapterWalletProvider (WalletProvider + MidnightProvider + .wallet).
|
|
1554
|
+
*/
|
|
1555
|
+
walletProvider: AdapterWalletProvider;
|
|
1556
|
+
/**
|
|
1557
|
+
* LevelDB encryption password for the private state store.
|
|
1558
|
+
* Must satisfy the policy: at least 3 of 4 character classes
|
|
1559
|
+
* (uppercase, lowercase, digits, special characters).
|
|
1560
|
+
* Recommended derivation: "Aa1!" + seedHex (all 4 classes guaranteed).
|
|
1561
|
+
*/
|
|
1562
|
+
privateStatePassword: string;
|
|
1563
|
+
/**
|
|
1564
|
+
* Path to the directory that contains the compiled DataRegistry contract's ZK artifacts.
|
|
1565
|
+
* Expected sub-directories:
|
|
1566
|
+
* ${zkArtifactsPath}/keys/${circuitId}.prover
|
|
1567
|
+
* ${zkArtifactsPath}/keys/${circuitId}.verifier
|
|
1568
|
+
* ${zkArtifactsPath}/zkir/${circuitId}.bzkir
|
|
1569
|
+
*
|
|
1570
|
+
* Required for write operations (storeReference, etc.) in provider mode.
|
|
1571
|
+
*/
|
|
1572
|
+
zkArtifactsPath?: string;
|
|
1573
|
+
} | {
|
|
1574
|
+
/**
|
|
1575
|
+
* Browser wallet connector mode.
|
|
1576
|
+
* Delegates all key management to the wallet extension (e.g., Midnight Lace).
|
|
1577
|
+
*/
|
|
1578
|
+
walletMode: "connector";
|
|
1579
|
+
/**
|
|
1580
|
+
* Wallet connector name. Default: 'mnLace' (Midnight Lace).
|
|
1581
|
+
* Example: window.midnight.mnLace
|
|
1582
|
+
*/
|
|
1583
|
+
connectorName?: string;
|
|
1584
|
+
/**
|
|
1585
|
+
* Base URL from which the ZK artifacts for the DataRegistry contract are served.
|
|
1586
|
+
* Must be an absolute http/https URL.
|
|
1587
|
+
*
|
|
1588
|
+
* In Vite apps: copy the compiled contract's keys/ and zkir/ directories
|
|
1589
|
+
* to public/ and set this to window.location.origin.
|
|
1590
|
+
*
|
|
1591
|
+
* Required for write operations (storeReference, etc.) in connector mode.
|
|
1592
|
+
*/
|
|
1593
|
+
zkConfigBaseUrl?: string;
|
|
1594
|
+
/**
|
|
1595
|
+
* Allow a proof server URL supplied by the wallet extension to override
|
|
1596
|
+
* `proofServerEndpoint`. Default: `false`.
|
|
1597
|
+
*
|
|
1598
|
+
* When `false` (default): if the wallet returns a `proverServerUri` that differs
|
|
1599
|
+
* from the configured endpoint, it is logged as a warning and ignored — the
|
|
1600
|
+
* developer-configured endpoint is always used.
|
|
1601
|
+
*
|
|
1602
|
+
* Set to `true` only when you trust the connected wallet extension to supply a safe
|
|
1603
|
+
* proof server (e.g. Midnight Lace in a controlled deployment). A compromised wallet
|
|
1604
|
+
* extension can redirect ZK witness inputs — including the ownerSecret — to an
|
|
1605
|
+
* attacker-controlled server, allowing reference takeover or deletion.
|
|
1606
|
+
*/
|
|
1607
|
+
allowWalletProofServer?: boolean;
|
|
1608
|
+
});
|
|
1609
|
+
declare class MidnightChainAdapter implements ChainAdapter {
|
|
1610
|
+
readonly name: ChainProviderName;
|
|
1611
|
+
readonly providerName: string;
|
|
1612
|
+
readonly managedPaymentAdapter: ManagedPaymentAdapter | null;
|
|
1613
|
+
_lastPaymentReceipt: PaymentReceipt | undefined;
|
|
1614
|
+
private facade;
|
|
1615
|
+
private connectorAPI;
|
|
1616
|
+
private addresses;
|
|
1617
|
+
private connectorCoinPublicKey;
|
|
1618
|
+
private connectorEncPublicKey;
|
|
1619
|
+
private connectorIndexerHttp;
|
|
1620
|
+
private connectorIndexerWs;
|
|
1621
|
+
private connectorProofServer;
|
|
1622
|
+
private readonly walletMode;
|
|
1623
|
+
private readonly connectorName;
|
|
1624
|
+
private readonly allowWalletProofServer;
|
|
1625
|
+
private readonly logger;
|
|
1626
|
+
private _contractAddress;
|
|
1627
|
+
private _zkArtifactsPath;
|
|
1628
|
+
private _zkConfigBaseUrl;
|
|
1629
|
+
private _initialized;
|
|
1630
|
+
private _api;
|
|
1631
|
+
private _injectedWalletProvider;
|
|
1632
|
+
private _injectedPrivateStatePassword;
|
|
1633
|
+
private readonly config;
|
|
1634
|
+
constructor(config: MidnightChainAdapterConfig);
|
|
1635
|
+
/**
|
|
1636
|
+
* If a payment adapter was set, it delegates wallet provider wrapping to
|
|
1637
|
+
* the payment adapter, otherwise returns the provider unchanged (no wrapping needed).
|
|
1638
|
+
* When the managed payment adaper is set, It wraps the wallet provider's balanceTx()
|
|
1639
|
+
* to route transaction balancing through the managed signing server instead of the
|
|
1640
|
+
* local wallet. The server receives the hex-serialized UnboundTransaction,
|
|
1641
|
+
* balances and signs it, and returns the FinalizedTransaction in the receipt.
|
|
1642
|
+
*/
|
|
1643
|
+
private _withProofRetry;
|
|
1644
|
+
private _wrapPaymentProvider;
|
|
1645
|
+
/**
|
|
1646
|
+
* Build a mode-specific ZK config provider.
|
|
1647
|
+
*
|
|
1648
|
+
* Facade (Node.js): reads ZK artifact files from the local filesystem via zkArtifactsPath.
|
|
1649
|
+
* Connector (browser): fetches ZK artifacts over HTTP via zkConfigBaseUrl.
|
|
1650
|
+
*/
|
|
1651
|
+
private _buildZkConfigProvider;
|
|
1652
|
+
/**
|
|
1653
|
+
* midnight-js-contracts expects privateStateProvider.setContractAddress().
|
|
1654
|
+
* Some providers (e.g. in-memory) do not implement it, so we add a no-op shim.
|
|
1655
|
+
* Providers that already implement it (e.g. levelPrivateStateProvider) are left
|
|
1656
|
+
* untouched — their real implementation must run so the contract address is set
|
|
1657
|
+
* before any private state access.
|
|
1658
|
+
*/
|
|
1659
|
+
private _withContractAddressShim;
|
|
1660
|
+
/**
|
|
1661
|
+
* Assemble DataRegistryProviders from mode-specific pieces.
|
|
1662
|
+
*/
|
|
1663
|
+
private _assembleDataRegistryProviders;
|
|
1664
|
+
/**
|
|
1665
|
+
* Build providers for connector (browser) mode.
|
|
1666
|
+
* Uses in-memory private state, FetchZkConfigProvider, and the Lace wallet connector API.
|
|
1667
|
+
*/
|
|
1668
|
+
private _buildConnectorProviders;
|
|
1669
|
+
/**
|
|
1670
|
+
* Build DataRegistryProviders using a pre-built, already-started wallet provider.
|
|
1671
|
+
* The caller is responsible for wallet construction, sync, and fund-waiting before
|
|
1672
|
+
* passing the provider to the adapter via walletMode: "provider".
|
|
1673
|
+
*/
|
|
1674
|
+
private _buildWalletProviderMode;
|
|
1675
|
+
/**
|
|
1676
|
+
* Lazily initialize and return the DataRegistryAPI.
|
|
1677
|
+
* Joins the existing contract at the configured address.
|
|
1678
|
+
* Throws if no address is configured and no deployment has occurred.
|
|
1679
|
+
*/
|
|
1680
|
+
private _getAPI;
|
|
1681
|
+
/** Midnight contract addresses are 32 bytes encoded as 64 lowercase hex chars. */
|
|
1682
|
+
private static _validateContractAddress;
|
|
1683
|
+
/**
|
|
1684
|
+
* Set the contract address to use for subsequent operations.
|
|
1685
|
+
* Resets the cached DataRegistryAPI so the next call re-joins at the new address.
|
|
1686
|
+
*/
|
|
1687
|
+
setContractAddress(address: string): void;
|
|
1688
|
+
/**
|
|
1689
|
+
* Get the contract address
|
|
1690
|
+
*/
|
|
1691
|
+
getContractAddress(): string;
|
|
1692
|
+
/**
|
|
1693
|
+
* List references currently stored in the joined/deployed DataRegistry contract.
|
|
1694
|
+
* For Arweave references, storageId is the original txId string.
|
|
1695
|
+
* For other providers, storageId is the hex of the stored Bytes<32>.
|
|
1696
|
+
*/
|
|
1697
|
+
listReferences(): Promise<DataReferenceSummary[]>;
|
|
1698
|
+
/**
|
|
1699
|
+
* Look up a single reference by its refId.
|
|
1700
|
+
* Returns { storageId, storageProvider } with the storageId decoded to the
|
|
1701
|
+
* original storage network identifier (e.g. Arweave txId), or null if not found.
|
|
1702
|
+
*/
|
|
1703
|
+
readReference(refId: string): Promise<ChainReference>;
|
|
1704
|
+
estimateCost(): Promise<ChainQuote>;
|
|
1705
|
+
writeReference(ref: ChainReference): Promise<ChainWriteResult>;
|
|
1706
|
+
removeReference(refId: string, ownerSecret?: Uint8Array): Promise<void>;
|
|
1707
|
+
/**
|
|
1708
|
+
* Update the mutable fields of an existing reference.
|
|
1709
|
+
*
|
|
1710
|
+
* `update.storageId` is stored verbatim on-chain without format validation. Passing a
|
|
1711
|
+
* malformed storageId permanently bricks the reference (silent decryption failure on read).
|
|
1712
|
+
* Validate the format against the storage provider before calling this method.
|
|
1713
|
+
*/
|
|
1714
|
+
updateReference(refId: string, update: ChainReferenceUpdate, ownerSecret?: Uint8Array, newOwnerSecret?: Uint8Array): Promise<void>;
|
|
1715
|
+
/**
|
|
1716
|
+
* Initialize the wallet.
|
|
1717
|
+
* Branches based on wallet mode:
|
|
1718
|
+
* - 'facade': derive keys, build WalletFacade, wait for sync (Node.js CLI)
|
|
1719
|
+
* - 'connector': connect to browser wallet extension, extract addresses (browser dApp)
|
|
1720
|
+
*
|
|
1721
|
+
* Must be called before write operations or getBalances().
|
|
1722
|
+
* All Midnight wallet SDK imports are dynamic to avoid hard build-time failures.
|
|
1723
|
+
*/
|
|
1724
|
+
init(): Promise<string>;
|
|
1725
|
+
/**
|
|
1726
|
+
* Initialize in connector mode: connect to browser wallet extension.
|
|
1727
|
+
*
|
|
1728
|
+
* Discovers available wallets by enumerating window.midnight, as per the
|
|
1729
|
+
* dApp connector spec: https://docs.midnight.network/api-reference/dapp-connector
|
|
1730
|
+
*/
|
|
1731
|
+
private _initConnector;
|
|
1732
|
+
/**
|
|
1733
|
+
* Return wallet addresses derived during init().
|
|
1734
|
+
* Throws if init() not yet called.
|
|
1735
|
+
*/
|
|
1736
|
+
getAddresses(): WalletAddresses;
|
|
1737
|
+
/**
|
|
1738
|
+
* Read NIGHT and DUST balances.
|
|
1739
|
+
*/
|
|
1740
|
+
getBalances(): Promise<WalletBalances>;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* @dstorage/chain — adapters/midnight/sync.ts
|
|
1745
|
+
*
|
|
1746
|
+
* Wallet sync-waiting helper.
|
|
1747
|
+
*/
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Wait for a WalletFacade to report `isSynced`, falling back to the current
|
|
1751
|
+
* facade state after `timeoutMs`.
|
|
1752
|
+
*
|
|
1753
|
+
* `isSynced` (and `waitForSyncedState()`) gate on an internal `isConnected` flag
|
|
1754
|
+
* on the shielded/dust sub-wallets that only flips true once a non-empty batch of
|
|
1755
|
+
* events arrives from the indexer — on a quiet chain (idle Preprod, fresh
|
|
1756
|
+
* undeployed network) it can stay false forever even though the wallet has
|
|
1757
|
+
* genuinely caught up, so waiting on it unconditionally can hang indefinitely.
|
|
1758
|
+
*/
|
|
1759
|
+
declare function waitForFacadeSync(facade: Pick<WalletFacade, "state">, timeoutMs?: number): Promise<FacadeState>;
|
|
1760
|
+
|
|
1761
|
+
declare const EncryptionErrorCode: {
|
|
1762
|
+
readonly KEYPAIR_MISSING_SECRET_KEY: 13001;
|
|
1763
|
+
readonly MNEMONIC_TOO_SHORT: 13002;
|
|
1764
|
+
readonly PASSWORD_UNSUPPORTED_KDF: 13003;
|
|
1765
|
+
readonly PASSWORD_EMPTY_SALT: 13004;
|
|
1766
|
+
readonly PASSWORD_UNKNOWN_PRESET: 13005;
|
|
1767
|
+
readonly PASSWORD_TOO_SHORT: 13006;
|
|
1768
|
+
readonly PASSWORD_TOO_FEW_DISTINCT: 13007;
|
|
1769
|
+
readonly PASSWORD_SEQUENTIAL_RUN: 13008;
|
|
1770
|
+
readonly PASSWORD_KEYBOARD_WALK: 13009;
|
|
1771
|
+
readonly PASSWORD_ENTROPY_TOO_LOW: 13010;
|
|
1772
|
+
};
|
|
1773
|
+
type EncryptionErrorCode = (typeof EncryptionErrorCode)[keyof typeof EncryptionErrorCode];
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* @dstorage/encryption — types.ts
|
|
1777
|
+
*
|
|
1778
|
+
* The EncryptionAdapter interface: the unified abstraction for how the
|
|
1779
|
+
* dStorage SDK wraps and unwraps per-upload Data Encryption Keys (DEKs).
|
|
1780
|
+
*
|
|
1781
|
+
* Both symmetric (password, mnemonic) and asymmetric (ML-KEM) adapters implement
|
|
1782
|
+
* this interface, so the core SDK calls wrapDek/unwrapDek uniformly with no
|
|
1783
|
+
* knowledge of which algorithm is in use.
|
|
1784
|
+
*
|
|
1785
|
+
* The result of wrapDek() is stored as a KeyWrapper entry in the on-chain
|
|
1786
|
+
* KeyEnvelope. At retrieval time, the same result is passed back to unwrapDek()
|
|
1787
|
+
* to recover the DEK.
|
|
1788
|
+
*/
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Wraps and unwraps per-upload DEKs using adapter-specific key material.
|
|
1792
|
+
*
|
|
1793
|
+
* Implementations:
|
|
1794
|
+
* PasswordEncryptionAdapter — symmetric: scrypt → HKDF → KEK → XChaCha20
|
|
1795
|
+
* MnemonicEncryptionAdapter — symmetric: BIP-39 seed → HKDF → KEK → XChaCha20
|
|
1796
|
+
* KeypairEncryptionAdapter — asymmetric: ML-KEM encapsulate/decapsulate + HKDF + XChaCha20
|
|
1797
|
+
*/
|
|
1798
|
+
interface EncryptionAdapter {
|
|
1799
|
+
/** Stable identifier used as wrapKeyName in key envelopes. */
|
|
1800
|
+
readonly name: string;
|
|
1801
|
+
/**
|
|
1802
|
+
* Wrap a DEK under this adapter's key material.
|
|
1803
|
+
* Called once per upload, per adapter.
|
|
1804
|
+
*
|
|
1805
|
+
* @param dek 32-byte Data Encryption Key to protect
|
|
1806
|
+
* @returns WrappedDekResult to store in the on-chain key envelope
|
|
1807
|
+
*/
|
|
1808
|
+
wrapDek(dek: Uint8Array): Promise<WrappedDekResult>;
|
|
1809
|
+
/**
|
|
1810
|
+
* Unwrap a DEK from a previously wrapped result.
|
|
1811
|
+
* Called at retrieval time using the same result that wrapDek() returned.
|
|
1812
|
+
*
|
|
1813
|
+
* @param data WrappedDekResult from the on-chain key envelope
|
|
1814
|
+
* @returns 32-byte Data Encryption Key
|
|
1815
|
+
* @throws If the adapter's key material cannot decrypt the wrapped DEK
|
|
1816
|
+
*/
|
|
1817
|
+
unwrapDek(data: WrappedDekResult): Promise<Uint8Array>;
|
|
1818
|
+
/**
|
|
1819
|
+
* Zero any raw key bytes held by this adapter and mark it unusable.
|
|
1820
|
+
* Optional — only adapters holding raw byte arrays implement this.
|
|
1821
|
+
* Call after the adapter is no longer needed to minimise the window
|
|
1822
|
+
* during which secret key material sits in GC-reachable memory.
|
|
1823
|
+
*/
|
|
1824
|
+
destroy?(): void;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
declare class KeypairEncryptionAdapter implements EncryptionAdapter {
|
|
1828
|
+
readonly name: string;
|
|
1829
|
+
readonly publicKey: Uint8Array;
|
|
1830
|
+
private secretKey;
|
|
1831
|
+
private readonly variant;
|
|
1832
|
+
private readonly context;
|
|
1833
|
+
private constructor();
|
|
1834
|
+
/**
|
|
1835
|
+
* Upload-only adapter — holds only the Public Key.
|
|
1836
|
+
* wrapDek() works normally; unwrapDek() throws (no SK available).
|
|
1837
|
+
*/
|
|
1838
|
+
static fromPublicKey(pk: Uint8Array, context: string, variant?: MLKemVariant): KeypairEncryptionAdapter;
|
|
1839
|
+
/**
|
|
1840
|
+
* Full adapter — holds both Public Key and Secret Key.
|
|
1841
|
+
* Both wrapDek() and unwrapDek() work.
|
|
1842
|
+
*/
|
|
1843
|
+
static fromKeypair(pk: Uint8Array, sk: Uint8Array, context: string, variant?: MLKemVariant): KeypairEncryptionAdapter;
|
|
1844
|
+
/**
|
|
1845
|
+
* Generate a fresh random ML-KEM keypair.
|
|
1846
|
+
*
|
|
1847
|
+
* Returns the adapter (with both PK+SK) plus the raw keys so the caller
|
|
1848
|
+
* can persist the secret key and share the public key separately.
|
|
1849
|
+
*
|
|
1850
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
1851
|
+
* @param variant Default: "mlkem768".
|
|
1852
|
+
*/
|
|
1853
|
+
static generateKeypair(context: string, variant?: MLKemVariant): {
|
|
1854
|
+
adapter: KeypairEncryptionAdapter;
|
|
1855
|
+
publicKey: Uint8Array;
|
|
1856
|
+
secretKey: Uint8Array;
|
|
1857
|
+
};
|
|
1858
|
+
/**
|
|
1859
|
+
* Deterministically derive a ML-KEM keypair from a BIP-39 mnemonic phrase or hex seed.
|
|
1860
|
+
*
|
|
1861
|
+
* Delegates to MnemonicEncryptionAdapter.intoKeypairEncryptionAdapter() so all
|
|
1862
|
+
* mnemonic/seed handling lives in a single place.
|
|
1863
|
+
*
|
|
1864
|
+
* Same inputs + variant always produce the same keypair.
|
|
1865
|
+
*
|
|
1866
|
+
* `seedHex` may be either 32 bytes (64 hex chars) or 64 bytes (128 hex chars) —
|
|
1867
|
+
* both are expanded to the 64-byte ML-KEM seed via HKDF.
|
|
1868
|
+
*
|
|
1869
|
+
* @param input { mnemonic } (24-word BIP-39) or { seedHex } (32- or 64-byte hex)
|
|
1870
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
1871
|
+
* @param variant Default: "mlkem768"
|
|
1872
|
+
*/
|
|
1873
|
+
static fromMnemonic(input: {
|
|
1874
|
+
mnemonic?: string;
|
|
1875
|
+
seedHex?: string;
|
|
1876
|
+
}, context: string, variant?: MLKemVariant): Promise<KeypairEncryptionAdapter>;
|
|
1877
|
+
/**
|
|
1878
|
+
* Deterministically derive a ML-KEM keypair from a password and salt.
|
|
1879
|
+
*
|
|
1880
|
+
* Delegates to PasswordEncryptionAdapter.intoKeypairEncryptionAdapter() so all
|
|
1881
|
+
* password handling (scrypt params, entropy validation, 64-byte seed derivation)
|
|
1882
|
+
* lives in a single place.
|
|
1883
|
+
*
|
|
1884
|
+
* Same password + salt + variant always produces the same keypair.
|
|
1885
|
+
*
|
|
1886
|
+
* @param password User password (validated for entropy)
|
|
1887
|
+
* @param salt Domain salt — must not be empty
|
|
1888
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
1889
|
+
* @param variant Default: "mlkem768"
|
|
1890
|
+
* @param params Optional custom scrypt params
|
|
1891
|
+
*/
|
|
1892
|
+
static fromPassword(password: string, salt: string, context: string, variant?: MLKemVariant, params?: {
|
|
1893
|
+
N?: number;
|
|
1894
|
+
r?: number;
|
|
1895
|
+
p?: number;
|
|
1896
|
+
}): Promise<KeypairEncryptionAdapter>;
|
|
1897
|
+
/**
|
|
1898
|
+
* Zero the Secret Key bytes and mark this adapter as read-only.
|
|
1899
|
+
* Call when the adapter is no longer needed to minimise the window
|
|
1900
|
+
* during which raw ML-KEM key material sits in GC-reachable memory.
|
|
1901
|
+
* After destroy(), unwrapDek() will throw.
|
|
1902
|
+
*/
|
|
1903
|
+
destroy(): void;
|
|
1904
|
+
wrapDek(dek: Uint8Array): Promise<WrappedDekResult>;
|
|
1905
|
+
unwrapDek(data: WrappedDekResult): Promise<Uint8Array>;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
declare class MnemonicEncryptionAdapter implements EncryptionAdapter {
|
|
1909
|
+
readonly name = "mnemonic";
|
|
1910
|
+
/**
|
|
1911
|
+
* Non-extractable HKDF CryptoKey imported from the BIP-39 / hex seed.
|
|
1912
|
+
* Raw seed bytes are zeroed immediately after import.
|
|
1913
|
+
*/
|
|
1914
|
+
private readonly kekMaterialPromise;
|
|
1915
|
+
constructor(input: {
|
|
1916
|
+
mnemonic?: string;
|
|
1917
|
+
seedHex?: string;
|
|
1918
|
+
});
|
|
1919
|
+
wrapDek(dek: Uint8Array): Promise<WrappedDekResult>;
|
|
1920
|
+
unwrapDek({ wrappedDek }: WrappedDekResult): Promise<Uint8Array>;
|
|
1921
|
+
/**
|
|
1922
|
+
* Deterministically derive a ML-KEM keypair from this adapter's key material.
|
|
1923
|
+
*
|
|
1924
|
+
* Uses Web Crypto HKDF to derive a 64-byte ML-KEM seed from the stored
|
|
1925
|
+
* CryptoKey with info="dstorage:mlkem-seed:v1", domain-separated from the
|
|
1926
|
+
* symmetric KEK derivation path. The same derivation applies to all seed
|
|
1927
|
+
* types (mnemonic or hex), producing consistent, domain-separated keypairs.
|
|
1928
|
+
*
|
|
1929
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
1930
|
+
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
1931
|
+
*/
|
|
1932
|
+
intoKeypairEncryptionAdapter(context: string, variant?: MLKemVariant): Promise<KeypairEncryptionAdapter>;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
/**
|
|
1936
|
+
* Named scrypt parameter presets. Use these at construction time as a
|
|
1937
|
+
* convenience — they expand to concrete N/r/p values. For persistence,
|
|
1938
|
+
* always store the actual values from `getKdfParams()`, not the preset name.
|
|
1939
|
+
*
|
|
1940
|
+
* "v1" — N=131072, 128 MB, ~500ms–1s — OWASP-recommended minimum.
|
|
1941
|
+
* Use for all sensitive data (default).
|
|
1942
|
+
* "v1-lite" — N=65536, 64 MB, ~200–400ms — half the work factor of "v1".
|
|
1943
|
+
* An offline attacker needs half the resources to brute-force the
|
|
1944
|
+
* same password. Use only on memory-constrained devices (mobile,
|
|
1945
|
+
* low-RAM embedded). Prefer "v1" whenever the environment allows.
|
|
1946
|
+
*/
|
|
1947
|
+
declare const KDF_PRESETS: {
|
|
1948
|
+
readonly v1: {
|
|
1949
|
+
readonly N: 131072;
|
|
1950
|
+
readonly r: 8;
|
|
1951
|
+
readonly p: 1;
|
|
1952
|
+
};
|
|
1953
|
+
readonly "v1-lite": {
|
|
1954
|
+
readonly N: 65536;
|
|
1955
|
+
readonly r: 8;
|
|
1956
|
+
readonly p: 1;
|
|
1957
|
+
};
|
|
1958
|
+
};
|
|
1959
|
+
type KdfPreset = keyof typeof KDF_PRESETS;
|
|
1960
|
+
/**
|
|
1961
|
+
* The resolved scrypt parameters to store alongside encrypted data.
|
|
1962
|
+
* Interoperable: any scrypt implementation in any language can re-derive
|
|
1963
|
+
* the key from these values without knowledge of this SDK's preset names.
|
|
1964
|
+
*/
|
|
1965
|
+
interface StoredKdfParams {
|
|
1966
|
+
/** Always "scrypt" — identifies the KDF algorithm. */
|
|
1967
|
+
kdf: "scrypt";
|
|
1968
|
+
N: number;
|
|
1969
|
+
r: number;
|
|
1970
|
+
p: number;
|
|
1971
|
+
}
|
|
1972
|
+
interface PasswordEncryptionAdapterConfig {
|
|
1973
|
+
/** The user's password. Validated for entropy at construction time. */
|
|
1974
|
+
password: string;
|
|
1975
|
+
/**
|
|
1976
|
+
* Domain salt — REQUIRED, must not be empty.
|
|
1977
|
+
*
|
|
1978
|
+
* Recommended: an app-specific label combined with a per-user identifier,
|
|
1979
|
+
* e.g. `"myapp:v1:alice@example.com"` or `"myapp:v1:" + tenantId`.
|
|
1980
|
+
*
|
|
1981
|
+
* Using a string is convenient; it is UTF-8 encoded before use.
|
|
1982
|
+
* Pass a Uint8Array if you prefer raw bytes.
|
|
1983
|
+
*
|
|
1984
|
+
* Same password + same salt → same seed, forever. Different salts produce
|
|
1985
|
+
* independent seeds even for identical passwords.
|
|
1986
|
+
*/
|
|
1987
|
+
salt: string | Uint8Array;
|
|
1988
|
+
/**
|
|
1989
|
+
* Named scrypt preset. Controls N/r/p parameters.
|
|
1990
|
+
* Default: "v1" (N=131072, 128 MB, ~500ms–1s).
|
|
1991
|
+
*
|
|
1992
|
+
* Takes precedence over `params` when both are provided.
|
|
1993
|
+
* Preset names are convenience shorthands — use `getKdfParams()` to get
|
|
1994
|
+
* the actual values for storage.
|
|
1995
|
+
*/
|
|
1996
|
+
preset?: KdfPreset;
|
|
1997
|
+
/**
|
|
1998
|
+
* Custom scrypt parameters. Only used when `preset` is not provided.
|
|
1999
|
+
* Prefer `preset` for well-known configurations.
|
|
2000
|
+
*/
|
|
2001
|
+
params?: {
|
|
2002
|
+
N?: number;
|
|
2003
|
+
r?: number;
|
|
2004
|
+
p?: number;
|
|
2005
|
+
};
|
|
2006
|
+
/**
|
|
2007
|
+
* Minimum password length. Default: 12 characters.
|
|
2008
|
+
*/
|
|
2009
|
+
minPasswordLength?: number;
|
|
2010
|
+
/**
|
|
2011
|
+
* Minimum estimated entropy in bits (charset-based estimate). Default: 60 bits.
|
|
2012
|
+
*
|
|
2013
|
+
* The built-in estimator uses character pool size × length. It catches trivially
|
|
2014
|
+
* weak passwords but does not detect dictionary words. Use `additionalValidators`
|
|
2015
|
+
* for higher assurance.
|
|
2016
|
+
*/
|
|
2017
|
+
minEntropyBits?: number;
|
|
2018
|
+
/**
|
|
2019
|
+
* Optional additional password validator functions. Each receives the password
|
|
2020
|
+
* and should throw an Error with a helpful message if the password is rejected.
|
|
2021
|
+
* Run after the built-in checks. Useful for integrating zxcvbn or a blacklist.
|
|
2022
|
+
*
|
|
2023
|
+
* @example
|
|
2024
|
+
* additionalValidators: [(pw) => {
|
|
2025
|
+
* if (zxcvbn(pw).score < 3) throw new Error("Password is too common.");
|
|
2026
|
+
* }]
|
|
2027
|
+
*/
|
|
2028
|
+
additionalValidators?: Array<(password: string) => void>;
|
|
2029
|
+
}
|
|
2030
|
+
/** Config for `PasswordEncryptionAdapter.fromKdfParams()` — reconstructs from stored metadata. */
|
|
2031
|
+
interface FromKdfParamsConfig extends StoredKdfParams {
|
|
2032
|
+
password: string;
|
|
2033
|
+
salt: string | Uint8Array;
|
|
2034
|
+
minPasswordLength?: number;
|
|
2035
|
+
minEntropyBits?: number;
|
|
2036
|
+
additionalValidators?: Array<(password: string) => void>;
|
|
2037
|
+
}
|
|
2038
|
+
declare class PasswordEncryptionAdapter implements EncryptionAdapter {
|
|
2039
|
+
readonly name = "password";
|
|
2040
|
+
private readonly salt;
|
|
2041
|
+
private readonly N;
|
|
2042
|
+
private readonly r;
|
|
2043
|
+
private readonly p;
|
|
2044
|
+
/**
|
|
2045
|
+
* Non-extractable HKDF CryptoKey imported from the scrypt output.
|
|
2046
|
+
* The raw scrypt bytes are zeroed immediately after import; this handle is
|
|
2047
|
+
* the only in-memory representation of the secret from this point on.
|
|
2048
|
+
*/
|
|
2049
|
+
private readonly kekMaterialPromise;
|
|
2050
|
+
constructor(config: PasswordEncryptionAdapterConfig);
|
|
2051
|
+
/**
|
|
2052
|
+
* Reconstruct an adapter from parameters previously stored via `getKdfParams()`.
|
|
2053
|
+
* Use this when loading existing encrypted data — ensures the exact same N/r/p
|
|
2054
|
+
* are used regardless of what the current SDK defaults are.
|
|
2055
|
+
*
|
|
2056
|
+
* @example
|
|
2057
|
+
* const adapter = PasswordEncryptionAdapter.fromKdfParams({
|
|
2058
|
+
* password,
|
|
2059
|
+
* salt: meta.salt,
|
|
2060
|
+
* kdf: meta.kdf,
|
|
2061
|
+
* N: meta.N,
|
|
2062
|
+
* r: meta.r,
|
|
2063
|
+
* p: meta.p,
|
|
2064
|
+
* });
|
|
2065
|
+
*/
|
|
2066
|
+
static fromKdfParams(config: FromKdfParamsConfig): PasswordEncryptionAdapter;
|
|
2067
|
+
/**
|
|
2068
|
+
* Returns the resolved KDF parameters to store alongside encrypted data.
|
|
2069
|
+
*
|
|
2070
|
+
* These values are language- and SDK-agnostic: any scrypt implementation
|
|
2071
|
+
* can re-derive the key from `{ kdf, N, r, p }` + the original salt and
|
|
2072
|
+
* password, without any knowledge of this SDK's preset names.
|
|
2073
|
+
*
|
|
2074
|
+
* @example
|
|
2075
|
+
* const meta = {
|
|
2076
|
+
* ...adapter.getKdfParams(), // { kdf: "scrypt", N: 131072, r: 8, p: 1 }
|
|
2077
|
+
* salt: "myapp:alice@example.com",
|
|
2078
|
+
* };
|
|
2079
|
+
* await db.save({ encryptedData, meta });
|
|
2080
|
+
*/
|
|
2081
|
+
getKdfParams(): StoredKdfParams;
|
|
2082
|
+
wrapDek(dek: Uint8Array): Promise<WrappedDekResult>;
|
|
2083
|
+
unwrapDek({ wrappedDek }: WrappedDekResult): Promise<Uint8Array>;
|
|
2084
|
+
/**
|
|
2085
|
+
* Deterministically derive a ML-KEM keypair from this adapter's key material.
|
|
2086
|
+
*
|
|
2087
|
+
* Uses Web Crypto HKDF to derive a 64-byte ML-KEM seed from the stored
|
|
2088
|
+
* CryptoKey, domain-separated from the symmetric KEK derivation path with
|
|
2089
|
+
* info="dstorage:mlkem-seed:v1". This is equivalent to noble's
|
|
2090
|
+
* hkdf(sha256, scryptOutput, undefined, info, 64) but avoids materialising
|
|
2091
|
+
* the raw scrypt output in a JS-accessible variable.
|
|
2092
|
+
*
|
|
2093
|
+
* Same password + salt + variant always produces the same keypair.
|
|
2094
|
+
*
|
|
2095
|
+
* @param context Domain-separation string bound into the KEK derivation
|
|
2096
|
+
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
2097
|
+
*/
|
|
2098
|
+
intoKeypairEncryptionAdapter(context: string, variant?: MLKemVariant): Promise<KeypairEncryptionAdapter>;
|
|
2099
|
+
}
|
|
2100
|
+
/**
|
|
2101
|
+
* Generate a cryptographically random password suitable for use with
|
|
2102
|
+
* `PasswordEncryptionAdapter` when post-quantum-safe key derivation is required.
|
|
2103
|
+
*
|
|
2104
|
+
* Produces 32 random bytes (256 bits of real entropy) encoded as a 43-character
|
|
2105
|
+
* base64url string. When combined with `intoKeypairEncryptionAdapter()`, this
|
|
2106
|
+
* provides a fully recoverable path to ML-KEM 192-bit post-quantum security:
|
|
2107
|
+
* the password is the only secret needed to re-derive the same ML-KEM keypair
|
|
2108
|
+
* on any device, without storing the private key itself.
|
|
2109
|
+
*
|
|
2110
|
+
* @example
|
|
2111
|
+
* const password = generatePqsPassword(); // store this securely
|
|
2112
|
+
* const adapter = new PasswordEncryptionAdapter({ password, salt: "myapp:alice" });
|
|
2113
|
+
* const keypairAdapter = await adapter.intoKeypairEncryptionAdapter("myapp:v1");
|
|
2114
|
+
* await sdk.connect(keypairAdapter); // full 192-bit PQ security
|
|
2115
|
+
*/
|
|
2116
|
+
declare function generatePqsPassword(): string;
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* @dstorage/core — types.ts
|
|
2120
|
+
* Top-level types for the dStorage SDK public API.
|
|
2121
|
+
*/
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Minimal logger interface accepted by every SDK class.
|
|
2125
|
+
* Compatible with `console` — pass `logger: console` for zero-boilerplate logging.
|
|
2126
|
+
* Omit the field entirely to suppress all SDK output.
|
|
2127
|
+
*/
|
|
2128
|
+
interface Logger {
|
|
2129
|
+
log(component: string, msg: string): void;
|
|
2130
|
+
warn(component: string, msg: string): void;
|
|
2131
|
+
error(component: string, msg: string): void;
|
|
2132
|
+
debug?(component: string, msg: string): void;
|
|
2133
|
+
}
|
|
2134
|
+
/** Wallet connection info returned after connecting */
|
|
2135
|
+
interface WalletInfo {
|
|
2136
|
+
address: string;
|
|
2137
|
+
chainProvider: ChainProviderName;
|
|
2138
|
+
/** The raw signature (or PBKDF2 seed) used to derive the encryption key (kept in memory only) */
|
|
2139
|
+
_signatureHex: string;
|
|
2140
|
+
}
|
|
2141
|
+
/** Configuration passed to dStorage constructor */
|
|
2142
|
+
interface DStorageConfig {
|
|
2143
|
+
/** Storage adapter to use (MockStorageAdapter | ArweaveStorageAdapter | ...) */
|
|
2144
|
+
storageAdapter: StorageAdapter;
|
|
2145
|
+
/**
|
|
2146
|
+
* Chain adapter to use (MockChainAdapter | MidnightChainAdapter | ...).
|
|
2147
|
+
* When omitted the SDK operates in storage-only mode — uploads store to the
|
|
2148
|
+
* storage backend but no on-chain reference is written.
|
|
2149
|
+
*/
|
|
2150
|
+
chainAdapter?: ChainAdapter;
|
|
2151
|
+
/**
|
|
2152
|
+
* Encryption adapters that wrap and unwrap per-upload Data Encryption Keys (DEKs).
|
|
2153
|
+
* Each adapter produces an independent wrapped DEK; any of them can independently decrypt.
|
|
2154
|
+
*
|
|
2155
|
+
* Choose the adapter(s) preferred by the user:
|
|
2156
|
+
* PasswordEncryptionAdapter — scrypt-derived from a user password + salt
|
|
2157
|
+
* MnemonicEncryptionAdapter — BIP-39 mnemonic or hex seed (Node.js / facade mode)
|
|
2158
|
+
* KeypairEncryptionAdapter — post-quantum asymmetric (ML-KEM keypair)
|
|
2159
|
+
*
|
|
2160
|
+
* When omitted or empty, no encryption key is available and all uploaded data
|
|
2161
|
+
* will be stored as plaintext (public).
|
|
2162
|
+
*
|
|
2163
|
+
* @example
|
|
2164
|
+
* // Single adapter (most common)
|
|
2165
|
+
* encryptionAdapters: [new PasswordEncryptionAdapter({ password, salt })]
|
|
2166
|
+
*
|
|
2167
|
+
* @example
|
|
2168
|
+
* // Two adapters — data accessible by either password or mnemonic
|
|
2169
|
+
* encryptionAdapters: [
|
|
2170
|
+
* new PasswordEncryptionAdapter({ password, salt }),
|
|
2171
|
+
* new MnemonicEncryptionAdapter({ mnemonic }),
|
|
2172
|
+
* ]
|
|
2173
|
+
*/
|
|
2174
|
+
encryptionAdapters?: EncryptionAdapter[];
|
|
2175
|
+
/**
|
|
2176
|
+
* Optional logger for SDK operational output.
|
|
2177
|
+
* Pass `logger: console` to see all output, or inject your own logger.
|
|
2178
|
+
* Omit to suppress all SDK log output.
|
|
2179
|
+
*/
|
|
2180
|
+
logger?: Logger;
|
|
2181
|
+
}
|
|
2182
|
+
/**
|
|
2183
|
+
* Payload included in both `StorePartialError.recovery` and the `"stored"`
|
|
2184
|
+
* phase of `StoreProgress`. Contains enough information to retry a failed
|
|
2185
|
+
* chain write via `registerReference()` without re-uploading.
|
|
2186
|
+
*
|
|
2187
|
+
* `keyEnvelope` is the DEK encrypted under the user's KEK — safe to persist
|
|
2188
|
+
* (e.g. in localStorage or a database). It is `undefined` for public uploads
|
|
2189
|
+
* since their on-chain reference does not depend on a content DEK.
|
|
2190
|
+
*/
|
|
2191
|
+
interface StoreRecovery {
|
|
2192
|
+
storageId: string;
|
|
2193
|
+
/** Storage provider that holds the content — required by registerReference(). */
|
|
2194
|
+
storageProvider: StorageProviderName;
|
|
2195
|
+
keyEnvelope: string | undefined;
|
|
2196
|
+
/**
|
|
2197
|
+
* BLAKE3 hash of the ciphertext bytes stored at `storageId`, hex-encoded (64 chars).
|
|
2198
|
+
* Pass to `registerReference()` to preserve the on-chain integrity check on the recovered reference.
|
|
2199
|
+
*/
|
|
2200
|
+
contentHash?: string;
|
|
2201
|
+
}
|
|
2202
|
+
interface StoreProgress {
|
|
2203
|
+
phase: "encrypting" | "uploading" | "stored" | "finalizing";
|
|
2204
|
+
chunksUploaded: number;
|
|
2205
|
+
totalChunks: number;
|
|
2206
|
+
bytesUploaded: number;
|
|
2207
|
+
totalBytes: number;
|
|
2208
|
+
/**
|
|
2209
|
+
* Present when `phase === "stored"`. Fired after the storage write succeeds
|
|
2210
|
+
* and before the chain write begins — persist this to recover from a partial
|
|
2211
|
+
* failure without re-uploading.
|
|
2212
|
+
*/
|
|
2213
|
+
recovery?: StoreRecovery;
|
|
2214
|
+
}
|
|
2215
|
+
interface StoreOptions {
|
|
2216
|
+
/**
|
|
2217
|
+
* Unencrypted key/value tags forwarded to the storage layer (e.g. Arweave tx tags).
|
|
2218
|
+
* Never written on-chain.
|
|
2219
|
+
*/
|
|
2220
|
+
tags?: Record<string, string>;
|
|
2221
|
+
/**
|
|
2222
|
+
* Encrypted key/value metadata stored on-chain alongside the key envelope.
|
|
2223
|
+
* Encrypted with the content DEK — only holders of a valid KEK can read it.
|
|
2224
|
+
* Returned in `RetrieveResult.metadata` after decryption.
|
|
2225
|
+
* Not supported for public (`isPublic: true`) stores.
|
|
2226
|
+
*/
|
|
2227
|
+
metadata?: Record<string, string>;
|
|
2228
|
+
onProgress?: (progress: StoreProgress) => void;
|
|
2229
|
+
/** When true, content is stored unencrypted and the storageId is written on-chain as plaintext. */
|
|
2230
|
+
isPublic?: boolean;
|
|
2231
|
+
/**
|
|
2232
|
+
* Optional caller-supplied reference ID, forwarded to the chain adapter as
|
|
2233
|
+
* {@link ChainReference.refId}. Adapters that control their own ID generation
|
|
2234
|
+
* (e.g. mock, HTTP gateway) use this as the stored and returned identifier.
|
|
2235
|
+
* Adapters where the on-chain protocol determines the ID (e.g. Midnight)
|
|
2236
|
+
* ignore this field — the chain-assigned ID is returned instead.
|
|
2237
|
+
*/
|
|
2238
|
+
refId?: string;
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Aggregated cost estimate for a complete store operation.
|
|
2242
|
+
* Built from two quotes — one from the storage adapter and one from the chain adapter.
|
|
2243
|
+
*/
|
|
2244
|
+
interface CostEstimate {
|
|
2245
|
+
storageCost: {
|
|
2246
|
+
amount: string;
|
|
2247
|
+
token: TokenSymbol;
|
|
2248
|
+
};
|
|
2249
|
+
/** Chain cost. Undefined when no chain adapter is configured. */
|
|
2250
|
+
chainCost?: {
|
|
2251
|
+
amount: string;
|
|
2252
|
+
token: TokenSymbol;
|
|
2253
|
+
};
|
|
2254
|
+
/** File size in bytes */
|
|
2255
|
+
fileSizeBytes: number;
|
|
2256
|
+
}
|
|
2257
|
+
/** Result returned from dStorage.store() */
|
|
2258
|
+
interface StoreResult {
|
|
2259
|
+
/**
|
|
2260
|
+
* The primary on-chain reference ID.
|
|
2261
|
+
* Undefined when no chain adapter is configured (storage-only mode).
|
|
2262
|
+
*/
|
|
2263
|
+
chainRefId?: string;
|
|
2264
|
+
/** The storage network content ID */
|
|
2265
|
+
storageId: string;
|
|
2266
|
+
/** Storage provider used */
|
|
2267
|
+
storageProvider: StorageProviderName;
|
|
2268
|
+
/** Chain provider used. Undefined when no chain adapter is configured. */
|
|
2269
|
+
chainProvider?: ChainProviderName;
|
|
2270
|
+
/** Timestamp */
|
|
2271
|
+
uploadedAt: number;
|
|
2272
|
+
/**
|
|
2273
|
+
* Encryption algorithm used for the stored data and on-chain storageId.
|
|
2274
|
+
* "xchacha20poly1305-v1" for private (encrypted) stores.
|
|
2275
|
+
* Empty string ("") for public (unencrypted) stores.
|
|
2276
|
+
*/
|
|
2277
|
+
encryptionScheme: string;
|
|
2278
|
+
/**
|
|
2279
|
+
* Decryption scheme for the stored content.
|
|
2280
|
+
* Present only for private stores in storage-only mode (no chainAdapter).
|
|
2281
|
+
* In chain mode the scheme is recoverable from the on-chain key envelope instead.
|
|
2282
|
+
* Pass this back to retrieveByStorageId() to decrypt locally.
|
|
2283
|
+
*/
|
|
2284
|
+
cryptoScheme?: CryptoScheme;
|
|
2285
|
+
/** Estimated cost of the store operation */
|
|
2286
|
+
costEstimate: CostEstimate;
|
|
2287
|
+
}
|
|
2288
|
+
/** Options for dStorage.listReferences() */
|
|
2289
|
+
interface ListReferencesOptions {
|
|
2290
|
+
/** When provided, only references whose refId appears in this array are returned. */
|
|
2291
|
+
refIds?: string[];
|
|
2292
|
+
}
|
|
2293
|
+
/** Options for dStorage.registerReference() */
|
|
2294
|
+
interface RegisterReferenceOptions {
|
|
2295
|
+
/** The pre-existing storage network ID to register. Omit for metadata-only references. */
|
|
2296
|
+
storageId?: string;
|
|
2297
|
+
/**
|
|
2298
|
+
* Storage provider name recorded in the chain reference.
|
|
2299
|
+
* Defaults to the configured `storageAdapter.name`.
|
|
2300
|
+
*/
|
|
2301
|
+
storageProvider?: StorageProviderName;
|
|
2302
|
+
/**
|
|
2303
|
+
* Optional caller-supplied reference ID, forwarded to the chain adapter as
|
|
2304
|
+
* {@link ChainReference.refId}. Adapters that control their own ID generation
|
|
2305
|
+
* (e.g. mock, HTTP gateway) use this as the stored and returned identifier.
|
|
2306
|
+
* Adapters where the on-chain protocol determines the ID (e.g. Midnight)
|
|
2307
|
+
* ignore this field — the chain-assigned ID is returned instead.
|
|
2308
|
+
*/
|
|
2309
|
+
refId?: string;
|
|
2310
|
+
/**
|
|
2311
|
+
* Encrypted key/value metadata stored on-chain alongside the key envelope.
|
|
2312
|
+
* Encrypted with the content DEK — only holders of a valid KEK can read it.
|
|
2313
|
+
* Returned in `RetrieveResult.metadata` after decryption via retrieveByRefId().
|
|
2314
|
+
*/
|
|
2315
|
+
metadata?: Record<string, string>;
|
|
2316
|
+
/**
|
|
2317
|
+
* Recovery: the `keyEnvelope` from a `StorePartialError` (or from the
|
|
2318
|
+
* `"stored"` phase of `onProgress`). When provided, the DEK is unwrapped
|
|
2319
|
+
* from this envelope and used to encrypt the storageId and derive the
|
|
2320
|
+
* ownerSecret — producing a reference identical to what `store()` would have
|
|
2321
|
+
* written, without requiring a re-upload.
|
|
2322
|
+
*/
|
|
2323
|
+
keyEnvelope?: string;
|
|
2324
|
+
/**
|
|
2325
|
+
* BLAKE3 hash of the ciphertext bytes at `storageId`, hex-encoded (64 chars).
|
|
2326
|
+
* When passed from `StorePartialError.recovery.contentHash`, this ensures the
|
|
2327
|
+
* recovered reference carries the same on-chain hash as a normal `store()` write.
|
|
2328
|
+
*/
|
|
2329
|
+
contentHash?: string;
|
|
2330
|
+
}
|
|
2331
|
+
/** Result returned from dStorage.registerReference() */
|
|
2332
|
+
interface RegisterReferenceResult {
|
|
2333
|
+
/** The on-chain reference ID — use with retrieveByRefId(). */
|
|
2334
|
+
chainRefId: string;
|
|
2335
|
+
}
|
|
2336
|
+
/** Result returned from dStorage.update() */
|
|
2337
|
+
interface UpdateResult {
|
|
2338
|
+
/** Same refId as the input — updated in place. */
|
|
2339
|
+
chainRefId: string;
|
|
2340
|
+
/** StorageId of the newly stored content. */
|
|
2341
|
+
storageId: string;
|
|
2342
|
+
}
|
|
2343
|
+
/** Result returned from dStorage.retrieveByRefId() / retrieveByStorageId() */
|
|
2344
|
+
interface RetrieveResult {
|
|
2345
|
+
/** The raw decrypted bytes */
|
|
2346
|
+
bytes: Uint8Array;
|
|
2347
|
+
/** Decrypted on-chain metadata (empty when none was provided at upload time or when retrieved without a chain reference) */
|
|
2348
|
+
metadata: Record<string, string>;
|
|
2349
|
+
/** Unencrypted tags attached to the storage-layer upload (e.g. Arweave tx tags) */
|
|
2350
|
+
tags: Record<string, string>;
|
|
2351
|
+
}
|
|
2352
|
+
/** AAD for single-shot payload encryption (non-chunked user content). */
|
|
2353
|
+
declare const PAYLOAD_AAD: Uint8Array;
|
|
2354
|
+
/**
|
|
2355
|
+
* AAD for chunked manifest encryption.
|
|
2356
|
+
* Using a distinct label from PAYLOAD_AAD means a ciphertext produced for a
|
|
2357
|
+
* manifest cannot decrypt successfully under PAYLOAD_AAD and vice versa —
|
|
2358
|
+
* manifest detection is cryptographic, not based on JSON shape inspection.
|
|
2359
|
+
*/
|
|
2360
|
+
declare const MANIFEST_AAD: Uint8Array;
|
|
2361
|
+
/** AAD for encrypted on-chain metadata (stored in ChainReference.encryptedMetadata). */
|
|
2362
|
+
declare const METADATA_AAD: Uint8Array;
|
|
2363
|
+
/**
|
|
2364
|
+
* HKDF salt for ownerSecret derivation in metadata-only references (no storageId).
|
|
2365
|
+
* Using a fixed non-empty sentinel avoids RFC 5869's empty-salt substitution
|
|
2366
|
+
* (which silently substitutes zeros(32)) and creates a clear domain boundary
|
|
2367
|
+
* from normal-upload ownerSecrets whose salt is the plaintext storageId.
|
|
2368
|
+
*/
|
|
2369
|
+
declare const METADATA_ONLY_OWNER_SECRET_SALT: Uint8Array;
|
|
2370
|
+
/**
|
|
2371
|
+
* Per-chunk AAD that binds a ciphertext to its position in a chunked upload.
|
|
2372
|
+
* A malicious gateway swapping two chunks will produce an AEAD auth failure
|
|
2373
|
+
* because the stored AAD won't match the expected index.
|
|
2374
|
+
*/
|
|
2375
|
+
declare const chunkAad: (index: number, total: number) => Uint8Array;
|
|
2376
|
+
|
|
2377
|
+
/**
|
|
2378
|
+
* @dstorage/core — metaTx/types.ts
|
|
2379
|
+
*
|
|
2380
|
+
* All public interfaces and type aliases for the MetaTx orchestrator.
|
|
2381
|
+
*/
|
|
2382
|
+
|
|
2383
|
+
type MetaTxStepId = "estimate" | "encrypt" | "payment_storage" | "upload" | "chain_reference" | "complete";
|
|
2384
|
+
type MetaTxStepStatus = "pending" | "running" | "done" | "error";
|
|
2385
|
+
interface MetaTxStepState {
|
|
2386
|
+
id: MetaTxStepId;
|
|
2387
|
+
label: string;
|
|
2388
|
+
description: string;
|
|
2389
|
+
status: MetaTxStepStatus;
|
|
2390
|
+
/** Live detail message updated during the step */
|
|
2391
|
+
detail?: string;
|
|
2392
|
+
/** Duration in ms (set when done) */
|
|
2393
|
+
durationMs?: number;
|
|
2394
|
+
startedAt?: number;
|
|
2395
|
+
}
|
|
2396
|
+
interface MetaTxProgress {
|
|
2397
|
+
steps: MetaTxStepState[];
|
|
2398
|
+
currentStepId: MetaTxStepId | null;
|
|
2399
|
+
overallStatus: "idle" | "awaiting_confirmation" | "running" | "complete" | "error";
|
|
2400
|
+
/** Cost estimate — set after 'estimate' step completes */
|
|
2401
|
+
estimate?: CostEstimate;
|
|
2402
|
+
/** Final receipt — set when complete */
|
|
2403
|
+
receipt?: MetaTxReceipt;
|
|
2404
|
+
/** Error message if overallStatus is 'error' */
|
|
2405
|
+
error?: string;
|
|
2406
|
+
}
|
|
2407
|
+
interface MetaTxReceipt {
|
|
2408
|
+
dataId: string;
|
|
2409
|
+
storageId: string;
|
|
2410
|
+
/** Undefined when no chain adapter is configured (storage-only mode). */
|
|
2411
|
+
chainRefId?: string;
|
|
2412
|
+
/** Original file info */
|
|
2413
|
+
file: {
|
|
2414
|
+
name: string;
|
|
2415
|
+
type: string;
|
|
2416
|
+
sizeBytes: number;
|
|
2417
|
+
};
|
|
2418
|
+
/** Payment receipts */
|
|
2419
|
+
storagePayment: PaymentReceipt;
|
|
2420
|
+
/** Undefined when no chain adapter is configured. */
|
|
2421
|
+
chainPayment?: PaymentReceipt;
|
|
2422
|
+
/** Tokens used */
|
|
2423
|
+
storageToken: TokenSymbol;
|
|
2424
|
+
/** Undefined when no chain adapter is configured. */
|
|
2425
|
+
chainToken?: TokenSymbol;
|
|
2426
|
+
/** Contract invoked (if selected) */
|
|
2427
|
+
contract?: {
|
|
2428
|
+
address: string;
|
|
2429
|
+
name: string;
|
|
2430
|
+
};
|
|
2431
|
+
completedAt: number;
|
|
2432
|
+
/** Duration of the full meta-transaction in ms */
|
|
2433
|
+
totalDurationMs: number;
|
|
2434
|
+
}
|
|
2435
|
+
interface MetaTxConfig {
|
|
2436
|
+
/** Optional metadata to attach to the on-chain reference */
|
|
2437
|
+
metadata?: Record<string, string>;
|
|
2438
|
+
/** Selected contract address (from the contract registry) */
|
|
2439
|
+
contractAddress?: string;
|
|
2440
|
+
/** Selected contract name (for display / receipt) */
|
|
2441
|
+
contractName?: string;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Crypto materials for a single upload: a fresh random DEK wrapped in a
|
|
2445
|
+
* key envelope, ready to encrypt payload and storageId.
|
|
2446
|
+
*
|
|
2447
|
+
* For private uploads: uploadScheme encrypts content; dek is the per-upload
|
|
2448
|
+
* Data Encryption Key used both to encrypt content AND to derive
|
|
2449
|
+
* ownerSecret = HKDF(dek, rawStorageId). Any KEK holder can re-derive the
|
|
2450
|
+
* ownerSecret by unwrapping the envelope DEK.
|
|
2451
|
+
* For public uploads: uploadScheme is null; ownerSeed is a random secret wrapped
|
|
2452
|
+
* under every KEK in keyEnvelope, and ownerSecret = HKDF(ownerSeed, rawStorageId).
|
|
2453
|
+
* Any single KEK holder can re-derive the ownerSecret by unwrapping the envelope.
|
|
2454
|
+
*/
|
|
2455
|
+
interface UploadCrypto {
|
|
2456
|
+
/** XChaChaScheme built from a fresh random DEK. null for public uploads. */
|
|
2457
|
+
uploadScheme: CryptoScheme | null;
|
|
2458
|
+
/** JSON-encoded KeyEnvelope wrapping the DEK (private) or ownerSeed (public) under every KEK. */
|
|
2459
|
+
keyEnvelope: string;
|
|
2460
|
+
/** Encryption scheme identifier to record on-chain. "" for public uploads. */
|
|
2461
|
+
encryptionScheme: EncryptionScheme;
|
|
2462
|
+
/**
|
|
2463
|
+
* The raw per-upload DEK for private uploads; undefined for public uploads.
|
|
2464
|
+
* Used by MetaTx to derive ownerSecret = HKDF(dek, rawStorageId) after upload.
|
|
2465
|
+
* Not stored anywhere — must not be persisted.
|
|
2466
|
+
*/
|
|
2467
|
+
dek?: Uint8Array;
|
|
2468
|
+
/**
|
|
2469
|
+
* The raw ownerSeed for public uploads; undefined for private uploads.
|
|
2470
|
+
* Used by MetaTx to derive ownerSecret = HKDF(ownerSeed, rawStorageId) after upload.
|
|
2471
|
+
* Not stored anywhere — must not be persisted.
|
|
2472
|
+
*/
|
|
2473
|
+
ownerSeed?: Uint8Array;
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Minimal SDK surface required by MetaTx.
|
|
2477
|
+
* Implemented by DStorage — MetaTx receives the SDK instance directly
|
|
2478
|
+
* rather than individual adapters/keys/address to avoid redundant constructor args.
|
|
2479
|
+
*/
|
|
2480
|
+
interface DStorageContext {
|
|
2481
|
+
readonly storageAdapter: StorageAdapter;
|
|
2482
|
+
readonly chainAdapter: ChainAdapter | undefined;
|
|
2483
|
+
/** Wallet address of the connected user, or null if using init() / facade mode. */
|
|
2484
|
+
readonly connectedAddress: string | null;
|
|
2485
|
+
/**
|
|
2486
|
+
* Generate a fresh random DEK, wrap it under the KEK, and return the
|
|
2487
|
+
* upload crypto materials needed to encrypt payload and storageId.
|
|
2488
|
+
* @param isPublic Pass true to skip encryption (returns null scheme + no envelope).
|
|
2489
|
+
*/
|
|
2490
|
+
prepareUploadCrypto(isPublic?: boolean): Promise<UploadCrypto>;
|
|
2491
|
+
/** Estimate the full cost (storage + chain) for a given payload size. */
|
|
2492
|
+
estimateCost(sizeBytes: number): Promise<CostEstimate>;
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
/**
|
|
2496
|
+
* @dstorage/core — metaTx/utils.ts
|
|
2497
|
+
*
|
|
2498
|
+
* Helpers used internally by MetaTx and one exported utility.
|
|
2499
|
+
*/
|
|
2500
|
+
|
|
2501
|
+
/**
|
|
2502
|
+
* Return the default chain payment token for a given chain provider name.
|
|
2503
|
+
*/
|
|
2504
|
+
declare function defaultChainToken(chainProvider: string): TokenSymbol;
|
|
2505
|
+
|
|
2506
|
+
/**
|
|
2507
|
+
* @dstorage/core — metaTx/MetaTx.ts
|
|
2508
|
+
*
|
|
2509
|
+
* The MetaTx orchestrator.
|
|
2510
|
+
*
|
|
2511
|
+
* Presents a single conceptual action to the user while internally executing:
|
|
2512
|
+
* [0] Estimate → compute storage + chain costs
|
|
2513
|
+
* [1] Encrypt → XChaCha20-Poly1305 encrypt the file client-side
|
|
2514
|
+
* [2] PayStorage → simulate storage payment (AR / MOCK)
|
|
2515
|
+
* [3] Upload → upload encrypted blob to decentralised storage
|
|
2516
|
+
* [4] Reference → pay chain fee + write CID + metadata reference on-chain
|
|
2517
|
+
* [✓] Complete → return full receipt
|
|
2518
|
+
*
|
|
2519
|
+
* Usage:
|
|
2520
|
+
* const metaTx = new MetaTx(dStorage);
|
|
2521
|
+
* metaTx.onProgress((progress) => updateUI(progress));
|
|
2522
|
+
* const receipt = await metaTx.execute(file);
|
|
2523
|
+
*/
|
|
2524
|
+
|
|
2525
|
+
declare class MetaTx {
|
|
2526
|
+
private sdk;
|
|
2527
|
+
private progressCallback;
|
|
2528
|
+
private steps;
|
|
2529
|
+
private startedAt;
|
|
2530
|
+
constructor(sdk: DStorageContext);
|
|
2531
|
+
/** Register a progress listener. Called after every step state change. */
|
|
2532
|
+
onProgress(cb: (progress: MetaTxProgress) => void): this;
|
|
2533
|
+
execute(file: File, config?: MetaTxConfig): Promise<MetaTxReceipt>;
|
|
2534
|
+
private startStep;
|
|
2535
|
+
private updateStepDetail;
|
|
2536
|
+
private completeStep;
|
|
2537
|
+
private getStep;
|
|
2538
|
+
private emit;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
/**
|
|
2542
|
+
* @dstorage/core — dStorage.ts
|
|
2543
|
+
*
|
|
2544
|
+
* The main SDK class. Orchestrates:
|
|
2545
|
+
* 1. Encryption adapter key wrapping (@dstorage/encryption + @dstorage/crypto)
|
|
2546
|
+
* 2. Client-side encryption (@dstorage/crypto)
|
|
2547
|
+
* 3. Decentralised storage (@dstorage/storage)
|
|
2548
|
+
* 4. On-chain reference writing (@dstorage/chain)
|
|
2549
|
+
*
|
|
2550
|
+
* Developer API:
|
|
2551
|
+
* const ds = new DStorage(config);
|
|
2552
|
+
* await ds.init();
|
|
2553
|
+
* const { chainRefId, storageId } = await ds.store(new TextEncoder().encode("hello"));
|
|
2554
|
+
* const { bytes } = await ds.retrieveByRefId(chainRefId);
|
|
2555
|
+
* await ds.listReferences();
|
|
2556
|
+
* await ds.removeReference(chainRefId);
|
|
2557
|
+
*/
|
|
2558
|
+
|
|
2559
|
+
declare class DStorage implements DStorageContext {
|
|
2560
|
+
private config;
|
|
2561
|
+
private wallet;
|
|
2562
|
+
/** Encryption adapters — each wraps/unwraps per-upload DEKs using its own algorithm. */
|
|
2563
|
+
private _encryptionProviders;
|
|
2564
|
+
private _initialized;
|
|
2565
|
+
private readonly logger;
|
|
2566
|
+
constructor(config: DStorageConfig);
|
|
2567
|
+
get storageAdapter(): StorageAdapter;
|
|
2568
|
+
get chainAdapter(): ChainAdapter | undefined;
|
|
2569
|
+
/**
|
|
2570
|
+
* Initialize the SDK:
|
|
2571
|
+
* 1. Initialize the chain adapter wallet (if supported), and
|
|
2572
|
+
* deploy a new DataRegistry contract, or connect to an existing one.
|
|
2573
|
+
* 2. Derive an encryption key from the chain adapter's credentials (if supported).
|
|
2574
|
+
*
|
|
2575
|
+
* Returns the address of the DataRegistry contract in use.
|
|
2576
|
+
* Call this instead of connect() when using MidnightChainAdapter directly.
|
|
2577
|
+
*/
|
|
2578
|
+
init(): Promise<string | undefined>;
|
|
2579
|
+
/** Tear down active state and clear all in-memory key material. */
|
|
2580
|
+
destroy(): void;
|
|
2581
|
+
get isConnected(): boolean;
|
|
2582
|
+
get connectedAddress(): string | null;
|
|
2583
|
+
/**
|
|
2584
|
+
* Encrypt content client-side, store to decentralised storage,
|
|
2585
|
+
* and write a cryptographic reference on-chain.
|
|
2586
|
+
*
|
|
2587
|
+
* Files larger than CHUNK_SIZE (10 MB) are automatically split into chunks,
|
|
2588
|
+
* each encrypted and stored independently. A manifest file ties them together.
|
|
2589
|
+
* Only the manifest's storageId is written on-chain.
|
|
2590
|
+
*
|
|
2591
|
+
* @param bytes Uint8Array to store
|
|
2592
|
+
* @param options Optional StoreOptions (metadata, onProgress, isPublic, refId)
|
|
2593
|
+
* @returns StoreResult containing the chainRefId/storageId needed to retrieve later
|
|
2594
|
+
*/
|
|
2595
|
+
store(bytes: Uint8Array, options?: StoreOptions): Promise<StoreResult>;
|
|
2596
|
+
/**
|
|
2597
|
+
* Register a pre-existing storageId as a new on-chain reference.
|
|
2598
|
+
*
|
|
2599
|
+
* Use this when data has already been uploaded to the storage network by
|
|
2600
|
+
* other means (e.g. a third-party tool or a separate pipeline). The content
|
|
2601
|
+
* is not touched — only the chain reference is created.
|
|
2602
|
+
*
|
|
2603
|
+
* A fresh DEK is generated solely to encrypt the storageId and derive the
|
|
2604
|
+
* ownerSecret. The resulting reference round-trips through retrieveByRefId()
|
|
2605
|
+
* exactly like one created by store().
|
|
2606
|
+
*
|
|
2607
|
+
* Note: chunked manifests are not handled here. For large pre-existing
|
|
2608
|
+
* uploads already split into chunks, register the manifest storageId.
|
|
2609
|
+
*/
|
|
2610
|
+
registerReference(options?: RegisterReferenceOptions): Promise<RegisterReferenceResult>;
|
|
2611
|
+
/**
|
|
2612
|
+
* Store new content and update an existing on-chain reference in place.
|
|
2613
|
+
*
|
|
2614
|
+
* Ownership is proved by re-deriving the ownerSecret from the existing
|
|
2615
|
+
* reference — the same mechanism used by removeReference(). A fresh DEK is
|
|
2616
|
+
* generated for the new content; the previous version is not modified and remains
|
|
2617
|
+
* independently decryptable if the caller retained the old storageId.
|
|
2618
|
+
*
|
|
2619
|
+
* Note: chunking is not applied here. For large files use store() to get a
|
|
2620
|
+
* new chunked reference, then removeReference() on the old one.
|
|
2621
|
+
*
|
|
2622
|
+
* @param refId The chain reference to update (returned by a prior store/registerReference).
|
|
2623
|
+
* @param bytes New content to encrypt and store.
|
|
2624
|
+
* @param options Optional StoreOptions. isPublic is ignored.
|
|
2625
|
+
*/
|
|
2626
|
+
update(refId: string, bytes: Uint8Array, options?: StoreOptions): Promise<UpdateResult>;
|
|
2627
|
+
/**
|
|
2628
|
+
* Retry only the on-chain reference write after a failed `update()` call.
|
|
2629
|
+
*
|
|
2630
|
+
* Use this when `update()` throws a `StorePartialError` — meaning the new
|
|
2631
|
+
* content was stored successfully but the chain write failed. Call with the
|
|
2632
|
+
* `refId` you passed to `update()` and the `err.recovery` from the caught
|
|
2633
|
+
* error (or the `recovery` emitted via `onProgress` at phase `"stored"`).
|
|
2634
|
+
*
|
|
2635
|
+
* The new content is already in storage; this method re-derives all chain
|
|
2636
|
+
* write parameters from the recovery envelope without re-uploading.
|
|
2637
|
+
*/
|
|
2638
|
+
retryUpdate(refId: string, recovery: StoreRecovery): Promise<UpdateResult>;
|
|
2639
|
+
/**
|
|
2640
|
+
* Rotate the encryption adapters protecting an existing reference without
|
|
2641
|
+
* re-uploading the content.
|
|
2642
|
+
*
|
|
2643
|
+
* Useful when you want to:
|
|
2644
|
+
* - Change a password: configure [newPassword, mnemonic] and call rotateKeys().
|
|
2645
|
+
* The mnemonic unwraps the old DEK, the new envelope is wrapped under both
|
|
2646
|
+
* new adapters, and the old password wrapper is dropped.
|
|
2647
|
+
* - Add or remove adapters: any single adapter that matches a wrapper in the
|
|
2648
|
+
* existing key envelope can authorise the rotation. The resulting envelope
|
|
2649
|
+
* is wrapped under exactly the adapters currently configured on this SDK.
|
|
2650
|
+
*
|
|
2651
|
+
* The content in storage is not touched — only the on-chain key envelope is
|
|
2652
|
+
* updated. writtenAt is preserved to reflect the original upload time.
|
|
2653
|
+
*/
|
|
2654
|
+
rotateKeys(refId: string): Promise<void>;
|
|
2655
|
+
/**
|
|
2656
|
+
* Retrieve and decrypt data by its storageId.
|
|
2657
|
+
* Decryption happens locally — the SDK never sends plaintext anywhere.
|
|
2658
|
+
*
|
|
2659
|
+
* Automatically detects chunked manifests and reassembles the original file.
|
|
2660
|
+
*
|
|
2661
|
+
* @param storageId The storageId returned from store()
|
|
2662
|
+
*/
|
|
2663
|
+
retrieveByStorageId(storageId: string, dekScheme?: CryptoScheme, contentHash?: string): Promise<RetrieveResult>;
|
|
2664
|
+
/**
|
|
2665
|
+
* Unwrap the data DEK from a key envelope and return an XChaChaScheme built from it.
|
|
2666
|
+
* Throws if the KEK is not available or the envelope cannot be parsed.
|
|
2667
|
+
* Only valid for private uploads (envelope.wrappers must be present).
|
|
2668
|
+
*/
|
|
2669
|
+
private _getDekScheme;
|
|
2670
|
+
/**
|
|
2671
|
+
* Unwrap the raw DEK bytes from a key envelope using the available KEKs.
|
|
2672
|
+
* The ownerSecret for the reference can be re-derived as HKDF(dek, rawStorageId).
|
|
2673
|
+
* Throws if no wrapper matches any available KEK.
|
|
2674
|
+
*/
|
|
2675
|
+
private _unwrapDek;
|
|
2676
|
+
/**
|
|
2677
|
+
* Compute the ownerSecret for an existing on-chain reference.
|
|
2678
|
+
* Used by removeReference/updateReference to derive the ZK witness secret.
|
|
2679
|
+
*
|
|
2680
|
+
* Flow:
|
|
2681
|
+
* 1. Read the reference from chain to get keyEnvelope + storageId
|
|
2682
|
+
* 2. Unwrap the DEK from keyEnvelope using available KEKs
|
|
2683
|
+
* 3. Recover raw storageId (decrypt with DEK if private, plaintext if public)
|
|
2684
|
+
* 4. Return HKDF-SHA256(dek, rawStorageId) for private, or HKDF-SHA256(ownerSeed, rawStorageId) for public
|
|
2685
|
+
*/
|
|
2686
|
+
private _computeOwnerSecret;
|
|
2687
|
+
private _decryptAndReassemble;
|
|
2688
|
+
/**
|
|
2689
|
+
* Retrieve and decrypt data using only its on-chain reference ID.
|
|
2690
|
+
*
|
|
2691
|
+
* Flow:
|
|
2692
|
+
* 1. Look up the reference on-chain by refId to obtain the storage network ID.
|
|
2693
|
+
* 2. Fetch the blob from the storage network.
|
|
2694
|
+
* 3. Decrypt locally if an encryption key is available.
|
|
2695
|
+
*
|
|
2696
|
+
* Requires the chain adapter to implement readReference() (part of the
|
|
2697
|
+
* ChainAdapter interface — shared by MidnightChainAdapter, MockChainAdapter, etc.).
|
|
2698
|
+
*
|
|
2699
|
+
* @param refId The chainRefId returned from store()
|
|
2700
|
+
*/
|
|
2701
|
+
retrieveByRefId(refId: string): Promise<RetrieveResult>;
|
|
2702
|
+
/**
|
|
2703
|
+
* List references currently available from the configured chain adapter.
|
|
2704
|
+
*/
|
|
2705
|
+
listReferences(options?: ListReferencesOptions): Promise<DataReferenceSummary[]>;
|
|
2706
|
+
/**
|
|
2707
|
+
* Remove a reference from the on-chain registry.
|
|
2708
|
+
* Only the owner of the reference can successfully call this — the chain
|
|
2709
|
+
* enforces ownership via ZK proof using the witness-derived ownerSecret.
|
|
2710
|
+
*/
|
|
2711
|
+
removeReference(refId: string): Promise<void>;
|
|
2712
|
+
/**
|
|
2713
|
+
* Estimate the full cost (storage + chain) for a given payload size before committing.
|
|
2714
|
+
*/
|
|
2715
|
+
estimateCost(sizeBytes: number): Promise<CostEstimate>;
|
|
2716
|
+
/**
|
|
2717
|
+
* Execute a full meta-transaction for a file:
|
|
2718
|
+
* estimate → encrypt → pay storage → upload → pay chain → write reference
|
|
2719
|
+
*
|
|
2720
|
+
* Presents the entire flow as a single action with step-by-step progress.
|
|
2721
|
+
*
|
|
2722
|
+
* @param file The File to encrypt and store
|
|
2723
|
+
* @param onProgress Callback fired on every step state change
|
|
2724
|
+
* @param config Optional token overrides and metadata
|
|
2725
|
+
*/
|
|
2726
|
+
executeMetaTransaction(file: File, onProgress: (progress: MetaTxProgress) => void, config?: MetaTxConfig): Promise<MetaTxReceipt>;
|
|
2727
|
+
/**
|
|
2728
|
+
* Generate a fresh random DEK, wrap it under the KEK(s), and return the crypto
|
|
2729
|
+
* materials needed by MetaTx to encrypt payload and storageId.
|
|
2730
|
+
*
|
|
2731
|
+
* For private stores: the DEK is wrapped under every available KEK. The ownerSecret
|
|
2732
|
+
* can later be re-derived as HKDF(dek, rawStorageId) by any KEK holder.
|
|
2733
|
+
* For public stores: a random ownerSeed is generated and wrapped under all KEKs (same pattern).
|
|
2734
|
+
*/
|
|
2735
|
+
prepareUploadCrypto(isPublic?: boolean): Promise<UploadCrypto>;
|
|
2736
|
+
/**
|
|
2737
|
+
* Upload large content by splitting into CHUNK_SIZE pieces, encrypting each
|
|
2738
|
+
* independently, and storing a manifest that ties them together.
|
|
2739
|
+
* Only the manifest's storageId is written on-chain.
|
|
2740
|
+
*/
|
|
2741
|
+
private _uploadChunked;
|
|
2742
|
+
/**
|
|
2743
|
+
* Reassemble a chunked file from its manifest.
|
|
2744
|
+
* Fetches and decrypts each chunk sequentially to bound memory usage.
|
|
2745
|
+
*/
|
|
2746
|
+
private _retrieveChunked;
|
|
2747
|
+
private assertConnected;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
/**
|
|
2751
|
+
* @dstorage/core — chunked.ts
|
|
2752
|
+
*
|
|
2753
|
+
* Defines the manifest shape and helpers for large-file (chunked) uploads.
|
|
2754
|
+
* SDK-level chunking splits files into CHUNK_SIZE pieces before encryption,
|
|
2755
|
+
* bounding peak memory usage to ~2× the chunk size regardless of file size.
|
|
2756
|
+
*/
|
|
2757
|
+
|
|
2758
|
+
/**
|
|
2759
|
+
* Nominal SDK chunk size: 10 MB per piece.
|
|
2760
|
+
*
|
|
2761
|
+
* Each chunk becomes one independent Arweave transaction, so larger chunks
|
|
2762
|
+
* mean fewer transactions and therefore less total base-fee overhead.
|
|
2763
|
+
* 10 MB sits comfortably below the arweave.net gateway POST limit (~12 MB)
|
|
2764
|
+
* while halving transaction count compared to 5 MB.
|
|
2765
|
+
*
|
|
2766
|
+
* The Arweave adapter uses getUploader() which sends each transaction's data
|
|
2767
|
+
* in 256 KB network slices, so 10 MB chunks upload reliably without hitting
|
|
2768
|
+
* any HTTP body size limit.
|
|
2769
|
+
*/
|
|
2770
|
+
declare const CHUNK_SIZE: number;
|
|
2771
|
+
interface ChunkEntry {
|
|
2772
|
+
index: number;
|
|
2773
|
+
storageId: string;
|
|
2774
|
+
/** Actual byte count in this chunk (last chunk may be smaller). */
|
|
2775
|
+
size: number;
|
|
2776
|
+
}
|
|
2777
|
+
interface ChunkManifest {
|
|
2778
|
+
v: 1;
|
|
2779
|
+
type: "dstorage-chunked-manifest";
|
|
2780
|
+
totalSize: number;
|
|
2781
|
+
chunkSize: number;
|
|
2782
|
+
chunkCount: number;
|
|
2783
|
+
provider: StorageProviderName;
|
|
2784
|
+
chunks: ChunkEntry[];
|
|
2785
|
+
}
|
|
2786
|
+
declare function isManifest(payload: unknown): payload is ChunkManifest;
|
|
2787
|
+
|
|
2788
|
+
declare const CoreErrorCode: {
|
|
2789
|
+
readonly METADATA_WITH_PUBLIC_UPLOAD: 10001;
|
|
2790
|
+
readonly UPLOAD_NO_PROVIDERS: 10002;
|
|
2791
|
+
readonly PUBLIC_UPLOAD_REQUIRES_SEED_PROVIDER: 10003;
|
|
2792
|
+
readonly CHAIN_WRITE_FAILED: 10004;
|
|
2793
|
+
readonly REGISTER_REF_REQUIRES_CHAIN: 10010;
|
|
2794
|
+
readonly REGISTER_REF_REQUIRES_ENCRYPTION: 10011;
|
|
2795
|
+
readonly UPDATE_UPLOAD_REQUIRES_CHAIN: 10020;
|
|
2796
|
+
readonly UPDATE_UPLOAD_NOT_SUPPORTED: 10021;
|
|
2797
|
+
readonly UPDATE_UPLOAD_REQUIRES_ENCRYPTION: 10022;
|
|
2798
|
+
readonly ROTATE_KEYS_REQUIRES_CHAIN: 10023;
|
|
2799
|
+
readonly ROTATE_KEYS_NOT_SUPPORTED: 10024;
|
|
2800
|
+
readonly ROTATE_KEYS_REQUIRES_ENCRYPTION: 10025;
|
|
2801
|
+
readonly DECRYPT_NO_PROVIDERS: 10030;
|
|
2802
|
+
readonly DECRYPT_ENVELOPE_EMPTY: 10031;
|
|
2803
|
+
readonly DECRYPT_ENVELOPE_MALFORMED: 10032;
|
|
2804
|
+
readonly DECRYPT_NO_WRAPPER_MATCHED: 10033;
|
|
2805
|
+
readonly UNWRAP_DEK_NO_PROVIDERS: 10034;
|
|
2806
|
+
readonly UNWRAP_DEK_ENVELOPE_EMPTY: 10035;
|
|
2807
|
+
readonly UNWRAP_DEK_ENVELOPE_MALFORMED: 10036;
|
|
2808
|
+
readonly UNWRAP_DEK_NO_WRAPPER_MATCHED: 10037;
|
|
2809
|
+
readonly DECRYPT_PAYLOAD_FAILED: 10038;
|
|
2810
|
+
readonly RETRIEVE_BY_REF_ID_REQUIRES_CHAIN: 10050;
|
|
2811
|
+
readonly REF_NOT_FOUND: 10051;
|
|
2812
|
+
readonly STORAGE_ADAPTER_MISMATCH: 10052;
|
|
2813
|
+
readonly RETRIEVE_BY_REF_ID_ENVELOPE_EMPTY: 10053;
|
|
2814
|
+
readonly CONTENT_HASH_MISMATCH: 10054;
|
|
2815
|
+
readonly LIST_REFS_REQUIRES_CHAIN: 10060;
|
|
2816
|
+
readonly LIST_REFS_NOT_SUPPORTED: 10061;
|
|
2817
|
+
readonly REMOVE_REF_REQUIRES_CHAIN: 10070;
|
|
2818
|
+
readonly REMOVE_REF_NOT_SUPPORTED: 10071;
|
|
2819
|
+
readonly META_TX_REQUIRES_ENCRYPTION: 10080;
|
|
2820
|
+
readonly PREPARE_UPLOAD_NO_PROVIDERS: 10081;
|
|
2821
|
+
readonly MANIFEST_INVALID_STRUCTURE: 10090;
|
|
2822
|
+
readonly MANIFEST_CHUNK_COUNT_MISMATCH: 10091;
|
|
2823
|
+
readonly MANIFEST_NOT_CONTIGUOUS: 10092;
|
|
2824
|
+
readonly DECRYPT_CHUNK_FAILED: 10093;
|
|
2825
|
+
readonly CHUNK_OVERFLOWS_TOTAL_SIZE: 10094;
|
|
2826
|
+
readonly REASSEMBLY_SIZE_MISMATCH: 10095;
|
|
2827
|
+
readonly NOT_INITIALIZED: 10100;
|
|
2828
|
+
readonly META_TX_UNKNOWN_STEP: 10200;
|
|
2829
|
+
readonly UNKNOWN_ERROR: 10999;
|
|
2830
|
+
};
|
|
2831
|
+
type CoreErrorCode = (typeof CoreErrorCode)[keyof typeof CoreErrorCode];
|
|
2832
|
+
/**
|
|
2833
|
+
* Thrown when `store()` succeeds at the storage layer but fails to write the
|
|
2834
|
+
* on-chain reference. The content is permanently on the storage network — use
|
|
2835
|
+
* `err.recovery` with `registerReference()` to retry only the chain write.
|
|
2836
|
+
*/
|
|
2837
|
+
declare class StorePartialError extends DStorageError {
|
|
2838
|
+
readonly recovery: StoreRecovery;
|
|
2839
|
+
constructor(recovery: StoreRecovery);
|
|
2840
|
+
}
|
|
2841
|
+
declare function isStorePartialError(err: unknown): err is StorePartialError;
|
|
2842
|
+
|
|
2843
|
+
export { ARWEAVE_LOCAL, type AdapterWalletProvider, type ArweaveBundlerAdapterConfig, ArweaveBundlerStorageAdapter, type ArweaveLocalAdapterConfig, type ArweaveLocalBalance, ArweaveLocalError, ArweaveLocalHelper, type ArweaveLocalHelperConfig, type ArweaveLocalInfo, ArweaveLocalStorageAdapter, ArweavePaymentAdapter, ArweaveStorageAdapter, CHUNK_SIZE, type ChunkEntry, type ChunkManifest, CoreErrorCode, type CostEstimate, CryptoErrorCode, type CryptoScheme, DStorage, type DStorageConfig, type DStorageContext, DStorageError, type EncryptionAdapter, EncryptionErrorCode, type EncryptionScheme, type FromKdfParamsConfig, HttpGatewayChainAdapter, type HttpGatewayChainAdapterConfig, KDF_PRESETS, type KdfPreset, KeyDeriver, type KeyEnvelope, type KeyWrapper, KeypairEncryptionAdapter, type ListReferencesOptions, type Logger, MANIFEST_AAD, METADATA_AAD, METADATA_ONLY_OWNER_SECRET_SALT, type MLKemVariant, ManagedPaymentAdapter, MetaTx, type MetaTxConfig, type MetaTxProgress, type MetaTxReceipt, type MetaTxStepId, type MetaTxStepState, type MetaTxStepStatus, MidnightChainAdapter, type MidnightChainAdapterConfig, MidnightSimulatorChainAdapter, MnemonicEncryptionAdapter, NETWORKS, PAYLOAD_AAD, PasswordEncryptionAdapter, type PasswordEncryptionAdapterConfig, type RegisterReferenceOptions, type RegisterReferenceResult, type RetrieveResult, type StoreOptions, StorePartialError, type StoreProgress, type StoreRecovery, type StoreResult, type StoredKdfParams, type UpdateResult, type UploadCrypto, type WalletAddresses, type WalletInfo, type WrappedDekResult, type XChaChaPayload, XChaChaScheme, arlocalGateway, base64urlToBytes, buildKeyEnvelope, bytesToBase64url, chunkAad, computeBlake3, computeBlake3Hex, decryptStorageIdXChaCha, decryptXChaCha, defaultChainToken, deriveKek, deriveOwnerSecret, deriveSymmetricKeyFromSeed, deserializeXChaChaPayload, encryptStorageIdXChaCha, encryptXChaCha, findWrapper, generateDek, generatePqsPassword, hexToBytes, isDStorageError, isManifest, isStorePartialError, mlkemGenerateKeypair, mlkemGenerateKeypairFromSeed, mlkemUnwrapDek, mlkemWrapDek, parseKeyEnvelope, serializeKeyEnvelope, serializeXChaChaPayload, unwrapKey, waitForFacadeSync, wrapKey };
|