@miden-sdk/react 0.13.2 → 0.14.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,13 +30,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AuthScheme: () => import_miden_sdk4.AuthScheme,
33
34
  DEFAULTS: () => DEFAULTS,
35
+ MidenError: () => MidenError,
34
36
  MidenProvider: () => MidenProvider,
35
37
  SignerContext: () => SignerContext,
38
+ accountIdsEqual: () => accountIdsEqual,
39
+ bigIntToBytes: () => bigIntToBytes,
40
+ bytesToBigInt: () => bytesToBigInt,
41
+ clearMidenStorage: () => clearMidenStorage,
42
+ concatBytes: () => concatBytes,
43
+ createMidenStorage: () => createMidenStorage,
44
+ createNoteAttachment: () => createNoteAttachment,
36
45
  formatAssetAmount: () => formatAssetAmount,
37
46
  formatNoteSummary: () => formatNoteSummary,
38
47
  getNoteSummary: () => getNoteSummary,
48
+ migrateStorage: () => migrateStorage,
49
+ normalizeAccountId: () => normalizeAccountId,
39
50
  parseAssetAmount: () => parseAssetAmount,
51
+ readNoteAttachment: () => readNoteAttachment,
40
52
  toBech32AccountId: () => toBech32AccountId,
41
53
  useAccount: () => useAccount,
42
54
  useAccounts: () => useAccounts,
@@ -50,15 +62,19 @@ __export(index_exports, {
50
62
  useMidenClient: () => useMidenClient,
51
63
  useMint: () => useMint,
52
64
  useMultiSend: () => useMultiSend,
65
+ useNoteStream: () => useNoteStream,
53
66
  useNotes: () => useNotes,
54
67
  useSend: () => useSend,
68
+ useSessionAccount: () => useSessionAccount,
55
69
  useSigner: () => useSigner,
56
70
  useSwap: () => useSwap,
57
71
  useSyncState: () => useSyncState,
58
72
  useTransaction: () => useTransaction,
59
73
  useTransactionHistory: () => useTransactionHistory,
60
74
  useWaitForCommit: () => useWaitForCommit,
61
- useWaitForNotes: () => useWaitForNotes
75
+ useWaitForNotes: () => useWaitForNotes,
76
+ waitForWalletDetection: () => waitForWalletDetection,
77
+ wrapWasmError: () => wrapWasmError
62
78
  });
63
79
  module.exports = __toCommonJS(index_exports);
64
80
 
@@ -88,6 +104,7 @@ var initialState = {
88
104
  notes: [],
89
105
  consumableNotes: [],
90
106
  assetMetadata: /* @__PURE__ */ new Map(),
107
+ noteFirstSeen: /* @__PURE__ */ new Map(),
91
108
  isLoadingAccounts: false,
92
109
  isLoadingNotes: false
93
110
  };
@@ -115,8 +132,74 @@ var useMidenStore = (0, import_zustand.create)()((set) => ({
115
132
  newMap.set(accountId, account);
116
133
  return { accountDetails: newMap };
117
134
  }),
118
- setNotes: (notes) => set({ notes }),
135
+ setNotes: (notes) => set((state) => {
136
+ const now = Date.now();
137
+ const newFirstSeen = /* @__PURE__ */ new Map();
138
+ for (const note of notes) {
139
+ try {
140
+ const id = note.id().toString();
141
+ newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
142
+ } catch {
143
+ }
144
+ }
145
+ return { notes, noteFirstSeen: newFirstSeen };
146
+ }),
147
+ setNotesIfChanged: (notes) => set((state) => {
148
+ const safeId = (n) => {
149
+ try {
150
+ return n.id().toString();
151
+ } catch {
152
+ return null;
153
+ }
154
+ };
155
+ const prevIds = /* @__PURE__ */ new Set();
156
+ for (const n of state.notes) {
157
+ const id = safeId(n);
158
+ if (id) prevIds.add(id);
159
+ }
160
+ const newIds = /* @__PURE__ */ new Set();
161
+ for (const n of notes) {
162
+ const id = safeId(n);
163
+ if (id) newIds.add(id);
164
+ }
165
+ if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
166
+ return {};
167
+ }
168
+ const now = Date.now();
169
+ const newFirstSeen = /* @__PURE__ */ new Map();
170
+ for (const note of notes) {
171
+ try {
172
+ const id = note.id().toString();
173
+ newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
174
+ } catch {
175
+ }
176
+ }
177
+ return { notes, noteFirstSeen: newFirstSeen };
178
+ }),
119
179
  setConsumableNotes: (consumableNotes) => set({ consumableNotes }),
180
+ setConsumableNotesIfChanged: (consumableNotes) => set((state) => {
181
+ const safeId = (n) => {
182
+ try {
183
+ return n.inputNoteRecord().id().toString();
184
+ } catch {
185
+ return null;
186
+ }
187
+ };
188
+ const prevIds = /* @__PURE__ */ new Set();
189
+ for (const n of state.consumableNotes) {
190
+ const id = safeId(n);
191
+ if (id) prevIds.add(id);
192
+ }
193
+ const newIds = /* @__PURE__ */ new Set();
194
+ for (const n of consumableNotes) {
195
+ const id = safeId(n);
196
+ if (id) newIds.add(id);
197
+ }
198
+ if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
199
+ return {};
200
+ }
201
+ return { consumableNotes };
202
+ }),
120
203
  setAssetMetadata: (assetId, metadata) => set((state) => {
121
204
  const newMap = new Map(state.assetMetadata);
122
205
  newMap.set(assetId, metadata);
@@ -131,6 +214,7 @@ var useAccountsStore = () => useMidenStore((state) => state.accounts);
131
214
  var useNotesStore = () => useMidenStore((state) => state.notes);
132
215
  var useConsumableNotesStore = () => useMidenStore((state) => state.consumableNotes);
133
216
  var useAssetMetadataStore = () => useMidenStore((state) => state.assetMetadata);
217
+ var useNoteFirstSeenStore = () => useMidenStore((state) => state.noteFirstSeen);
134
218
 
135
219
  // src/utils/accountParsing.ts
136
220
  var import_miden_sdk2 = require("@miden-sdk/miden-sdk");
@@ -154,6 +238,19 @@ var parseAccountId = (value) => {
154
238
  const normalized = normalizeAccountIdInput(value);
155
239
  return parseAccountIdFromString(normalized);
156
240
  };
241
+ function isFaucetId(accountId) {
242
+ try {
243
+ let hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
244
+ if (hex.startsWith("0x") || hex.startsWith("0X")) {
245
+ hex = hex.slice(2);
246
+ }
247
+ const firstByte = parseInt(hex.slice(0, 2), 16);
248
+ const accountType = firstByte >> 4 & 3;
249
+ return accountType === 2 || accountType === 3;
250
+ } catch {
251
+ return false;
252
+ }
253
+ }
157
254
  var parseAddress = (value, accountId) => {
158
255
  const normalized = normalizeAccountIdInput(value);
159
256
  if (isBech32Input(normalized)) {
@@ -258,16 +355,17 @@ var toBech32AccountId = (accountId) => {
258
355
 
259
356
  // src/context/MidenProvider.tsx
260
357
  var import_react2 = require("react");
261
- var import_miden_sdk5 = require("@miden-sdk/miden-sdk");
358
+ var import_miden_sdk6 = require("@miden-sdk/miden-sdk");
262
359
 
263
360
  // src/types/index.ts
361
+ var import_miden_sdk4 = require("@miden-sdk/miden-sdk");
264
362
  var DEFAULTS = {
265
363
  RPC_URL: void 0,
266
364
  // Will use SDK's testnet default
267
365
  AUTO_SYNC_INTERVAL: 15e3,
268
366
  STORAGE_MODE: "private",
269
367
  WALLET_MUTABLE: true,
270
- AUTH_SCHEME: 0,
368
+ AUTH_SCHEME: import_miden_sdk4.AuthScheme.AuthRpoFalcon512,
271
369
  NOTE_TYPE: "private",
272
370
  FAUCET_DECIMALS: 8
273
371
  };
@@ -311,7 +409,7 @@ function resolveRpcUrl(rpcUrl) {
311
409
  }
312
410
 
313
411
  // src/utils/prover.ts
314
- var import_miden_sdk4 = require("@miden-sdk/miden-sdk");
412
+ var import_miden_sdk5 = require("@miden-sdk/miden-sdk");
315
413
  var DEFAULT_PROVER_URLS = {
316
414
  devnet: "https://tx-prover.devnet.miden.io",
317
415
  testnet: "https://tx-prover.testnet.miden.io"
@@ -324,19 +422,19 @@ function resolveTransactionProver(config) {
324
422
  if (typeof prover === "string") {
325
423
  const normalized = prover.trim().toLowerCase();
326
424
  if (normalized === "local") {
327
- return import_miden_sdk4.TransactionProver.newLocalProver();
425
+ return import_miden_sdk5.TransactionProver.newLocalProver();
328
426
  }
329
427
  if (normalized === "devnet" || normalized === "testnet") {
330
428
  const url = config.proverUrls?.[normalized] ?? DEFAULT_PROVER_URLS[normalized] ?? null;
331
429
  if (!url) {
332
430
  throw new Error(`Missing ${normalized} prover URL`);
333
431
  }
334
- return import_miden_sdk4.TransactionProver.newRemoteProver(
432
+ return import_miden_sdk5.TransactionProver.newRemoteProver(
335
433
  url,
336
434
  normalizeTimeout(config.proverTimeoutMs)
337
435
  );
338
436
  }
339
- return import_miden_sdk4.TransactionProver.newRemoteProver(
437
+ return import_miden_sdk5.TransactionProver.newRemoteProver(
340
438
  prover,
341
439
  normalizeTimeout(config.proverTimeoutMs)
342
440
  );
@@ -348,7 +446,7 @@ function createRemoteProver(config, fallbackTimeout) {
348
446
  if (!url) {
349
447
  throw new Error("Remote prover requires a URL");
350
448
  }
351
- return import_miden_sdk4.TransactionProver.newRemoteProver(
449
+ return import_miden_sdk5.TransactionProver.newRemoteProver(
352
450
  url,
353
451
  normalizeTimeout(timeoutMs ?? fallbackTimeout)
354
452
  );
@@ -371,38 +469,41 @@ function useSigner() {
371
469
  }
372
470
 
373
471
  // src/utils/signerAccount.ts
374
- async function getAccountType(accountType) {
375
- const { AccountType } = await import("@miden-sdk/miden-sdk");
376
- switch (accountType) {
377
- case "RegularAccountImmutableCode":
378
- return AccountType.RegularAccountImmutableCode;
379
- case "RegularAccountUpdatableCode":
380
- return AccountType.RegularAccountUpdatableCode;
381
- case "FungibleFaucet":
382
- return AccountType.FungibleFaucet;
383
- case "NonFungibleFaucet":
384
- return AccountType.NonFungibleFaucet;
385
- default:
386
- return AccountType.RegularAccountImmutableCode;
387
- }
472
+ var WASM_ACCOUNT_TYPE = {
473
+ FungibleFaucet: 0,
474
+ NonFungibleFaucet: 1,
475
+ RegularAccountImmutableCode: 2,
476
+ RegularAccountUpdatableCode: 3
477
+ };
478
+ function getAccountType(accountType) {
479
+ return WASM_ACCOUNT_TYPE[accountType] ?? WASM_ACCOUNT_TYPE.RegularAccountImmutableCode;
388
480
  }
389
481
  function isPrivateStorageMode(storageMode) {
390
482
  return storageMode.toString() === "private";
391
483
  }
392
484
  async function initializeSignerAccount(client, config) {
393
- const { AccountBuilder, AccountComponent, Word } = await import("@miden-sdk/miden-sdk");
485
+ const { AccountBuilder, AccountComponent, AuthScheme: AuthScheme2, Word: Word2 } = await import("@miden-sdk/miden-sdk");
394
486
  await client.syncState();
395
- const commitmentWord = Word.deserialize(config.publicKeyCommitment);
487
+ const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
396
488
  const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
397
- const accountType = await getAccountType(config.accountType);
398
- const builder = new AccountBuilder(seed);
399
- const buildResult = builder.withAuthComponent(
489
+ const accountType = getAccountType(config.accountType);
490
+ let builder = new AccountBuilder(seed).withAuthComponent(
400
491
  AccountComponent.createAuthComponentFromCommitment(
401
492
  commitmentWord,
402
- 1
403
- // ECDSA auth scheme (K256/Keccak)
493
+ AuthScheme2.AuthEcdsaK256Keccak
404
494
  )
405
- ).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent().build();
495
+ ).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent();
496
+ if (config.customComponents?.length) {
497
+ for (const component of config.customComponents) {
498
+ if (component == null || typeof component.getProcedures !== "function") {
499
+ throw new Error(
500
+ "Each entry in customComponents must be an AccountComponent instance created via AccountComponent.compile(), AccountComponent.fromPackage(), or AccountComponent.fromLibrary()."
501
+ );
502
+ }
503
+ builder = builder.withComponent(component);
504
+ }
505
+ }
506
+ const buildResult = builder.build();
406
507
  const account = buildResult.account;
407
508
  const accountId = account.id();
408
509
  if (!isPrivateStorageMode(config.storageMode)) {
@@ -506,9 +607,6 @@ function MidenProvider({
506
607
  }
507
608
  return;
508
609
  }
509
- if (!signerContext) {
510
- isInitializedRef.current = true;
511
- }
512
610
  let cancelled = false;
513
611
  const initClient = async () => {
514
612
  await runExclusive(async () => {
@@ -520,7 +618,7 @@ function MidenProvider({
520
618
  let didSignerInit = false;
521
619
  if (signerContext && signerContext.isConnected) {
522
620
  const storeName = `MidenClientDB_${signerContext.storeName}`;
523
- webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
621
+ webClient = await import_miden_sdk6.WasmWebClient.createClientWithExternalKeystore(
524
622
  resolvedConfig.rpcUrl,
525
623
  resolvedConfig.noteTransportUrl,
526
624
  resolvedConfig.seed,
@@ -541,7 +639,7 @@ function MidenProvider({
541
639
  didSignerInit = true;
542
640
  } else {
543
641
  const seed = resolvedConfig.seed;
544
- webClient = await import_miden_sdk5.WebClient.createClient(
642
+ webClient = await import_miden_sdk6.WasmWebClient.createClient(
545
643
  resolvedConfig.rpcUrl,
546
644
  resolvedConfig.noteTransportUrl,
547
645
  seed
@@ -568,6 +666,9 @@ function MidenProvider({
568
666
  }
569
667
  }
570
668
  if (!cancelled) {
669
+ if (!signerContext) {
670
+ isInitializedRef.current = true;
671
+ }
571
672
  setClient(webClient);
572
673
  }
573
674
  } catch (error) {
@@ -582,6 +683,7 @@ function MidenProvider({
582
683
  initClient();
583
684
  return () => {
584
685
  cancelled = true;
686
+ isInitializedRef.current = false;
585
687
  };
586
688
  }, [
587
689
  runExclusive,
@@ -697,23 +799,13 @@ function useAccounts() {
697
799
  refetch
698
800
  };
699
801
  }
700
- function isFaucetId(accountId) {
701
- try {
702
- const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
703
- const firstByte = parseInt(hex.slice(0, 2), 16);
704
- const accountType = firstByte >> 4 & 3;
705
- return accountType === 2 || accountType === 3;
706
- } catch {
707
- return false;
708
- }
709
- }
710
802
 
711
803
  // src/hooks/useAccount.ts
712
804
  var import_react5 = require("react");
713
805
 
714
806
  // src/hooks/useAssetMetadata.ts
715
807
  var import_react4 = require("react");
716
- var import_miden_sdk6 = require("@miden-sdk/miden-sdk");
808
+ var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
717
809
  var inflight = /* @__PURE__ */ new Map();
718
810
  var rpcClients = /* @__PURE__ */ new Map();
719
811
  var getRpcClient = (rpcUrl) => {
@@ -721,27 +813,22 @@ var getRpcClient = (rpcUrl) => {
721
813
  const existing = rpcClients.get(key);
722
814
  if (existing) return existing;
723
815
  try {
724
- const endpoint = rpcUrl ? new import_miden_sdk6.Endpoint(rpcUrl) : import_miden_sdk6.Endpoint.testnet();
725
- const client = new import_miden_sdk6.RpcClient(endpoint);
816
+ const endpoint = rpcUrl ? new import_miden_sdk7.Endpoint(rpcUrl) : import_miden_sdk7.Endpoint.testnet();
817
+ const client = new import_miden_sdk7.RpcClient(endpoint);
726
818
  rpcClients.set(key, client);
727
819
  return client;
728
820
  } catch {
729
821
  return null;
730
822
  }
731
823
  };
732
- var fetchAssetMetadata = async (client, rpcClient, assetId) => {
824
+ var fetchAssetMetadata = async (rpcClient, assetId) => {
733
825
  try {
734
826
  const accountId = parseAccountId(assetId);
735
- let account = await client.getAccount(accountId);
736
- if (!account && rpcClient) {
737
- try {
738
- const fetched = await rpcClient.getAccountDetails(accountId);
739
- account = fetched.account?.();
740
- } catch {
741
- }
742
- }
827
+ if (!isFaucetId(accountId)) return null;
828
+ const fetched = await rpcClient.getAccountDetails(accountId);
829
+ const account = fetched.account?.();
743
830
  if (!account) return null;
744
- const faucet = import_miden_sdk6.BasicFungibleFaucetComponent.fromAccount(account);
831
+ const faucet = import_miden_sdk7.BasicFungibleFaucetComponent.fromAccount(account);
745
832
  const symbol = faucet.symbol().toString();
746
833
  const decimals = faucet.decimals();
747
834
  return { assetId, symbol, decimals };
@@ -750,8 +837,6 @@ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
750
837
  }
751
838
  };
752
839
  function useAssetMetadata(assetIds = []) {
753
- const { client, isReady, runExclusive } = useMiden();
754
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
755
840
  const assetMetadata = useAssetMetadataStore();
756
841
  const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
757
842
  const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
@@ -761,32 +846,19 @@ function useAssetMetadata(assetIds = []) {
761
846
  [assetIds]
762
847
  );
763
848
  (0, import_react4.useEffect)(() => {
764
- if (!client || !isReady || uniqueAssetIds.length === 0) return;
849
+ if (!rpcClient || uniqueAssetIds.length === 0) return;
765
850
  uniqueAssetIds.forEach((assetId) => {
766
851
  const existing = assetMetadata.get(assetId);
767
852
  const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
768
853
  if (hasMetadata || inflight.has(assetId)) return;
769
- const promise = runExclusiveSafe(async () => {
770
- const metadata = await fetchAssetMetadata(
771
- client,
772
- rpcClient,
773
- assetId
774
- );
854
+ const promise = fetchAssetMetadata(rpcClient, assetId).then((metadata) => {
775
855
  setAssetMetadata(assetId, metadata ?? { assetId });
776
856
  }).finally(() => {
777
857
  inflight.delete(assetId);
778
858
  });
779
859
  inflight.set(assetId, promise);
780
860
  });
781
- }, [
782
- client,
783
- isReady,
784
- uniqueAssetIds,
785
- assetMetadata,
786
- runExclusiveSafe,
787
- setAssetMetadata,
788
- rpcClient
789
- ]);
861
+ }, [uniqueAssetIds, assetMetadata, setAssetMetadata, rpcClient]);
790
862
  return { assetMetadata };
791
863
  }
792
864
 
@@ -888,7 +960,7 @@ function useAccount(accountId) {
888
960
 
889
961
  // src/hooks/useNotes.ts
890
962
  var import_react6 = require("react");
891
- var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
963
+ var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
892
964
 
893
965
  // src/utils/amounts.ts
894
966
  var formatAssetAmount = (amount, decimals) => {
@@ -972,6 +1044,82 @@ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(
972
1044
  return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
973
1045
  };
974
1046
 
1047
+ // src/utils/accountId.ts
1048
+ function normalizeAccountId(id) {
1049
+ return toBech32AccountId(id);
1050
+ }
1051
+ function accountIdsEqual(a, b) {
1052
+ let idA;
1053
+ let idB;
1054
+ try {
1055
+ idA = parseAccountId(a);
1056
+ idB = parseAccountId(b);
1057
+ return idA.toString() === idB.toString();
1058
+ } catch {
1059
+ return a === b;
1060
+ } finally {
1061
+ idA?.free?.();
1062
+ idB?.free?.();
1063
+ }
1064
+ }
1065
+
1066
+ // src/utils/noteFilters.ts
1067
+ var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
1068
+ function getNoteFilterType(status) {
1069
+ switch (status) {
1070
+ case "consumed":
1071
+ return import_miden_sdk8.NoteFilterTypes.Consumed;
1072
+ case "committed":
1073
+ return import_miden_sdk8.NoteFilterTypes.Committed;
1074
+ case "expected":
1075
+ return import_miden_sdk8.NoteFilterTypes.Expected;
1076
+ case "processing":
1077
+ return import_miden_sdk8.NoteFilterTypes.Processing;
1078
+ case "all":
1079
+ default:
1080
+ return import_miden_sdk8.NoteFilterTypes.All;
1081
+ }
1082
+ }
1083
+ function getNoteType(type) {
1084
+ switch (type) {
1085
+ case "private":
1086
+ return import_miden_sdk8.NoteType.Private;
1087
+ case "public":
1088
+ return import_miden_sdk8.NoteType.Public;
1089
+ default:
1090
+ return import_miden_sdk8.NoteType.Private;
1091
+ }
1092
+ }
1093
+ async function waitForTransactionCommit(client, runExclusiveSafe, txIdHex, maxWaitMs = 1e4, delayMs = 1e3) {
1094
+ const deadline = Date.now() + maxWaitMs;
1095
+ const targetHex = normalizeHex(txIdHex);
1096
+ while (Date.now() < deadline) {
1097
+ await runExclusiveSafe(() => client.syncState());
1098
+ const records = await runExclusiveSafe(
1099
+ () => client.getTransactions(import_miden_sdk8.TransactionFilter.all())
1100
+ );
1101
+ const record = records.find(
1102
+ (r) => normalizeHex(r.id().toHex()) === targetHex
1103
+ );
1104
+ if (record) {
1105
+ const status = record.transactionStatus();
1106
+ if (status.isCommitted()) {
1107
+ return;
1108
+ }
1109
+ if (status.isDiscarded()) {
1110
+ throw new Error("Transaction was discarded before commit");
1111
+ }
1112
+ }
1113
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1114
+ }
1115
+ throw new Error("Timeout waiting for transaction commit");
1116
+ }
1117
+ function normalizeHex(value) {
1118
+ const trimmed = value.trim();
1119
+ const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1120
+ return normalized.toLowerCase();
1121
+ }
1122
+
975
1123
  // src/hooks/useNotes.ts
976
1124
  function useNotes(options) {
977
1125
  const { client, isReady, runExclusive } = useMiden();
@@ -980,8 +1128,10 @@ function useNotes(options) {
980
1128
  const consumableNotes = useConsumableNotesStore();
981
1129
  const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
982
1130
  const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
983
- const setNotes = useMidenStore((state) => state.setNotes);
984
- const setConsumableNotes = useMidenStore((state) => state.setConsumableNotes);
1131
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1132
+ const setConsumableNotesIfChanged = useMidenStore(
1133
+ (state) => state.setConsumableNotesIfChanged
1134
+ );
985
1135
  const { lastSyncTime } = useSyncStateStore();
986
1136
  const [error, setError] = (0, import_react6.useState)(null);
987
1137
  const refetch = (0, import_react6.useCallback)(async () => {
@@ -992,7 +1142,7 @@ function useNotes(options) {
992
1142
  const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
993
1143
  async () => {
994
1144
  const filterType = getNoteFilterType(options?.status);
995
- const filter = new import_miden_sdk7.NoteFilter(filterType);
1145
+ const filter = new import_miden_sdk9.NoteFilter(filterType);
996
1146
  const notesResult = await client.getInputNotes(filter);
997
1147
  let consumableResult;
998
1148
  if (options?.accountId) {
@@ -1007,8 +1157,8 @@ function useNotes(options) {
1007
1157
  };
1008
1158
  }
1009
1159
  );
1010
- setNotes(fetchedNotes);
1011
- setConsumableNotes(fetchedConsumable);
1160
+ setNotesIfChanged(fetchedNotes);
1161
+ setConsumableNotesIfChanged(fetchedConsumable);
1012
1162
  } catch (err) {
1013
1163
  setError(err instanceof Error ? err : new Error(String(err)));
1014
1164
  } finally {
@@ -1021,8 +1171,8 @@ function useNotes(options) {
1021
1171
  options?.status,
1022
1172
  options?.accountId,
1023
1173
  setLoadingNotes,
1024
- setNotes,
1025
- setConsumableNotes
1174
+ setNotesIfChanged,
1175
+ setConsumableNotesIfChanged
1026
1176
  ]);
1027
1177
  (0, import_react6.useEffect)(() => {
1028
1178
  if (isReady && notes.length === 0) {
@@ -1049,14 +1199,65 @@ function useNotes(options) {
1049
1199
  (assetId) => assetMetadata.get(assetId),
1050
1200
  [assetMetadata]
1051
1201
  );
1052
- const noteSummaries = (0, import_react6.useMemo)(
1053
- () => notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1054
- [notes, getMetadata]
1055
- );
1056
- const consumableNoteSummaries = (0, import_react6.useMemo)(
1057
- () => consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1058
- [consumableNotes, getMetadata]
1202
+ const normalizedSender = (0, import_react6.useMemo)(() => {
1203
+ if (!options?.sender) return null;
1204
+ try {
1205
+ return normalizeAccountId(options.sender);
1206
+ } catch {
1207
+ return options.sender;
1208
+ }
1209
+ }, [options?.sender]);
1210
+ const excludeIdsKey = (0, import_react6.useMemo)(() => {
1211
+ if (!options?.excludeIds || options.excludeIds.length === 0) return "";
1212
+ return [...options.excludeIds].sort().join("\0");
1213
+ }, [options?.excludeIds]);
1214
+ const filterBySender = (0, import_react6.useCallback)(
1215
+ (summaries, target) => {
1216
+ const cache = /* @__PURE__ */ new Map();
1217
+ return summaries.filter((s) => {
1218
+ if (!s.sender) return false;
1219
+ let normalized = cache.get(s.sender);
1220
+ if (normalized === void 0) {
1221
+ try {
1222
+ normalized = normalizeAccountId(s.sender);
1223
+ } catch {
1224
+ normalized = s.sender;
1225
+ }
1226
+ cache.set(s.sender, normalized);
1227
+ }
1228
+ return normalized === target;
1229
+ });
1230
+ },
1231
+ []
1059
1232
  );
1233
+ const noteSummaries = (0, import_react6.useMemo)(() => {
1234
+ let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
1235
+ if (normalizedSender) {
1236
+ summaries = filterBySender(summaries, normalizedSender);
1237
+ }
1238
+ if (excludeIdsKey) {
1239
+ const excludeSet = new Set(excludeIdsKey.split("\0"));
1240
+ summaries = summaries.filter((s) => !excludeSet.has(s.id));
1241
+ }
1242
+ return summaries;
1243
+ }, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
1244
+ const consumableNoteSummaries = (0, import_react6.useMemo)(() => {
1245
+ let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
1246
+ if (normalizedSender) {
1247
+ summaries = filterBySender(summaries, normalizedSender);
1248
+ }
1249
+ if (excludeIdsKey) {
1250
+ const excludeSet = new Set(excludeIdsKey.split("\0"));
1251
+ summaries = summaries.filter((s) => !excludeSet.has(s.id));
1252
+ }
1253
+ return summaries;
1254
+ }, [
1255
+ consumableNotes,
1256
+ getMetadata,
1257
+ normalizedSender,
1258
+ excludeIdsKey,
1259
+ filterBySender
1260
+ ]);
1060
1261
  return {
1061
1262
  notes,
1062
1263
  consumableNotes,
@@ -1067,46 +1268,246 @@ function useNotes(options) {
1067
1268
  refetch
1068
1269
  };
1069
1270
  }
1070
- function getNoteFilterType(status) {
1071
- switch (status) {
1072
- case "consumed":
1073
- return import_miden_sdk7.NoteFilterTypes.Consumed;
1074
- case "committed":
1075
- return import_miden_sdk7.NoteFilterTypes.Committed;
1076
- case "expected":
1077
- return import_miden_sdk7.NoteFilterTypes.Expected;
1078
- case "processing":
1079
- return import_miden_sdk7.NoteFilterTypes.Processing;
1080
- case "all":
1081
- default:
1082
- return import_miden_sdk7.NoteFilterTypes.All;
1271
+
1272
+ // src/hooks/useNoteStream.ts
1273
+ var import_react7 = require("react");
1274
+ var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
1275
+
1276
+ // src/utils/noteAttachment.ts
1277
+ var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
1278
+ function readNoteAttachment(note) {
1279
+ try {
1280
+ const metadata = note.metadata?.();
1281
+ if (!metadata) return null;
1282
+ const attachment = metadata.attachment?.();
1283
+ if (!attachment) return null;
1284
+ const kind = attachment.kind?.();
1285
+ if (!kind) return null;
1286
+ if (kind === import_miden_sdk10.NoteAttachmentKind.None) return null;
1287
+ if (kind === import_miden_sdk10.NoteAttachmentKind.Word) {
1288
+ const word = attachment.asWord?.();
1289
+ if (!word) return null;
1290
+ const u64s = word.toU64s();
1291
+ const values = Array.from(u64s).map(
1292
+ (v) => BigInt(v)
1293
+ );
1294
+ return { values, kind: "word" };
1295
+ }
1296
+ if (kind === import_miden_sdk10.NoteAttachmentKind.Array) {
1297
+ const arr = attachment.asArray?.();
1298
+ if (!arr) return null;
1299
+ const u64s = arr.toU64s();
1300
+ const values = Array.from(u64s).map(
1301
+ (v) => BigInt(v)
1302
+ );
1303
+ return { values, kind: "array" };
1304
+ }
1305
+ return null;
1306
+ } catch {
1307
+ return null;
1308
+ }
1309
+ }
1310
+ function createNoteAttachment(values) {
1311
+ const bigints = [];
1312
+ for (let i = 0; i < values.length; i++) {
1313
+ bigints.push(BigInt(values[i]));
1314
+ }
1315
+ if (bigints.length === 0) {
1316
+ return new import_miden_sdk10.NoteAttachment();
1317
+ }
1318
+ const scheme = import_miden_sdk10.NoteAttachmentScheme.none();
1319
+ if (bigints.length <= 4) {
1320
+ while (bigints.length < 4) {
1321
+ bigints.push(0n);
1322
+ }
1323
+ const word = new import_miden_sdk10.Word(BigUint64Array.from(bigints));
1324
+ return import_miden_sdk10.NoteAttachment.newWord(scheme, word);
1325
+ }
1326
+ while (bigints.length % 4 !== 0) {
1327
+ bigints.push(0n);
1328
+ }
1329
+ const words = [];
1330
+ for (let i = 0; i < bigints.length; i += 4) {
1331
+ words.push(new import_miden_sdk10.Word(BigUint64Array.from(bigints.slice(i, i + 4))));
1332
+ }
1333
+ const newArray = import_miden_sdk10.NoteAttachment["newArray"];
1334
+ if (typeof newArray !== "function") {
1335
+ throw new Error(
1336
+ "NoteAttachment.newArray is not available. Ensure @miden-sdk/miden-sdk >= 0.13.1."
1337
+ );
1083
1338
  }
1339
+ return newArray.call(import_miden_sdk10.NoteAttachment, scheme, words);
1084
1340
  }
1085
1341
 
1086
- // src/hooks/useTransactionHistory.ts
1087
- var import_react7 = require("react");
1088
- var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
1089
- function useTransactionHistory(options = {}) {
1342
+ // src/hooks/useNoteStream.ts
1343
+ function useNoteStream(options = {}) {
1090
1344
  const { client, isReady, runExclusive } = useMiden();
1091
1345
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1346
+ const allNotes = useNotesStore();
1347
+ const noteFirstSeen = useNoteFirstSeenStore();
1092
1348
  const { lastSyncTime } = useSyncStateStore();
1093
- const [records, setRecords] = (0, import_react7.useState)([]);
1349
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1094
1350
  const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1095
1351
  const [error, setError] = (0, import_react7.useState)(null);
1096
- const rawIds = (0, import_react7.useMemo)(() => {
1352
+ const handledIdsRef = (0, import_react7.useRef)(/* @__PURE__ */ new Set());
1353
+ const [handledVersion, setHandledVersion] = (0, import_react7.useState)(0);
1354
+ const status = options.status ?? "committed";
1355
+ const sender = options.sender ?? null;
1356
+ const since = options.since;
1357
+ const amountFilterRef = (0, import_react7.useRef)(options.amountFilter);
1358
+ amountFilterRef.current = options.amountFilter;
1359
+ const excludeIdsKey = (0, import_react7.useMemo)(() => {
1360
+ if (!options.excludeIds) return "";
1361
+ if (options.excludeIds instanceof Set)
1362
+ return Array.from(options.excludeIds).sort().join("\0");
1363
+ return [...options.excludeIds].sort().join("\0");
1364
+ }, [options.excludeIds]);
1365
+ const excludeIdSet = (0, import_react7.useMemo)(() => {
1366
+ if (!excludeIdsKey) return null;
1367
+ return new Set(excludeIdsKey.split("\0"));
1368
+ }, [excludeIdsKey]);
1369
+ const refetch = (0, import_react7.useCallback)(async () => {
1370
+ if (!client || !isReady) return;
1371
+ setIsLoading(true);
1372
+ setError(null);
1373
+ try {
1374
+ const filterType = getNoteFilterType(status);
1375
+ const filter = new import_miden_sdk11.NoteFilter(filterType);
1376
+ const fetched = await runExclusiveSafe(
1377
+ () => client.getInputNotes(filter)
1378
+ );
1379
+ setNotesIfChanged(fetched);
1380
+ } catch (err) {
1381
+ setError(err instanceof Error ? err : new Error(String(err)));
1382
+ } finally {
1383
+ setIsLoading(false);
1384
+ }
1385
+ }, [client, isReady, runExclusiveSafe, status, setNotesIfChanged]);
1386
+ (0, import_react7.useEffect)(() => {
1387
+ if (isReady) {
1388
+ refetch();
1389
+ }
1390
+ }, [isReady, lastSyncTime, refetch]);
1391
+ const streamedNotes = (0, import_react7.useMemo)(() => {
1392
+ void handledVersion;
1393
+ const result = [];
1394
+ let normalizedSender = null;
1395
+ if (sender) {
1396
+ try {
1397
+ normalizedSender = normalizeAccountId(sender);
1398
+ } catch {
1399
+ normalizedSender = sender;
1400
+ }
1401
+ }
1402
+ for (const record of allNotes) {
1403
+ const note = buildStreamedNote(record, noteFirstSeen);
1404
+ if (!note) continue;
1405
+ if (handledIdsRef.current.has(note.id)) continue;
1406
+ if (excludeIdSet && excludeIdSet.has(note.id)) continue;
1407
+ if (normalizedSender && note.sender !== normalizedSender) continue;
1408
+ if (since !== void 0 && note.firstSeenAt < since) continue;
1409
+ if (amountFilterRef.current && !amountFilterRef.current(note.amount))
1410
+ continue;
1411
+ result.push(note);
1412
+ }
1413
+ result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
1414
+ return result;
1415
+ }, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
1416
+ const latest = (0, import_react7.useMemo)(
1417
+ () => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
1418
+ [streamedNotes]
1419
+ );
1420
+ const markHandled = (0, import_react7.useCallback)((noteId) => {
1421
+ handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
1422
+ setHandledVersion((v) => v + 1);
1423
+ }, []);
1424
+ const markAllHandled = (0, import_react7.useCallback)(() => {
1425
+ const newSet = new Set(handledIdsRef.current);
1426
+ for (const note of streamedNotes) {
1427
+ newSet.add(note.id);
1428
+ }
1429
+ handledIdsRef.current = newSet;
1430
+ setHandledVersion((v) => v + 1);
1431
+ }, [streamedNotes]);
1432
+ const snapshot = (0, import_react7.useCallback)(() => {
1433
+ const ids = /* @__PURE__ */ new Set();
1434
+ for (const note of streamedNotes) {
1435
+ ids.add(note.id);
1436
+ }
1437
+ return { ids, timestamp: Date.now() };
1438
+ }, [streamedNotes]);
1439
+ return {
1440
+ notes: streamedNotes,
1441
+ latest,
1442
+ markHandled,
1443
+ markAllHandled,
1444
+ snapshot,
1445
+ isLoading,
1446
+ error
1447
+ };
1448
+ }
1449
+ function buildStreamedNote(record, noteFirstSeen) {
1450
+ try {
1451
+ const id = record.id().toString();
1452
+ const metadata = record.metadata?.();
1453
+ const senderHex = metadata?.sender?.()?.toString?.();
1454
+ const sender = senderHex ? toBech32AccountId(senderHex) : "";
1455
+ const assets = [];
1456
+ let primaryAmount = 0n;
1457
+ try {
1458
+ const details = record.details();
1459
+ const assetsList = details?.assets?.().fungibleAssets?.() ?? [];
1460
+ for (const asset of assetsList) {
1461
+ const assetId = asset.faucetId().toString();
1462
+ const amount = BigInt(asset.amount());
1463
+ assets.push({ assetId, amount });
1464
+ if (primaryAmount === 0n) {
1465
+ primaryAmount = amount;
1466
+ }
1467
+ }
1468
+ } catch {
1469
+ }
1470
+ const attachmentData = readNoteAttachment(record);
1471
+ const attachment = attachmentData ? attachmentData.values : null;
1472
+ const firstSeenAt = noteFirstSeen.get(id) ?? Date.now();
1473
+ return {
1474
+ id,
1475
+ sender,
1476
+ amount: primaryAmount,
1477
+ assets,
1478
+ record,
1479
+ firstSeenAt,
1480
+ attachment
1481
+ };
1482
+ } catch {
1483
+ return null;
1484
+ }
1485
+ }
1486
+
1487
+ // src/hooks/useTransactionHistory.ts
1488
+ var import_react8 = require("react");
1489
+ var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
1490
+ function useTransactionHistory(options = {}) {
1491
+ const { client, isReady, runExclusive } = useMiden();
1492
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1493
+ const { lastSyncTime } = useSyncStateStore();
1494
+ const [records, setRecords] = (0, import_react8.useState)([]);
1495
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
1496
+ const [error, setError] = (0, import_react8.useState)(null);
1497
+ const rawIds = (0, import_react8.useMemo)(() => {
1097
1498
  if (options.id) return [options.id];
1098
1499
  if (options.ids && options.ids.length > 0) return options.ids;
1099
1500
  return null;
1100
1501
  }, [options.id, options.ids]);
1101
- const idsHex = (0, import_react7.useMemo)(() => {
1502
+ const idsHex = (0, import_react8.useMemo)(() => {
1102
1503
  if (!rawIds) return null;
1103
1504
  return rawIds.map(
1104
- (id) => normalizeHex(typeof id === "string" ? id : id.toHex())
1505
+ (id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
1105
1506
  );
1106
1507
  }, [rawIds]);
1107
1508
  const filter = options.filter;
1108
1509
  const refreshOnSync = options.refreshOnSync !== false;
1109
- const refetch = (0, import_react7.useCallback)(async () => {
1510
+ const refetch = (0, import_react8.useCallback)(async () => {
1110
1511
  if (!client || !isReady) return;
1111
1512
  setIsLoading(true);
1112
1513
  setError(null);
@@ -1120,7 +1521,7 @@ function useTransactionHistory(options = {}) {
1120
1521
  () => client.getTransactions(resolvedFilter)
1121
1522
  );
1122
1523
  const filtered = localFilterHexes ? fetched.filter(
1123
- (record2) => localFilterHexes.includes(normalizeHex(record2.id().toHex()))
1524
+ (record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
1124
1525
  ) : fetched;
1125
1526
  setRecords(filtered);
1126
1527
  } catch (err) {
@@ -1129,19 +1530,19 @@ function useTransactionHistory(options = {}) {
1129
1530
  setIsLoading(false);
1130
1531
  }
1131
1532
  }, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
1132
- (0, import_react7.useEffect)(() => {
1533
+ (0, import_react8.useEffect)(() => {
1133
1534
  if (!isReady) return;
1134
1535
  refetch();
1135
1536
  }, [isReady, refetch]);
1136
- (0, import_react7.useEffect)(() => {
1537
+ (0, import_react8.useEffect)(() => {
1137
1538
  if (!isReady || !refreshOnSync || !lastSyncTime) return;
1138
1539
  refetch();
1139
1540
  }, [isReady, lastSyncTime, refreshOnSync, refetch]);
1140
- const record = (0, import_react7.useMemo)(() => {
1541
+ const record = (0, import_react8.useMemo)(() => {
1141
1542
  if (!idsHex || idsHex.length !== 1) return null;
1142
- return records.find((item) => normalizeHex(item.id().toHex()) === idsHex[0]) ?? null;
1543
+ return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
1143
1544
  }, [records, idsHex]);
1144
- const status = (0, import_react7.useMemo)(() => {
1545
+ const status = (0, import_react8.useMemo)(() => {
1145
1546
  if (!record) return null;
1146
1547
  const current = record.transactionStatus();
1147
1548
  if (current.isCommitted()) return "committed";
@@ -1163,29 +1564,29 @@ function buildFilter(filter, ids, idsHex) {
1163
1564
  return { filter };
1164
1565
  }
1165
1566
  if (!ids || ids.length === 0) {
1166
- return { filter: import_miden_sdk8.TransactionFilter.all() };
1567
+ return { filter: import_miden_sdk12.TransactionFilter.all() };
1167
1568
  }
1168
1569
  const allTransactionIds = ids.every((id) => typeof id !== "string");
1169
1570
  if (allTransactionIds) {
1170
- return { filter: import_miden_sdk8.TransactionFilter.ids(ids) };
1571
+ return { filter: import_miden_sdk12.TransactionFilter.ids(ids) };
1171
1572
  }
1172
1573
  return {
1173
- filter: import_miden_sdk8.TransactionFilter.all(),
1574
+ filter: import_miden_sdk12.TransactionFilter.all(),
1174
1575
  localFilterHexes: idsHex ?? []
1175
1576
  };
1176
1577
  }
1177
- function normalizeHex(value) {
1578
+ function normalizeHex2(value) {
1178
1579
  const trimmed = value.trim();
1179
1580
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1180
1581
  return normalized.toLowerCase();
1181
1582
  }
1182
1583
 
1183
1584
  // src/hooks/useSyncState.ts
1184
- var import_react8 = require("react");
1585
+ var import_react9 = require("react");
1185
1586
  function useSyncState() {
1186
1587
  const { sync: triggerSync } = useMiden();
1187
1588
  const syncState = useSyncStateStore();
1188
- const sync = (0, import_react8.useCallback)(async () => {
1589
+ const sync = (0, import_react9.useCallback)(async () => {
1189
1590
  await triggerSync();
1190
1591
  }, [triggerSync]);
1191
1592
  return {
@@ -1195,21 +1596,20 @@ function useSyncState() {
1195
1596
  }
1196
1597
 
1197
1598
  // src/hooks/useCreateWallet.ts
1198
- var import_react9 = require("react");
1199
- var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
1599
+ var import_react10 = require("react");
1600
+ var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
1200
1601
  function useCreateWallet() {
1201
- const { client, isReady, sync, runExclusive } = useMiden();
1602
+ const { client, isReady, runExclusive } = useMiden();
1202
1603
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1203
1604
  const setAccounts = useMidenStore((state) => state.setAccounts);
1204
- const [wallet, setWallet] = (0, import_react9.useState)(null);
1205
- const [isCreating, setIsCreating] = (0, import_react9.useState)(false);
1206
- const [error, setError] = (0, import_react9.useState)(null);
1207
- const createWallet = (0, import_react9.useCallback)(
1605
+ const [wallet, setWallet] = (0, import_react10.useState)(null);
1606
+ const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
1607
+ const [error, setError] = (0, import_react10.useState)(null);
1608
+ const createWallet = (0, import_react10.useCallback)(
1208
1609
  async (options = {}) => {
1209
1610
  if (!client || !isReady) {
1210
1611
  throw new Error("Miden client is not ready");
1211
1612
  }
1212
- await sync();
1213
1613
  setIsCreating(true);
1214
1614
  setError(null);
1215
1615
  try {
@@ -1242,7 +1642,7 @@ function useCreateWallet() {
1242
1642
  },
1243
1643
  [client, isReady, runExclusive, setAccounts]
1244
1644
  );
1245
- const reset = (0, import_react9.useCallback)(() => {
1645
+ const reset = (0, import_react10.useCallback)(() => {
1246
1646
  setWallet(null);
1247
1647
  setIsCreating(false);
1248
1648
  setError(null);
@@ -1258,27 +1658,27 @@ function useCreateWallet() {
1258
1658
  function getStorageMode(mode) {
1259
1659
  switch (mode) {
1260
1660
  case "private":
1261
- return import_miden_sdk9.AccountStorageMode.private();
1661
+ return import_miden_sdk13.AccountStorageMode.private();
1262
1662
  case "public":
1263
- return import_miden_sdk9.AccountStorageMode.public();
1663
+ return import_miden_sdk13.AccountStorageMode.public();
1264
1664
  case "network":
1265
- return import_miden_sdk9.AccountStorageMode.network();
1665
+ return import_miden_sdk13.AccountStorageMode.network();
1266
1666
  default:
1267
- return import_miden_sdk9.AccountStorageMode.private();
1667
+ return import_miden_sdk13.AccountStorageMode.private();
1268
1668
  }
1269
1669
  }
1270
1670
 
1271
1671
  // src/hooks/useCreateFaucet.ts
1272
- var import_react10 = require("react");
1273
- var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
1672
+ var import_react11 = require("react");
1673
+ var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
1274
1674
  function useCreateFaucet() {
1275
1675
  const { client, isReady, runExclusive } = useMiden();
1276
1676
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1277
1677
  const setAccounts = useMidenStore((state) => state.setAccounts);
1278
- const [faucet, setFaucet] = (0, import_react10.useState)(null);
1279
- const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
1280
- const [error, setError] = (0, import_react10.useState)(null);
1281
- const createFaucet = (0, import_react10.useCallback)(
1678
+ const [faucet, setFaucet] = (0, import_react11.useState)(null);
1679
+ const [isCreating, setIsCreating] = (0, import_react11.useState)(false);
1680
+ const [error, setError] = (0, import_react11.useState)(null);
1681
+ const createFaucet = (0, import_react11.useCallback)(
1282
1682
  async (options) => {
1283
1683
  if (!client || !isReady) {
1284
1684
  throw new Error("Miden client is not ready");
@@ -1317,7 +1717,7 @@ function useCreateFaucet() {
1317
1717
  },
1318
1718
  [client, isReady, runExclusive, setAccounts]
1319
1719
  );
1320
- const reset = (0, import_react10.useCallback)(() => {
1720
+ const reset = (0, import_react11.useCallback)(() => {
1321
1721
  setFaucet(null);
1322
1722
  setIsCreating(false);
1323
1723
  setError(null);
@@ -1333,27 +1733,27 @@ function useCreateFaucet() {
1333
1733
  function getStorageMode2(mode) {
1334
1734
  switch (mode) {
1335
1735
  case "private":
1336
- return import_miden_sdk10.AccountStorageMode.private();
1736
+ return import_miden_sdk14.AccountStorageMode.private();
1337
1737
  case "public":
1338
- return import_miden_sdk10.AccountStorageMode.public();
1738
+ return import_miden_sdk14.AccountStorageMode.public();
1339
1739
  case "network":
1340
- return import_miden_sdk10.AccountStorageMode.network();
1740
+ return import_miden_sdk14.AccountStorageMode.network();
1341
1741
  default:
1342
- return import_miden_sdk10.AccountStorageMode.private();
1742
+ return import_miden_sdk14.AccountStorageMode.private();
1343
1743
  }
1344
1744
  }
1345
1745
 
1346
1746
  // src/hooks/useImportAccount.ts
1347
- var import_react11 = require("react");
1348
- var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
1349
- function useImportAccount() {
1747
+ var import_react12 = require("react");
1748
+ var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
1749
+ function useImportAccount() {
1350
1750
  const { client, isReady, runExclusive } = useMiden();
1351
1751
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1352
1752
  const setAccounts = useMidenStore((state) => state.setAccounts);
1353
- const [account, setAccount] = (0, import_react11.useState)(null);
1354
- const [isImporting, setIsImporting] = (0, import_react11.useState)(false);
1355
- const [error, setError] = (0, import_react11.useState)(null);
1356
- const importAccount = (0, import_react11.useCallback)(
1753
+ const [account, setAccount] = (0, import_react12.useState)(null);
1754
+ const [isImporting, setIsImporting] = (0, import_react12.useState)(false);
1755
+ const [error, setError] = (0, import_react12.useState)(null);
1756
+ const importAccount = (0, import_react12.useCallback)(
1357
1757
  async (options) => {
1358
1758
  if (!client || !isReady) {
1359
1759
  throw new Error("Miden client is not ready");
@@ -1448,7 +1848,7 @@ function useImportAccount() {
1448
1848
  },
1449
1849
  [client, isReady, runExclusive, setAccounts]
1450
1850
  );
1451
- const reset = (0, import_react11.useCallback)(() => {
1851
+ const reset = (0, import_react12.useCallback)(() => {
1452
1852
  setAccount(null);
1453
1853
  setIsImporting(false);
1454
1854
  setError(null);
@@ -1466,10 +1866,10 @@ function resolveAccountId(accountId) {
1466
1866
  }
1467
1867
  async function resolveAccountFile(file) {
1468
1868
  if (file instanceof Uint8Array) {
1469
- return import_miden_sdk11.AccountFile.deserialize(file);
1869
+ return import_miden_sdk15.AccountFile.deserialize(file);
1470
1870
  }
1471
1871
  if (file instanceof ArrayBuffer) {
1472
- return import_miden_sdk11.AccountFile.deserialize(new Uint8Array(file));
1872
+ return import_miden_sdk15.AccountFile.deserialize(new Uint8Array(file));
1473
1873
  }
1474
1874
  return file;
1475
1875
  }
@@ -1498,43 +1898,146 @@ function bytesEqual(left, right) {
1498
1898
  }
1499
1899
 
1500
1900
  // src/hooks/useSend.ts
1501
- var import_react12 = require("react");
1502
- var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
1901
+ var import_react13 = require("react");
1902
+ var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
1903
+
1904
+ // src/utils/errors.ts
1905
+ var MidenError = class extends Error {
1906
+ constructor(message, options) {
1907
+ super(message);
1908
+ this.name = "MidenError";
1909
+ this.code = options?.code ?? "UNKNOWN";
1910
+ if (options?.cause !== void 0) {
1911
+ this.cause = options.cause;
1912
+ }
1913
+ }
1914
+ };
1915
+ var ERROR_PATTERNS = [
1916
+ {
1917
+ test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
1918
+ code: "WASM_CLASS_MISMATCH",
1919
+ message: "WASM class identity mismatch. This usually means multiple copies of @miden-sdk/miden-sdk are bundled. Ensure your bundler deduplicates the package. For Vite: add resolve.dedupe and optimizeDeps.exclude for @miden-sdk/miden-sdk."
1920
+ },
1921
+ {
1922
+ test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
1923
+ code: "WASM_POINTER_CONSUMED",
1924
+ message: "WASM object was already consumed. Some WASM-bound objects can only be passed once \u2014 if you need to reuse a value, create a fresh instance before each call."
1925
+ },
1926
+ {
1927
+ test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
1928
+ code: "WASM_NOT_INITIALIZED",
1929
+ message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
1930
+ },
1931
+ {
1932
+ test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
1933
+ code: "WASM_SYNC_REQUIRED",
1934
+ message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
1935
+ }
1936
+ ];
1937
+ function wrapWasmError(e) {
1938
+ if (e instanceof MidenError) return e;
1939
+ const msg = e instanceof Error ? e.message : String(e);
1940
+ for (const pattern of ERROR_PATTERNS) {
1941
+ if (pattern.test(msg)) {
1942
+ return new MidenError(pattern.message, { cause: e, code: pattern.code });
1943
+ }
1944
+ }
1945
+ if (e instanceof Error) return e;
1946
+ return new Error(msg);
1947
+ }
1948
+
1949
+ // src/hooks/useSend.ts
1503
1950
  function useSend() {
1504
1951
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1505
1952
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1506
- const [result, setResult] = (0, import_react12.useState)(null);
1507
- const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
1508
- const [stage, setStage] = (0, import_react12.useState)("idle");
1509
- const [error, setError] = (0, import_react12.useState)(null);
1510
- const send = (0, import_react12.useCallback)(
1953
+ const isBusyRef = (0, import_react13.useRef)(false);
1954
+ const [result, setResult] = (0, import_react13.useState)(null);
1955
+ const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1956
+ const [stage, setStage] = (0, import_react13.useState)("idle");
1957
+ const [error, setError] = (0, import_react13.useState)(null);
1958
+ const send = (0, import_react13.useCallback)(
1511
1959
  async (options) => {
1512
1960
  if (!client || !isReady) {
1513
1961
  throw new Error("Miden client is not ready");
1514
1962
  }
1963
+ if (isBusyRef.current) {
1964
+ throw new MidenError(
1965
+ "A send is already in progress. Await the previous send before starting another.",
1966
+ { code: "SEND_BUSY" }
1967
+ );
1968
+ }
1969
+ isBusyRef.current = true;
1515
1970
  setIsLoading(true);
1516
1971
  setStage("executing");
1517
1972
  setError(null);
1518
1973
  try {
1974
+ if (!options.skipSync) {
1975
+ await sync();
1976
+ }
1519
1977
  const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1520
- const fromAccountId = parseAccountId(options.from);
1521
- const toAccountId = parseAccountId(options.to);
1978
+ let amount = options.amount;
1979
+ if (options.sendAll) {
1980
+ const resolvedAmount = await runExclusiveSafe(async () => {
1981
+ const fromId = parseAccountId(options.from);
1982
+ const account = await client.getAccount(fromId);
1983
+ if (!account) throw new Error("Account not found");
1984
+ const assetIdObj = parseAccountId(options.assetId);
1985
+ const balance = account.vault?.()?.getBalance?.(assetIdObj);
1986
+ if (balance === void 0 || balance === null) {
1987
+ throw new Error("Could not query account balance");
1988
+ }
1989
+ const bal = BigInt(balance);
1990
+ if (bal === 0n) {
1991
+ throw new Error("Account has zero balance for this asset");
1992
+ }
1993
+ return bal;
1994
+ });
1995
+ amount = resolvedAmount;
1996
+ }
1997
+ if (amount === void 0 || amount === null) {
1998
+ throw new Error("Amount is required (provide amount or sendAll)");
1999
+ }
1522
2000
  const assetId = options.assetId ?? options.faucetId ?? null;
1523
2001
  if (!assetId) {
1524
2002
  throw new Error("Asset ID is required");
1525
2003
  }
1526
- const assetIdObj = parseAccountId(assetId);
1527
- const txResult = await runExclusiveSafe(async () => {
1528
- const txRequest = client.newSendTransactionRequest(
1529
- fromAccountId,
1530
- toAccountId,
1531
- assetIdObj,
1532
- noteType,
1533
- options.amount,
1534
- options.recallHeight ?? null,
1535
- options.timelockHeight ?? null
2004
+ const hasAttachment = options.attachment !== void 0 && options.attachment !== null;
2005
+ if (hasAttachment && (options.recallHeight != null || options.timelockHeight != null)) {
2006
+ throw new Error(
2007
+ "recallHeight and timelockHeight are not supported when attachment is provided"
1536
2008
  );
1537
- return await client.executeTransaction(fromAccountId, txRequest);
2009
+ }
2010
+ const txResult = await runExclusiveSafe(async () => {
2011
+ const fromAccountId = parseAccountId(options.from);
2012
+ const toAccountId = parseAccountId(options.to);
2013
+ const assetIdObj = parseAccountId(assetId);
2014
+ let txRequest;
2015
+ if (hasAttachment) {
2016
+ const attachment = createNoteAttachment(options.attachment);
2017
+ const assets = new import_miden_sdk16.NoteAssets([
2018
+ new import_miden_sdk16.FungibleAsset(assetIdObj, amount)
2019
+ ]);
2020
+ const note = import_miden_sdk16.Note.createP2IDNote(
2021
+ fromAccountId,
2022
+ toAccountId,
2023
+ assets,
2024
+ noteType,
2025
+ attachment
2026
+ );
2027
+ txRequest = new import_miden_sdk16.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk16.OutputNoteArray([import_miden_sdk16.OutputNote.full(note)])).build();
2028
+ } else {
2029
+ txRequest = client.newSendTransactionRequest(
2030
+ fromAccountId,
2031
+ toAccountId,
2032
+ assetIdObj,
2033
+ noteType,
2034
+ amount,
2035
+ options.recallHeight ?? null,
2036
+ options.timelockHeight ?? null
2037
+ );
2038
+ }
2039
+ const execAccountId = parseAccountId(options.from);
2040
+ return await client.executeTransaction(execAccountId, txRequest);
1538
2041
  });
1539
2042
  setStage("proving");
1540
2043
  const provenTransaction = await runExclusiveSafe(
@@ -1544,22 +2047,31 @@ function useSend() {
1544
2047
  const submissionHeight = await runExclusiveSafe(
1545
2048
  () => client.submitProvenTransaction(provenTransaction, txResult)
1546
2049
  );
2050
+ const txIdHex = txResult.id().toHex();
2051
+ const txIdString = txResult.id().toString();
2052
+ let fullNote = null;
2053
+ if (noteType === import_miden_sdk16.NoteType.Private) {
2054
+ fullNote = extractFullNote(txResult);
2055
+ }
1547
2056
  await runExclusiveSafe(
1548
2057
  () => client.applyTransaction(txResult, submissionHeight)
1549
2058
  );
1550
- const txId = txResult.id();
1551
- await waitForTransactionCommit(client, runExclusiveSafe, txId);
1552
- if (noteType === import_miden_sdk12.NoteType.Private) {
1553
- const fullNote = extractFullNote(txResult);
2059
+ if (noteType === import_miden_sdk16.NoteType.Private) {
1554
2060
  if (!fullNote) {
1555
2061
  throw new Error("Missing full note for private send");
1556
2062
  }
1557
- const recipientAddress = parseAddress(options.to, toAccountId);
2063
+ await waitForTransactionCommit(
2064
+ client,
2065
+ runExclusiveSafe,
2066
+ txIdHex
2067
+ );
2068
+ const recipientAccountId = parseAccountId(options.to);
2069
+ const recipientAddress = parseAddress(options.to, recipientAccountId);
1558
2070
  await runExclusiveSafe(
1559
2071
  () => client.sendPrivateNote(fullNote, recipientAddress)
1560
2072
  );
1561
2073
  }
1562
- const txSummary = { transactionId: txResult.id().toString() };
2074
+ const txSummary = { transactionId: txIdString };
1563
2075
  setStage("complete");
1564
2076
  setResult(txSummary);
1565
2077
  await sync();
@@ -1571,11 +2083,12 @@ function useSend() {
1571
2083
  throw error2;
1572
2084
  } finally {
1573
2085
  setIsLoading(false);
2086
+ isBusyRef.current = false;
1574
2087
  }
1575
2088
  },
1576
2089
  [client, isReady, prover, runExclusive, sync]
1577
2090
  );
1578
- const reset = (0, import_react12.useCallback)(() => {
2091
+ const reset = (0, import_react13.useCallback)(() => {
1579
2092
  setResult(null);
1580
2093
  setIsLoading(false);
1581
2094
  setStage("idle");
@@ -1590,39 +2103,6 @@ function useSend() {
1590
2103
  reset
1591
2104
  };
1592
2105
  }
1593
- function getNoteType(type) {
1594
- switch (type) {
1595
- case "private":
1596
- return import_miden_sdk12.NoteType.Private;
1597
- case "public":
1598
- return import_miden_sdk12.NoteType.Public;
1599
- case "encrypted":
1600
- return import_miden_sdk12.NoteType.Encrypted;
1601
- default:
1602
- return import_miden_sdk12.NoteType.Private;
1603
- }
1604
- }
1605
- async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1606
- let waited = 0;
1607
- while (waited < maxWaitMs) {
1608
- await runExclusiveSafe(() => client.syncState());
1609
- const [record] = await runExclusiveSafe(
1610
- () => client.getTransactions(import_miden_sdk12.TransactionFilter.ids([txId]))
1611
- );
1612
- if (record) {
1613
- const status = record.transactionStatus();
1614
- if (status.isCommitted()) {
1615
- return;
1616
- }
1617
- if (status.isDiscarded()) {
1618
- throw new Error("Transaction was discarded before commit");
1619
- }
1620
- }
1621
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1622
- waited += delayMs;
1623
- }
1624
- throw new Error("Timeout waiting for transaction commit");
1625
- }
1626
2106
  function extractFullNote(txResult) {
1627
2107
  try {
1628
2108
  const executedTx = txResult.executedTransaction?.();
@@ -1635,16 +2115,17 @@ function extractFullNote(txResult) {
1635
2115
  }
1636
2116
 
1637
2117
  // src/hooks/useMultiSend.ts
1638
- var import_react13 = require("react");
1639
- var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
2118
+ var import_react14 = require("react");
2119
+ var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
1640
2120
  function useMultiSend() {
1641
2121
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1642
2122
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1643
- const [result, setResult] = (0, import_react13.useState)(null);
1644
- const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1645
- const [stage, setStage] = (0, import_react13.useState)("idle");
1646
- const [error, setError] = (0, import_react13.useState)(null);
1647
- const sendMany = (0, import_react13.useCallback)(
2123
+ const isBusyRef = (0, import_react14.useRef)(false);
2124
+ const [result, setResult] = (0, import_react14.useState)(null);
2125
+ const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
2126
+ const [stage, setStage] = (0, import_react14.useState)("idle");
2127
+ const [error, setError] = (0, import_react14.useState)(null);
2128
+ const sendMany = (0, import_react14.useCallback)(
1648
2129
  async (options) => {
1649
2130
  if (!client || !isReady) {
1650
2131
  throw new Error("Miden client is not ready");
@@ -1652,35 +2133,53 @@ function useMultiSend() {
1652
2133
  if (options.recipients.length === 0) {
1653
2134
  throw new Error("No recipients provided");
1654
2135
  }
2136
+ if (isBusyRef.current) {
2137
+ throw new MidenError(
2138
+ "A send is already in progress. Await the previous send before starting another.",
2139
+ { code: "SEND_BUSY" }
2140
+ );
2141
+ }
2142
+ isBusyRef.current = true;
1655
2143
  setIsLoading(true);
1656
2144
  setStage("executing");
1657
2145
  setError(null);
1658
2146
  try {
1659
- const noteType = getNoteType2(options.noteType ?? DEFAULTS.NOTE_TYPE);
1660
- const senderId = parseAccountId(options.from);
1661
- const assetId = parseAccountId(options.assetId);
1662
- const outputs = options.recipients.map(({ to, amount }) => {
1663
- const receiverId = parseAccountId(to);
1664
- const assets = new import_miden_sdk13.NoteAssets([new import_miden_sdk13.FungibleAsset(assetId, amount)]);
1665
- const note = import_miden_sdk13.Note.createP2IDNote(
1666
- senderId,
1667
- receiverId,
1668
- assets,
1669
- noteType,
1670
- new import_miden_sdk13.NoteAttachment()
1671
- );
1672
- const recipientAddress = parseAddress(to, receiverId);
1673
- return {
1674
- outputNote: import_miden_sdk13.OutputNote.full(note),
1675
- note,
1676
- recipientAddress
1677
- };
1678
- });
1679
- const txRequest = new import_miden_sdk13.TransactionRequestBuilder().withOwnOutputNotes(
1680
- new import_miden_sdk13.OutputNoteArray(outputs.map((o) => o.outputNote))
2147
+ if (!options.skipSync) {
2148
+ await sync();
2149
+ }
2150
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2151
+ const outputs = options.recipients.map(
2152
+ ({ to, amount, attachment, noteType: recipientNoteType }) => {
2153
+ const iterSenderId = parseAccountId(options.from);
2154
+ const iterAssetId = parseAccountId(options.assetId);
2155
+ const receiverId = parseAccountId(to);
2156
+ const assets = new import_miden_sdk17.NoteAssets([
2157
+ new import_miden_sdk17.FungibleAsset(iterAssetId, amount)
2158
+ ]);
2159
+ const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
2160
+ const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new import_miden_sdk17.NoteAttachment();
2161
+ const note = import_miden_sdk17.Note.createP2IDNote(
2162
+ iterSenderId,
2163
+ receiverId,
2164
+ assets,
2165
+ resolvedNoteType,
2166
+ noteAttachment
2167
+ );
2168
+ const recipientAddress = parseAddress(to, receiverId);
2169
+ return {
2170
+ outputNote: import_miden_sdk17.OutputNote.full(note),
2171
+ note,
2172
+ recipientAddress,
2173
+ noteType: resolvedNoteType
2174
+ };
2175
+ }
2176
+ );
2177
+ const txRequest = new import_miden_sdk17.TransactionRequestBuilder().withOwnOutputNotes(
2178
+ new import_miden_sdk17.OutputNoteArray(outputs.map((o) => o.outputNote))
1681
2179
  ).build();
2180
+ const txSenderId = parseAccountId(options.from);
1682
2181
  const txResult = await runExclusiveSafe(
1683
- () => client.executeTransaction(senderId, txRequest)
2182
+ () => client.executeTransaction(txSenderId, txRequest)
1684
2183
  );
1685
2184
  setStage("proving");
1686
2185
  const provenTransaction = await runExclusiveSafe(
@@ -1690,23 +2189,27 @@ function useMultiSend() {
1690
2189
  const submissionHeight = await runExclusiveSafe(
1691
2190
  () => client.submitProvenTransaction(provenTransaction, txResult)
1692
2191
  );
2192
+ const txIdHex = txResult.id().toHex();
2193
+ const txIdString = txResult.id().toString();
1693
2194
  await runExclusiveSafe(
1694
2195
  () => client.applyTransaction(txResult, submissionHeight)
1695
2196
  );
1696
- const txId = txResult.id();
1697
- if (noteType === import_miden_sdk13.NoteType.Private) {
1698
- await waitForTransactionCommit2(
2197
+ const hasPrivate = outputs.some((o) => o.noteType === import_miden_sdk17.NoteType.Private);
2198
+ if (hasPrivate) {
2199
+ await waitForTransactionCommit(
1699
2200
  client,
1700
2201
  runExclusiveSafe,
1701
- txId
2202
+ txIdHex
1702
2203
  );
1703
2204
  for (const output of outputs) {
1704
- await runExclusiveSafe(
1705
- () => client.sendPrivateNote(output.note, output.recipientAddress)
1706
- );
2205
+ if (output.noteType === import_miden_sdk17.NoteType.Private) {
2206
+ await runExclusiveSafe(
2207
+ () => client.sendPrivateNote(output.note, output.recipientAddress)
2208
+ );
2209
+ }
1707
2210
  }
1708
2211
  }
1709
- const txSummary = { transactionId: txId.toString() };
2212
+ const txSummary = { transactionId: txIdString };
1710
2213
  setStage("complete");
1711
2214
  setResult(txSummary);
1712
2215
  await sync();
@@ -1718,11 +2221,12 @@ function useMultiSend() {
1718
2221
  throw error2;
1719
2222
  } finally {
1720
2223
  setIsLoading(false);
2224
+ isBusyRef.current = false;
1721
2225
  }
1722
2226
  },
1723
2227
  [client, isReady, prover, runExclusive, sync]
1724
2228
  );
1725
- const reset = (0, import_react13.useCallback)(() => {
2229
+ const reset = (0, import_react14.useCallback)(() => {
1726
2230
  setResult(null);
1727
2231
  setIsLoading(false);
1728
2232
  setStage("idle");
@@ -1737,71 +2241,38 @@ function useMultiSend() {
1737
2241
  reset
1738
2242
  };
1739
2243
  }
1740
- function getNoteType2(type) {
1741
- switch (type) {
1742
- case "private":
1743
- return import_miden_sdk13.NoteType.Private;
1744
- case "public":
1745
- return import_miden_sdk13.NoteType.Public;
1746
- case "encrypted":
1747
- return import_miden_sdk13.NoteType.Encrypted;
1748
- default:
1749
- return import_miden_sdk13.NoteType.Private;
1750
- }
1751
- }
1752
- async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1753
- let waited = 0;
1754
- while (waited < maxWaitMs) {
1755
- await runExclusiveSafe(() => client.syncState());
1756
- const [record] = await runExclusiveSafe(
1757
- () => client.getTransactions(import_miden_sdk13.TransactionFilter.ids([txId]))
1758
- );
1759
- if (record) {
1760
- const status = record.transactionStatus();
1761
- if (status.isCommitted()) {
1762
- return;
1763
- }
1764
- if (status.isDiscarded()) {
1765
- throw new Error("Transaction was discarded before commit");
1766
- }
1767
- }
1768
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1769
- waited += delayMs;
1770
- }
1771
- throw new Error("Timeout waiting for transaction commit");
1772
- }
1773
2244
 
1774
2245
  // src/hooks/useInternalTransfer.ts
1775
- var import_react14 = require("react");
1776
- var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
2246
+ var import_react15 = require("react");
2247
+ var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
1777
2248
  function useInternalTransfer() {
1778
2249
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1779
2250
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1780
- const [result, setResult] = (0, import_react14.useState)(null);
1781
- const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
1782
- const [stage, setStage] = (0, import_react14.useState)("idle");
1783
- const [error, setError] = (0, import_react14.useState)(null);
1784
- const transferOnce = (0, import_react14.useCallback)(
2251
+ const [result, setResult] = (0, import_react15.useState)(null);
2252
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
2253
+ const [stage, setStage] = (0, import_react15.useState)("idle");
2254
+ const [error, setError] = (0, import_react15.useState)(null);
2255
+ const transferOnce = (0, import_react15.useCallback)(
1785
2256
  async (options) => {
1786
2257
  if (!client || !isReady) {
1787
2258
  throw new Error("Miden client is not ready");
1788
2259
  }
1789
- const noteType = getNoteType3(options.noteType ?? DEFAULTS.NOTE_TYPE);
2260
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1790
2261
  const senderId = parseAccountId(options.from);
1791
2262
  const receiverId = parseAccountId(options.to);
1792
2263
  const assetId = parseAccountId(options.assetId);
1793
- const assets = new import_miden_sdk14.NoteAssets([
1794
- new import_miden_sdk14.FungibleAsset(assetId, options.amount)
2264
+ const assets = new import_miden_sdk18.NoteAssets([
2265
+ new import_miden_sdk18.FungibleAsset(assetId, options.amount)
1795
2266
  ]);
1796
- const note = import_miden_sdk14.Note.createP2IDNote(
2267
+ const note = import_miden_sdk18.Note.createP2IDNote(
1797
2268
  senderId,
1798
2269
  receiverId,
1799
2270
  assets,
1800
2271
  noteType,
1801
- new import_miden_sdk14.NoteAttachment()
2272
+ new import_miden_sdk18.NoteAttachment()
1802
2273
  );
1803
2274
  const noteId = note.id().toString();
1804
- const createRequest = new import_miden_sdk14.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk14.OutputNoteArray([import_miden_sdk14.OutputNote.full(note)])).build();
2275
+ const createRequest = new import_miden_sdk18.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk18.OutputNoteArray([import_miden_sdk18.OutputNote.full(note)])).build();
1805
2276
  const createTxId = await runExclusiveSafe(
1806
2277
  () => prover ? client.submitNewTransactionWithProver(
1807
2278
  senderId,
@@ -1809,7 +2280,7 @@ function useInternalTransfer() {
1809
2280
  prover
1810
2281
  ) : client.submitNewTransaction(senderId, createRequest)
1811
2282
  );
1812
- const consumeRequest = new import_miden_sdk14.TransactionRequestBuilder().withInputNotes(new import_miden_sdk14.NoteAndArgsArray([new import_miden_sdk14.NoteAndArgs(note, null)])).build();
2283
+ const consumeRequest = new import_miden_sdk18.TransactionRequestBuilder().withInputNotes(new import_miden_sdk18.NoteAndArgsArray([new import_miden_sdk18.NoteAndArgs(note, null)])).build();
1813
2284
  const consumeTxId = await runExclusiveSafe(
1814
2285
  () => prover ? client.submitNewTransactionWithProver(
1815
2286
  receiverId,
@@ -1825,7 +2296,7 @@ function useInternalTransfer() {
1825
2296
  },
1826
2297
  [client, isReady, prover, runExclusiveSafe]
1827
2298
  );
1828
- const transfer = (0, import_react14.useCallback)(
2299
+ const transfer = (0, import_react15.useCallback)(
1829
2300
  async (options) => {
1830
2301
  if (!client || !isReady) {
1831
2302
  throw new Error("Miden client is not ready");
@@ -1851,7 +2322,7 @@ function useInternalTransfer() {
1851
2322
  },
1852
2323
  [client, isReady, sync, transferOnce]
1853
2324
  );
1854
- const transferChain = (0, import_react14.useCallback)(
2325
+ const transferChain = (0, import_react15.useCallback)(
1855
2326
  async (options) => {
1856
2327
  if (!client || !isReady) {
1857
2328
  throw new Error("Miden client is not ready");
@@ -1892,7 +2363,7 @@ function useInternalTransfer() {
1892
2363
  },
1893
2364
  [client, isReady, sync, transferOnce]
1894
2365
  );
1895
- const reset = (0, import_react14.useCallback)(() => {
2366
+ const reset = (0, import_react15.useCallback)(() => {
1896
2367
  setResult(null);
1897
2368
  setIsLoading(false);
1898
2369
  setStage("idle");
@@ -1908,47 +2379,35 @@ function useInternalTransfer() {
1908
2379
  reset
1909
2380
  };
1910
2381
  }
1911
- function getNoteType3(type) {
1912
- switch (type) {
1913
- case "private":
1914
- return import_miden_sdk14.NoteType.Private;
1915
- case "public":
1916
- return import_miden_sdk14.NoteType.Public;
1917
- case "encrypted":
1918
- return import_miden_sdk14.NoteType.Encrypted;
1919
- default:
1920
- return import_miden_sdk14.NoteType.Private;
1921
- }
1922
- }
1923
2382
 
1924
2383
  // src/hooks/useWaitForCommit.ts
1925
- var import_react15 = require("react");
1926
- var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
2384
+ var import_react16 = require("react");
2385
+ var import_miden_sdk19 = require("@miden-sdk/miden-sdk");
1927
2386
  function useWaitForCommit() {
1928
2387
  const { client, isReady, runExclusive } = useMiden();
1929
2388
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1930
- const waitForCommit = (0, import_react15.useCallback)(
2389
+ const waitForCommit = (0, import_react16.useCallback)(
1931
2390
  async (txId, options) => {
1932
2391
  if (!client || !isReady) {
1933
2392
  throw new Error("Miden client is not ready");
1934
2393
  }
1935
2394
  const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
1936
2395
  const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
1937
- const targetHex = normalizeHex2(
2396
+ const targetHex = normalizeHex3(
1938
2397
  typeof txId === "string" ? txId : txId.toHex()
1939
2398
  );
1940
- let waited = 0;
1941
- while (waited < timeoutMs) {
2399
+ const deadline = Date.now() + timeoutMs;
2400
+ while (Date.now() < deadline) {
1942
2401
  await runExclusiveSafe(
1943
2402
  () => client.syncState()
1944
2403
  );
1945
2404
  const records = await runExclusiveSafe(
1946
2405
  () => client.getTransactions(
1947
- typeof txId === "string" ? import_miden_sdk15.TransactionFilter.all() : import_miden_sdk15.TransactionFilter.ids([txId])
2406
+ typeof txId === "string" ? import_miden_sdk19.TransactionFilter.all() : import_miden_sdk19.TransactionFilter.ids([txId])
1948
2407
  )
1949
2408
  );
1950
2409
  const record = records.find(
1951
- (item) => normalizeHex2(item.id().toHex()) === targetHex
2410
+ (item) => normalizeHex3(item.id().toHex()) === targetHex
1952
2411
  );
1953
2412
  if (record) {
1954
2413
  const status = record.transactionStatus();
@@ -1960,7 +2419,6 @@ function useWaitForCommit() {
1960
2419
  }
1961
2420
  }
1962
2421
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
1963
- waited += intervalMs;
1964
2422
  }
1965
2423
  throw new Error("Timeout waiting for transaction commit");
1966
2424
  },
@@ -1968,18 +2426,18 @@ function useWaitForCommit() {
1968
2426
  );
1969
2427
  return { waitForCommit };
1970
2428
  }
1971
- function normalizeHex2(value) {
2429
+ function normalizeHex3(value) {
1972
2430
  const trimmed = value.trim();
1973
2431
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1974
2432
  return normalized.toLowerCase();
1975
2433
  }
1976
2434
 
1977
2435
  // src/hooks/useWaitForNotes.ts
1978
- var import_react16 = require("react");
2436
+ var import_react17 = require("react");
1979
2437
  function useWaitForNotes() {
1980
2438
  const { client, isReady, runExclusive } = useMiden();
1981
2439
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1982
- const waitForConsumableNotes = (0, import_react16.useCallback)(
2440
+ const waitForConsumableNotes = (0, import_react17.useCallback)(
1983
2441
  async (options) => {
1984
2442
  if (!client || !isReady) {
1985
2443
  throw new Error("Miden client is not ready");
@@ -1990,7 +2448,9 @@ function useWaitForNotes() {
1990
2448
  const accountId = parseAccountId(options.accountId);
1991
2449
  let waited = 0;
1992
2450
  while (waited < timeoutMs) {
1993
- await runExclusiveSafe(() => client.syncState());
2451
+ await runExclusiveSafe(
2452
+ () => client.syncState()
2453
+ );
1994
2454
  const notes = await runExclusiveSafe(
1995
2455
  () => client.getConsumableNotes(accountId)
1996
2456
  );
@@ -2008,16 +2468,15 @@ function useWaitForNotes() {
2008
2468
  }
2009
2469
 
2010
2470
  // src/hooks/useMint.ts
2011
- var import_react17 = require("react");
2012
- var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
2471
+ var import_react18 = require("react");
2013
2472
  function useMint() {
2014
2473
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2015
2474
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2016
- const [result, setResult] = (0, import_react17.useState)(null);
2017
- const [isLoading, setIsLoading] = (0, import_react17.useState)(false);
2018
- const [stage, setStage] = (0, import_react17.useState)("idle");
2019
- const [error, setError] = (0, import_react17.useState)(null);
2020
- const mint = (0, import_react17.useCallback)(
2475
+ const [result, setResult] = (0, import_react18.useState)(null);
2476
+ const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
2477
+ const [stage, setStage] = (0, import_react18.useState)("idle");
2478
+ const [error, setError] = (0, import_react18.useState)(null);
2479
+ const mint = (0, import_react18.useCallback)(
2021
2480
  async (options) => {
2022
2481
  if (!client || !isReady) {
2023
2482
  throw new Error("Miden client is not ready");
@@ -2026,7 +2485,7 @@ function useMint() {
2026
2485
  setStage("executing");
2027
2486
  setError(null);
2028
2487
  try {
2029
- const noteType = getNoteType4(options.noteType ?? DEFAULTS.NOTE_TYPE);
2488
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2030
2489
  const targetAccountIdObj = parseAccountId(options.targetAccountId);
2031
2490
  const faucetIdObj = parseAccountId(options.faucetId);
2032
2491
  setStage("proving");
@@ -2059,7 +2518,7 @@ function useMint() {
2059
2518
  },
2060
2519
  [client, isReady, prover, runExclusive, sync]
2061
2520
  );
2062
- const reset = (0, import_react17.useCallback)(() => {
2521
+ const reset = (0, import_react18.useCallback)(() => {
2063
2522
  setResult(null);
2064
2523
  setIsLoading(false);
2065
2524
  setStage("idle");
@@ -2074,30 +2533,18 @@ function useMint() {
2074
2533
  reset
2075
2534
  };
2076
2535
  }
2077
- function getNoteType4(type) {
2078
- switch (type) {
2079
- case "private":
2080
- return import_miden_sdk16.NoteType.Private;
2081
- case "public":
2082
- return import_miden_sdk16.NoteType.Public;
2083
- case "encrypted":
2084
- return import_miden_sdk16.NoteType.Encrypted;
2085
- default:
2086
- return import_miden_sdk16.NoteType.Private;
2087
- }
2088
- }
2089
2536
 
2090
2537
  // src/hooks/useConsume.ts
2091
- var import_react18 = require("react");
2092
- var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
2538
+ var import_react19 = require("react");
2539
+ var import_miden_sdk20 = require("@miden-sdk/miden-sdk");
2093
2540
  function useConsume() {
2094
2541
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2095
2542
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2096
- const [result, setResult] = (0, import_react18.useState)(null);
2097
- const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
2098
- const [stage, setStage] = (0, import_react18.useState)("idle");
2099
- const [error, setError] = (0, import_react18.useState)(null);
2100
- const consume = (0, import_react18.useCallback)(
2543
+ const [result, setResult] = (0, import_react19.useState)(null);
2544
+ const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
2545
+ const [stage, setStage] = (0, import_react19.useState)("idle");
2546
+ const [error, setError] = (0, import_react19.useState)(null);
2547
+ const consume = (0, import_react19.useCallback)(
2101
2548
  async (options) => {
2102
2549
  if (!client || !isReady) {
2103
2550
  throw new Error("Miden client is not ready");
@@ -2113,9 +2560,9 @@ function useConsume() {
2113
2560
  setStage("proving");
2114
2561
  const txResult = await runExclusiveSafe(async () => {
2115
2562
  const noteIds = options.noteIds.map(
2116
- (noteId) => import_miden_sdk17.NoteId.fromHex(noteId)
2563
+ (noteId) => import_miden_sdk20.NoteId.fromHex(noteId)
2117
2564
  );
2118
- const filter = new import_miden_sdk17.NoteFilter(import_miden_sdk17.NoteFilterTypes.List, noteIds);
2565
+ const filter = new import_miden_sdk20.NoteFilter(import_miden_sdk20.NoteFilterTypes.List, noteIds);
2119
2566
  const noteRecords = await client.getInputNotes(filter);
2120
2567
  const notes = noteRecords.map((record) => record.toNote());
2121
2568
  if (notes.length === 0) {
@@ -2147,7 +2594,7 @@ function useConsume() {
2147
2594
  },
2148
2595
  [client, isReady, prover, runExclusive, sync]
2149
2596
  );
2150
- const reset = (0, import_react18.useCallback)(() => {
2597
+ const reset = (0, import_react19.useCallback)(() => {
2151
2598
  setResult(null);
2152
2599
  setIsLoading(false);
2153
2600
  setStage("idle");
@@ -2164,16 +2611,15 @@ function useConsume() {
2164
2611
  }
2165
2612
 
2166
2613
  // src/hooks/useSwap.ts
2167
- var import_react19 = require("react");
2168
- var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
2614
+ var import_react20 = require("react");
2169
2615
  function useSwap() {
2170
2616
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2171
2617
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2172
- const [result, setResult] = (0, import_react19.useState)(null);
2173
- const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
2174
- const [stage, setStage] = (0, import_react19.useState)("idle");
2175
- const [error, setError] = (0, import_react19.useState)(null);
2176
- const swap = (0, import_react19.useCallback)(
2618
+ const [result, setResult] = (0, import_react20.useState)(null);
2619
+ const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
2620
+ const [stage, setStage] = (0, import_react20.useState)("idle");
2621
+ const [error, setError] = (0, import_react20.useState)(null);
2622
+ const swap = (0, import_react20.useCallback)(
2177
2623
  async (options) => {
2178
2624
  if (!client || !isReady) {
2179
2625
  throw new Error("Miden client is not ready");
@@ -2182,8 +2628,8 @@ function useSwap() {
2182
2628
  setStage("executing");
2183
2629
  setError(null);
2184
2630
  try {
2185
- const noteType = getNoteType5(options.noteType ?? DEFAULTS.NOTE_TYPE);
2186
- const paybackNoteType = getNoteType5(
2631
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2632
+ const paybackNoteType = getNoteType(
2187
2633
  options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
2188
2634
  );
2189
2635
  const accountIdObj = parseAccountId(options.accountId);
@@ -2222,7 +2668,7 @@ function useSwap() {
2222
2668
  },
2223
2669
  [client, isReady, prover, runExclusive, sync]
2224
2670
  );
2225
- const reset = (0, import_react19.useCallback)(() => {
2671
+ const reset = (0, import_react20.useCallback)(() => {
2226
2672
  setResult(null);
2227
2673
  setIsLoading(false);
2228
2674
  setStage("idle");
@@ -2237,41 +2683,40 @@ function useSwap() {
2237
2683
  reset
2238
2684
  };
2239
2685
  }
2240
- function getNoteType5(type) {
2241
- switch (type) {
2242
- case "private":
2243
- return import_miden_sdk18.NoteType.Private;
2244
- case "public":
2245
- return import_miden_sdk18.NoteType.Public;
2246
- case "encrypted":
2247
- return import_miden_sdk18.NoteType.Encrypted;
2248
- default:
2249
- return import_miden_sdk18.NoteType.Private;
2250
- }
2251
- }
2252
2686
 
2253
2687
  // src/hooks/useTransaction.ts
2254
- var import_react20 = require("react");
2688
+ var import_react21 = require("react");
2255
2689
  function useTransaction() {
2256
2690
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2257
2691
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2258
- const [result, setResult] = (0, import_react20.useState)(null);
2259
- const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
2260
- const [stage, setStage] = (0, import_react20.useState)("idle");
2261
- const [error, setError] = (0, import_react20.useState)(null);
2262
- const execute = (0, import_react20.useCallback)(
2692
+ const isBusyRef = (0, import_react21.useRef)(false);
2693
+ const [result, setResult] = (0, import_react21.useState)(null);
2694
+ const [isLoading, setIsLoading] = (0, import_react21.useState)(false);
2695
+ const [stage, setStage] = (0, import_react21.useState)("idle");
2696
+ const [error, setError] = (0, import_react21.useState)(null);
2697
+ const execute = (0, import_react21.useCallback)(
2263
2698
  async (options) => {
2264
2699
  if (!client || !isReady) {
2265
2700
  throw new Error("Miden client is not ready");
2266
2701
  }
2702
+ if (isBusyRef.current) {
2703
+ throw new MidenError(
2704
+ "A transaction is already in progress. Await the previous transaction before starting another.",
2705
+ { code: "SEND_BUSY" }
2706
+ );
2707
+ }
2708
+ isBusyRef.current = true;
2267
2709
  setIsLoading(true);
2268
2710
  setStage("executing");
2269
2711
  setError(null);
2270
2712
  try {
2713
+ if (!options.skipSync) {
2714
+ await sync();
2715
+ }
2716
+ const txRequest = await resolveRequest(options.request, client);
2271
2717
  setStage("proving");
2272
2718
  const txResult = await runExclusiveSafe(async () => {
2273
2719
  const accountIdObj = resolveAccountId2(options.accountId);
2274
- const txRequest = await resolveRequest(options.request, client);
2275
2720
  const txId = prover ? await client.submitNewTransactionWithProver(
2276
2721
  accountIdObj,
2277
2722
  txRequest,
@@ -2290,11 +2735,12 @@ function useTransaction() {
2290
2735
  throw error2;
2291
2736
  } finally {
2292
2737
  setIsLoading(false);
2738
+ isBusyRef.current = false;
2293
2739
  }
2294
2740
  },
2295
2741
  [client, isReady, prover, runExclusive, sync]
2296
2742
  );
2297
- const reset = (0, import_react20.useCallback)(() => {
2743
+ const reset = (0, import_react21.useCallback)(() => {
2298
2744
  setResult(null);
2299
2745
  setIsLoading(false);
2300
2746
  setStage("idle");
@@ -2319,17 +2765,339 @@ async function resolveRequest(request, client) {
2319
2765
  return request;
2320
2766
  }
2321
2767
 
2768
+ // src/hooks/useSessionAccount.ts
2769
+ var import_react22 = require("react");
2770
+ var import_miden_sdk21 = require("@miden-sdk/miden-sdk");
2771
+ function useSessionAccount(options) {
2772
+ const { client, isReady, sync, runExclusive } = useMiden();
2773
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2774
+ const setAccounts = useMidenStore((state) => state.setAccounts);
2775
+ const [sessionAccountId, setSessionAccountId] = (0, import_react22.useState)(null);
2776
+ const [step, setStep] = (0, import_react22.useState)("idle");
2777
+ const [error, setError] = (0, import_react22.useState)(null);
2778
+ const cancelledRef = (0, import_react22.useRef)(false);
2779
+ const isBusyRef = (0, import_react22.useRef)(false);
2780
+ const storagePrefix = options.storagePrefix ?? "miden-session";
2781
+ const pollIntervalMs = options.pollIntervalMs ?? 3e3;
2782
+ const maxWaitMs = options.maxWaitMs ?? 6e4;
2783
+ const storageMode = options.walletOptions?.storageMode ?? "public";
2784
+ const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
2785
+ const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
2786
+ const fundRef = (0, import_react22.useRef)(options.fund);
2787
+ fundRef.current = options.fund;
2788
+ (0, import_react22.useEffect)(() => {
2789
+ try {
2790
+ const stored = localStorage.getItem(`${storagePrefix}:accountId`);
2791
+ const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
2792
+ if (stored && stored.length > 0) {
2793
+ const validationId = parseAccountId(stored);
2794
+ validationId?.free?.();
2795
+ setSessionAccountId(stored);
2796
+ if (storedReady === "true") {
2797
+ setStep("ready");
2798
+ }
2799
+ }
2800
+ } catch {
2801
+ localStorage.removeItem(`${storagePrefix}:accountId`);
2802
+ localStorage.removeItem(`${storagePrefix}:ready`);
2803
+ }
2804
+ }, [storagePrefix]);
2805
+ const initialize = (0, import_react22.useCallback)(async () => {
2806
+ if (!client || !isReady) {
2807
+ throw new Error("Miden client is not ready");
2808
+ }
2809
+ if (isBusyRef.current) {
2810
+ throw new MidenError(
2811
+ "Session account initialization is already in progress.",
2812
+ { code: "OPERATION_BUSY" }
2813
+ );
2814
+ }
2815
+ isBusyRef.current = true;
2816
+ cancelledRef.current = false;
2817
+ setError(null);
2818
+ try {
2819
+ let walletId = sessionAccountId;
2820
+ if (!walletId) {
2821
+ setStep("creating");
2822
+ const resolvedStorageMode = getStorageMode3(storageMode);
2823
+ const wallet = await runExclusiveSafe(async () => {
2824
+ const w = await client.newWallet(
2825
+ resolvedStorageMode,
2826
+ mutable,
2827
+ authScheme
2828
+ );
2829
+ ensureAccountBech32(w);
2830
+ const accounts = await client.getAccounts();
2831
+ setAccounts(accounts);
2832
+ return w;
2833
+ });
2834
+ if (cancelledRef.current) return;
2835
+ walletId = wallet.id().toString();
2836
+ setSessionAccountId(walletId);
2837
+ localStorage.setItem(`${storagePrefix}:accountId`, walletId);
2838
+ }
2839
+ setStep("funding");
2840
+ await fundRef.current(walletId);
2841
+ if (cancelledRef.current) return;
2842
+ setStep("consuming");
2843
+ await waitAndConsume(
2844
+ client,
2845
+ runExclusiveSafe,
2846
+ walletId,
2847
+ pollIntervalMs,
2848
+ maxWaitMs,
2849
+ cancelledRef
2850
+ );
2851
+ if (cancelledRef.current) return;
2852
+ setStep("ready");
2853
+ localStorage.setItem(`${storagePrefix}:ready`, "true");
2854
+ await sync();
2855
+ } catch (err) {
2856
+ if (!cancelledRef.current) {
2857
+ const error2 = err instanceof Error ? err : new Error(String(err));
2858
+ setError(error2);
2859
+ setStep("idle");
2860
+ throw error2;
2861
+ }
2862
+ } finally {
2863
+ isBusyRef.current = false;
2864
+ }
2865
+ }, [
2866
+ client,
2867
+ isReady,
2868
+ sync,
2869
+ runExclusiveSafe,
2870
+ sessionAccountId,
2871
+ storageMode,
2872
+ mutable,
2873
+ authScheme,
2874
+ storagePrefix,
2875
+ pollIntervalMs,
2876
+ maxWaitMs,
2877
+ setAccounts
2878
+ ]);
2879
+ const reset = (0, import_react22.useCallback)(() => {
2880
+ cancelledRef.current = true;
2881
+ isBusyRef.current = false;
2882
+ setSessionAccountId(null);
2883
+ setStep("idle");
2884
+ setError(null);
2885
+ localStorage.removeItem(`${storagePrefix}:accountId`);
2886
+ localStorage.removeItem(`${storagePrefix}:ready`);
2887
+ }, [storagePrefix]);
2888
+ return {
2889
+ initialize,
2890
+ sessionAccountId,
2891
+ isReady: step === "ready",
2892
+ step,
2893
+ error,
2894
+ reset
2895
+ };
2896
+ }
2897
+ function getStorageMode3(mode) {
2898
+ switch (mode) {
2899
+ case "private":
2900
+ return import_miden_sdk21.AccountStorageMode.private();
2901
+ case "public":
2902
+ return import_miden_sdk21.AccountStorageMode.public();
2903
+ default:
2904
+ return import_miden_sdk21.AccountStorageMode.public();
2905
+ }
2906
+ }
2907
+ async function waitAndConsume(client, runExclusiveSafe, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
2908
+ const deadline = Date.now() + maxWaitMs;
2909
+ while (Date.now() < deadline) {
2910
+ if (cancelledRef.current) return;
2911
+ await runExclusiveSafe(
2912
+ () => client.syncState()
2913
+ );
2914
+ if (cancelledRef.current) return;
2915
+ const consumed = await runExclusiveSafe(async () => {
2916
+ const accountIdObj = parseAccountId(walletId);
2917
+ const consumable = await client.getConsumableNotes(accountIdObj);
2918
+ if (consumable.length === 0) return false;
2919
+ const notes = consumable.map((c) => c.inputNoteRecord().toNote());
2920
+ const txRequest = client.newConsumeTransactionRequest(notes);
2921
+ const freshAccountId = parseAccountId(walletId);
2922
+ await client.submitNewTransaction(freshAccountId, txRequest);
2923
+ return true;
2924
+ });
2925
+ if (consumed) return;
2926
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2927
+ }
2928
+ throw new Error("Timeout waiting for session wallet funding");
2929
+ }
2930
+
2931
+ // src/utils/bytes.ts
2932
+ function bytesToBigInt(bytes) {
2933
+ let result = 0n;
2934
+ for (let i = 0; i < bytes.length; i++) {
2935
+ result = result << 8n | BigInt(bytes[i]);
2936
+ }
2937
+ return result;
2938
+ }
2939
+ function bigIntToBytes(value, length) {
2940
+ if (value < 0n) {
2941
+ throw new RangeError("bigIntToBytes: value must be non-negative");
2942
+ }
2943
+ const maxValue = (1n << BigInt(length * 8)) - 1n;
2944
+ if (value > maxValue) {
2945
+ throw new RangeError(
2946
+ `bigIntToBytes: value ${value} does not fit in ${length} byte(s) (max ${maxValue})`
2947
+ );
2948
+ }
2949
+ const bytes = new Uint8Array(length);
2950
+ let remaining = value;
2951
+ for (let i = length - 1; i >= 0; i--) {
2952
+ bytes[i] = Number(remaining & 0xffn);
2953
+ remaining >>= 8n;
2954
+ }
2955
+ return bytes;
2956
+ }
2957
+ function concatBytes(...arrays) {
2958
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
2959
+ const result = new Uint8Array(totalLength);
2960
+ let offset = 0;
2961
+ for (const arr of arrays) {
2962
+ result.set(arr, offset);
2963
+ offset += arr.length;
2964
+ }
2965
+ return result;
2966
+ }
2967
+
2968
+ // src/utils/walletDetection.ts
2969
+ async function waitForWalletDetection(adapter, timeoutMs = 5e3) {
2970
+ if (adapter.readyState === "Installed") return;
2971
+ return new Promise((resolve, reject) => {
2972
+ let settled = false;
2973
+ const settle = () => {
2974
+ if (settled) return;
2975
+ settled = true;
2976
+ clearTimeout(timer);
2977
+ adapter.off("readyStateChange", onReady);
2978
+ resolve();
2979
+ };
2980
+ const timer = setTimeout(() => {
2981
+ if (settled) return;
2982
+ settled = true;
2983
+ adapter.off("readyStateChange", onReady);
2984
+ reject(
2985
+ new Error(
2986
+ `Wallet extension not detected within ${timeoutMs}ms. Is the browser extension installed and enabled?`
2987
+ )
2988
+ );
2989
+ }, timeoutMs);
2990
+ const onReady = (state) => {
2991
+ if (state === "Installed") settle();
2992
+ };
2993
+ adapter.on("readyStateChange", onReady);
2994
+ if (adapter.readyState === "Installed") settle();
2995
+ });
2996
+ }
2997
+
2998
+ // src/utils/storage.ts
2999
+ async function migrateStorage(options) {
3000
+ if (typeof window === "undefined") return false;
3001
+ const versionKey = options.versionKey ?? "miden:storageVersion";
3002
+ const stored = localStorage.getItem(versionKey);
3003
+ if (stored === options.version) return false;
3004
+ if (options.onBeforeClear) {
3005
+ await options.onBeforeClear();
3006
+ }
3007
+ await clearMidenStorage();
3008
+ localStorage.setItem(versionKey, options.version);
3009
+ if (options.reloadOnClear !== false) {
3010
+ window.location.reload();
3011
+ }
3012
+ return true;
3013
+ }
3014
+ async function clearMidenStorage() {
3015
+ if (typeof indexedDB === "undefined") return;
3016
+ try {
3017
+ const databases = await indexedDB.databases();
3018
+ const midenDbs = databases.filter(
3019
+ (db) => db.name?.toLowerCase().includes("miden")
3020
+ );
3021
+ await Promise.all(
3022
+ midenDbs.map(
3023
+ (db) => new Promise((resolve, reject) => {
3024
+ if (!db.name) {
3025
+ resolve();
3026
+ return;
3027
+ }
3028
+ const req = indexedDB.deleteDatabase(db.name);
3029
+ req.onsuccess = () => resolve();
3030
+ req.onerror = () => reject(req.error);
3031
+ req.onblocked = () => {
3032
+ console.warn(
3033
+ `IndexedDB "${db.name}" delete was blocked \u2014 close other tabs using this database.`
3034
+ );
3035
+ resolve();
3036
+ };
3037
+ })
3038
+ )
3039
+ );
3040
+ } catch {
3041
+ }
3042
+ }
3043
+ function createMidenStorage(prefix) {
3044
+ const fullKey = (key) => `${prefix}:${key}`;
3045
+ return {
3046
+ get(key) {
3047
+ try {
3048
+ const raw = localStorage.getItem(fullKey(key));
3049
+ if (raw === null) return null;
3050
+ return JSON.parse(raw);
3051
+ } catch {
3052
+ return null;
3053
+ }
3054
+ },
3055
+ set(key, value) {
3056
+ try {
3057
+ localStorage.setItem(fullKey(key), JSON.stringify(value));
3058
+ } catch (e) {
3059
+ console.warn(`Failed to write localStorage key "${fullKey(key)}":`, e);
3060
+ }
3061
+ },
3062
+ remove(key) {
3063
+ localStorage.removeItem(fullKey(key));
3064
+ },
3065
+ clear() {
3066
+ const keysToRemove = [];
3067
+ for (let i = 0; i < localStorage.length; i++) {
3068
+ const k = localStorage.key(i);
3069
+ if (k?.startsWith(`${prefix}:`)) {
3070
+ keysToRemove.push(k);
3071
+ }
3072
+ }
3073
+ keysToRemove.forEach((k) => localStorage.removeItem(k));
3074
+ }
3075
+ };
3076
+ }
3077
+
2322
3078
  // src/index.ts
2323
3079
  installAccountBech32();
2324
3080
  // Annotate the CommonJS export names for ESM import in node:
2325
3081
  0 && (module.exports = {
3082
+ AuthScheme,
2326
3083
  DEFAULTS,
3084
+ MidenError,
2327
3085
  MidenProvider,
2328
3086
  SignerContext,
3087
+ accountIdsEqual,
3088
+ bigIntToBytes,
3089
+ bytesToBigInt,
3090
+ clearMidenStorage,
3091
+ concatBytes,
3092
+ createMidenStorage,
3093
+ createNoteAttachment,
2329
3094
  formatAssetAmount,
2330
3095
  formatNoteSummary,
2331
3096
  getNoteSummary,
3097
+ migrateStorage,
3098
+ normalizeAccountId,
2332
3099
  parseAssetAmount,
3100
+ readNoteAttachment,
2333
3101
  toBech32AccountId,
2334
3102
  useAccount,
2335
3103
  useAccounts,
@@ -2343,13 +3111,17 @@ installAccountBech32();
2343
3111
  useMidenClient,
2344
3112
  useMint,
2345
3113
  useMultiSend,
3114
+ useNoteStream,
2346
3115
  useNotes,
2347
3116
  useSend,
3117
+ useSessionAccount,
2348
3118
  useSigner,
2349
3119
  useSwap,
2350
3120
  useSyncState,
2351
3121
  useTransaction,
2352
3122
  useTransactionHistory,
2353
3123
  useWaitForCommit,
2354
- useWaitForNotes
3124
+ useWaitForNotes,
3125
+ waitForWalletDetection,
3126
+ wrapWasmError
2355
3127
  });