@miden-sdk/react 0.13.1 → 0.13.3

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
@@ -31,12 +31,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  DEFAULTS: () => DEFAULTS,
34
+ MidenError: () => MidenError,
34
35
  MidenProvider: () => MidenProvider,
35
36
  SignerContext: () => SignerContext,
37
+ accountIdsEqual: () => accountIdsEqual,
38
+ bigIntToBytes: () => bigIntToBytes,
39
+ bytesToBigInt: () => bytesToBigInt,
40
+ clearMidenStorage: () => clearMidenStorage,
41
+ concatBytes: () => concatBytes,
42
+ createMidenStorage: () => createMidenStorage,
43
+ createNoteAttachment: () => createNoteAttachment,
36
44
  formatAssetAmount: () => formatAssetAmount,
37
45
  formatNoteSummary: () => formatNoteSummary,
38
46
  getNoteSummary: () => getNoteSummary,
47
+ migrateStorage: () => migrateStorage,
48
+ normalizeAccountId: () => normalizeAccountId,
39
49
  parseAssetAmount: () => parseAssetAmount,
50
+ readNoteAttachment: () => readNoteAttachment,
40
51
  toBech32AccountId: () => toBech32AccountId,
41
52
  useAccount: () => useAccount,
42
53
  useAccounts: () => useAccounts,
@@ -50,15 +61,19 @@ __export(index_exports, {
50
61
  useMidenClient: () => useMidenClient,
51
62
  useMint: () => useMint,
52
63
  useMultiSend: () => useMultiSend,
64
+ useNoteStream: () => useNoteStream,
53
65
  useNotes: () => useNotes,
54
66
  useSend: () => useSend,
67
+ useSessionAccount: () => useSessionAccount,
55
68
  useSigner: () => useSigner,
56
69
  useSwap: () => useSwap,
57
70
  useSyncState: () => useSyncState,
58
71
  useTransaction: () => useTransaction,
59
72
  useTransactionHistory: () => useTransactionHistory,
60
73
  useWaitForCommit: () => useWaitForCommit,
61
- useWaitForNotes: () => useWaitForNotes
74
+ useWaitForNotes: () => useWaitForNotes,
75
+ waitForWalletDetection: () => waitForWalletDetection,
76
+ wrapWasmError: () => wrapWasmError
62
77
  });
63
78
  module.exports = __toCommonJS(index_exports);
64
79
 
@@ -88,6 +103,7 @@ var initialState = {
88
103
  notes: [],
89
104
  consumableNotes: [],
90
105
  assetMetadata: /* @__PURE__ */ new Map(),
106
+ noteFirstSeen: /* @__PURE__ */ new Map(),
91
107
  isLoadingAccounts: false,
92
108
  isLoadingNotes: false
93
109
  };
@@ -115,8 +131,74 @@ var useMidenStore = (0, import_zustand.create)()((set) => ({
115
131
  newMap.set(accountId, account);
116
132
  return { accountDetails: newMap };
117
133
  }),
118
- setNotes: (notes) => set({ notes }),
134
+ setNotes: (notes) => set((state) => {
135
+ const now = Date.now();
136
+ const newFirstSeen = /* @__PURE__ */ new Map();
137
+ for (const note of notes) {
138
+ try {
139
+ const id = note.id().toString();
140
+ newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
141
+ } catch {
142
+ }
143
+ }
144
+ return { notes, noteFirstSeen: newFirstSeen };
145
+ }),
146
+ setNotesIfChanged: (notes) => set((state) => {
147
+ const safeId = (n) => {
148
+ try {
149
+ return n.id().toString();
150
+ } catch {
151
+ return null;
152
+ }
153
+ };
154
+ const prevIds = /* @__PURE__ */ new Set();
155
+ for (const n of state.notes) {
156
+ const id = safeId(n);
157
+ if (id) prevIds.add(id);
158
+ }
159
+ const newIds = /* @__PURE__ */ new Set();
160
+ for (const n of notes) {
161
+ const id = safeId(n);
162
+ if (id) newIds.add(id);
163
+ }
164
+ if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
165
+ return {};
166
+ }
167
+ const now = Date.now();
168
+ const newFirstSeen = /* @__PURE__ */ new Map();
169
+ for (const note of notes) {
170
+ try {
171
+ const id = note.id().toString();
172
+ newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
173
+ } catch {
174
+ }
175
+ }
176
+ return { notes, noteFirstSeen: newFirstSeen };
177
+ }),
119
178
  setConsumableNotes: (consumableNotes) => set({ consumableNotes }),
179
+ setConsumableNotesIfChanged: (consumableNotes) => set((state) => {
180
+ const safeId = (n) => {
181
+ try {
182
+ return n.inputNoteRecord().id().toString();
183
+ } catch {
184
+ return null;
185
+ }
186
+ };
187
+ const prevIds = /* @__PURE__ */ new Set();
188
+ for (const n of state.consumableNotes) {
189
+ const id = safeId(n);
190
+ if (id) prevIds.add(id);
191
+ }
192
+ const newIds = /* @__PURE__ */ new Set();
193
+ for (const n of consumableNotes) {
194
+ const id = safeId(n);
195
+ if (id) newIds.add(id);
196
+ }
197
+ if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
198
+ return {};
199
+ }
200
+ return { consumableNotes };
201
+ }),
120
202
  setAssetMetadata: (assetId, metadata) => set((state) => {
121
203
  const newMap = new Map(state.assetMetadata);
122
204
  newMap.set(assetId, metadata);
@@ -131,6 +213,7 @@ var useAccountsStore = () => useMidenStore((state) => state.accounts);
131
213
  var useNotesStore = () => useMidenStore((state) => state.notes);
132
214
  var useConsumableNotesStore = () => useMidenStore((state) => state.consumableNotes);
133
215
  var useAssetMetadataStore = () => useMidenStore((state) => state.assetMetadata);
216
+ var useNoteFirstSeenStore = () => useMidenStore((state) => state.noteFirstSeen);
134
217
 
135
218
  // src/utils/accountParsing.ts
136
219
  var import_miden_sdk2 = require("@miden-sdk/miden-sdk");
@@ -154,6 +237,19 @@ var parseAccountId = (value) => {
154
237
  const normalized = normalizeAccountIdInput(value);
155
238
  return parseAccountIdFromString(normalized);
156
239
  };
240
+ function isFaucetId(accountId) {
241
+ try {
242
+ let hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
243
+ if (hex.startsWith("0x") || hex.startsWith("0X")) {
244
+ hex = hex.slice(2);
245
+ }
246
+ const firstByte = parseInt(hex.slice(0, 2), 16);
247
+ const accountType = firstByte >> 4 & 3;
248
+ return accountType === 2 || accountType === 3;
249
+ } catch {
250
+ return false;
251
+ }
252
+ }
157
253
  var parseAddress = (value, accountId) => {
158
254
  const normalized = normalizeAccountIdInput(value);
159
255
  if (isBech32Input(normalized)) {
@@ -390,19 +486,29 @@ function isPrivateStorageMode(storageMode) {
390
486
  return storageMode.toString() === "private";
391
487
  }
392
488
  async function initializeSignerAccount(client, config) {
393
- const { AccountBuilder, AccountComponent, Word } = await import("@miden-sdk/miden-sdk");
489
+ const { AccountBuilder, AccountComponent, Word: Word2 } = await import("@miden-sdk/miden-sdk");
394
490
  await client.syncState();
395
- const commitmentWord = Word.deserialize(config.publicKeyCommitment);
491
+ const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
396
492
  const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
397
493
  const accountType = await getAccountType(config.accountType);
398
- const builder = new AccountBuilder(seed);
399
- const buildResult = builder.withAuthComponent(
494
+ let builder = new AccountBuilder(seed).withAuthComponent(
400
495
  AccountComponent.createAuthComponentFromCommitment(
401
496
  commitmentWord,
402
497
  1
403
498
  // ECDSA auth scheme (K256/Keccak)
404
499
  )
405
- ).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent().build();
500
+ ).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent();
501
+ if (config.customComponents?.length) {
502
+ for (const component of config.customComponents) {
503
+ if (component == null || typeof component.getProcedures !== "function") {
504
+ throw new Error(
505
+ "Each entry in customComponents must be an AccountComponent instance created via AccountComponent.compile(), AccountComponent.fromPackage(), or AccountComponent.fromLibrary()."
506
+ );
507
+ }
508
+ builder = builder.withComponent(component);
509
+ }
510
+ }
511
+ const buildResult = builder.build();
406
512
  const account = buildResult.account;
407
513
  const accountId = account.id();
408
514
  if (!isPrivateStorageMode(config.storageMode)) {
@@ -499,63 +605,91 @@ function MidenProvider({
499
605
  (0, import_react2.useEffect)(() => {
500
606
  if (!signerContext && isInitializedRef.current) return;
501
607
  if (signerContext && !signerContext.isConnected) {
502
- if (client) {
608
+ if (useMidenStore.getState().client) {
503
609
  useMidenStore.getState().reset();
504
610
  setClient(null);
505
611
  setSignerAccountId(null);
506
612
  }
507
613
  return;
508
614
  }
509
- if (!signerContext) {
510
- isInitializedRef.current = true;
511
- }
615
+ let cancelled = false;
512
616
  const initClient = async () => {
513
- setInitializing(true);
514
- setConfig(resolvedConfig);
515
- try {
516
- let webClient;
517
- if (signerContext && signerContext.isConnected) {
518
- const storeName = `MidenClientDB_${signerContext.storeName}`;
519
- webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
520
- resolvedConfig.rpcUrl,
521
- resolvedConfig.noteTransportUrl,
522
- resolvedConfig.seed,
523
- storeName,
524
- void 0,
525
- // getKeyCb - not needed for public accounts
526
- void 0,
527
- // insertKeyCb - not needed for public accounts
528
- signerContext.signCb
529
- );
530
- const accountId = await initializeSignerAccount(
531
- webClient,
532
- signerContext.accountConfig
533
- );
534
- setSignerAccountId(accountId);
535
- } else {
536
- const seed = resolvedConfig.seed;
537
- webClient = await import_miden_sdk5.WebClient.createClient(
538
- resolvedConfig.rpcUrl,
539
- resolvedConfig.noteTransportUrl,
540
- seed
541
- );
542
- }
543
- setClient(webClient);
617
+ await runExclusive(async () => {
618
+ if (cancelled) return;
619
+ setInitializing(true);
620
+ setConfig(resolvedConfig);
544
621
  try {
545
- const summary = await runExclusive(() => webClient.syncState());
546
- setSyncState({
547
- syncHeight: summary.blockNum(),
548
- lastSyncTime: Date.now()
549
- });
550
- const accounts = await webClient.getAccounts();
551
- useMidenStore.getState().setAccounts(accounts);
552
- } catch {
622
+ let webClient;
623
+ let didSignerInit = false;
624
+ if (signerContext && signerContext.isConnected) {
625
+ const storeName = `MidenClientDB_${signerContext.storeName}`;
626
+ webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
627
+ resolvedConfig.rpcUrl,
628
+ resolvedConfig.noteTransportUrl,
629
+ resolvedConfig.seed,
630
+ storeName,
631
+ void 0,
632
+ // getKeyCb - not needed for public accounts
633
+ void 0,
634
+ // insertKeyCb - not needed for public accounts
635
+ signerContext.signCb
636
+ );
637
+ if (cancelled) return;
638
+ const accountId = await initializeSignerAccount(
639
+ webClient,
640
+ signerContext.accountConfig
641
+ );
642
+ if (cancelled) return;
643
+ setSignerAccountId(accountId);
644
+ didSignerInit = true;
645
+ } else {
646
+ const seed = resolvedConfig.seed;
647
+ webClient = await import_miden_sdk5.WebClient.createClient(
648
+ resolvedConfig.rpcUrl,
649
+ resolvedConfig.noteTransportUrl,
650
+ seed
651
+ );
652
+ if (cancelled) return;
653
+ }
654
+ if (!didSignerInit) {
655
+ try {
656
+ const summary = await webClient.syncState();
657
+ if (cancelled) return;
658
+ setSyncState({
659
+ syncHeight: summary.blockNum(),
660
+ lastSyncTime: Date.now()
661
+ });
662
+ } catch {
663
+ }
664
+ }
665
+ if (!cancelled) {
666
+ try {
667
+ const accounts = await webClient.getAccounts();
668
+ if (cancelled) return;
669
+ useMidenStore.getState().setAccounts(accounts);
670
+ } catch {
671
+ }
672
+ }
673
+ if (!cancelled) {
674
+ if (!signerContext) {
675
+ isInitializedRef.current = true;
676
+ }
677
+ setClient(webClient);
678
+ }
679
+ } catch (error) {
680
+ if (!cancelled) {
681
+ setInitError(
682
+ error instanceof Error ? error : new Error(String(error))
683
+ );
684
+ }
553
685
  }
554
- } catch (error) {
555
- setInitError(error instanceof Error ? error : new Error(String(error)));
556
- }
686
+ });
557
687
  };
558
688
  initClient();
689
+ return () => {
690
+ cancelled = true;
691
+ isInitializedRef.current = false;
692
+ };
559
693
  }, [
560
694
  runExclusive,
561
695
  resolvedConfig,
@@ -564,8 +698,7 @@ function MidenProvider({
564
698
  setInitError,
565
699
  setInitializing,
566
700
  setSyncState,
567
- signerContext,
568
- client
701
+ signerContext
569
702
  ]);
570
703
  (0, import_react2.useEffect)(() => {
571
704
  if (!isReady || !client) return;
@@ -671,16 +804,6 @@ function useAccounts() {
671
804
  refetch
672
805
  };
673
806
  }
674
- function isFaucetId(accountId) {
675
- try {
676
- const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
677
- const firstByte = parseInt(hex.slice(0, 2), 16);
678
- const accountType = firstByte >> 4 & 3;
679
- return accountType === 2 || accountType === 3;
680
- } catch {
681
- return false;
682
- }
683
- }
684
807
 
685
808
  // src/hooks/useAccount.ts
686
809
  var import_react5 = require("react");
@@ -703,17 +826,12 @@ var getRpcClient = (rpcUrl) => {
703
826
  return null;
704
827
  }
705
828
  };
706
- var fetchAssetMetadata = async (client, rpcClient, assetId) => {
829
+ var fetchAssetMetadata = async (rpcClient, assetId) => {
707
830
  try {
708
831
  const accountId = parseAccountId(assetId);
709
- let account = await client.getAccount(accountId);
710
- if (!account && rpcClient) {
711
- try {
712
- const fetched = await rpcClient.getAccountDetails(accountId);
713
- account = fetched.account?.();
714
- } catch {
715
- }
716
- }
832
+ if (!isFaucetId(accountId)) return null;
833
+ const fetched = await rpcClient.getAccountDetails(accountId);
834
+ const account = fetched.account?.();
717
835
  if (!account) return null;
718
836
  const faucet = import_miden_sdk6.BasicFungibleFaucetComponent.fromAccount(account);
719
837
  const symbol = faucet.symbol().toString();
@@ -724,8 +842,6 @@ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
724
842
  }
725
843
  };
726
844
  function useAssetMetadata(assetIds = []) {
727
- const { client, isReady, runExclusive } = useMiden();
728
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
729
845
  const assetMetadata = useAssetMetadataStore();
730
846
  const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
731
847
  const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
@@ -735,32 +851,19 @@ function useAssetMetadata(assetIds = []) {
735
851
  [assetIds]
736
852
  );
737
853
  (0, import_react4.useEffect)(() => {
738
- if (!client || !isReady || uniqueAssetIds.length === 0) return;
854
+ if (!rpcClient || uniqueAssetIds.length === 0) return;
739
855
  uniqueAssetIds.forEach((assetId) => {
740
856
  const existing = assetMetadata.get(assetId);
741
857
  const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
742
858
  if (hasMetadata || inflight.has(assetId)) return;
743
- const promise = runExclusiveSafe(async () => {
744
- const metadata = await fetchAssetMetadata(
745
- client,
746
- rpcClient,
747
- assetId
748
- );
859
+ const promise = fetchAssetMetadata(rpcClient, assetId).then((metadata) => {
749
860
  setAssetMetadata(assetId, metadata ?? { assetId });
750
861
  }).finally(() => {
751
862
  inflight.delete(assetId);
752
863
  });
753
864
  inflight.set(assetId, promise);
754
865
  });
755
- }, [
756
- client,
757
- isReady,
758
- uniqueAssetIds,
759
- assetMetadata,
760
- runExclusiveSafe,
761
- setAssetMetadata,
762
- rpcClient
763
- ]);
866
+ }, [uniqueAssetIds, assetMetadata, setAssetMetadata, rpcClient]);
764
867
  return { assetMetadata };
765
868
  }
766
869
 
@@ -862,7 +965,7 @@ function useAccount(accountId) {
862
965
 
863
966
  // src/hooks/useNotes.ts
864
967
  var import_react6 = require("react");
865
- var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
968
+ var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
866
969
 
867
970
  // src/utils/amounts.ts
868
971
  var formatAssetAmount = (amount, decimals) => {
@@ -946,6 +1049,82 @@ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(
946
1049
  return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
947
1050
  };
948
1051
 
1052
+ // src/utils/accountId.ts
1053
+ function normalizeAccountId(id) {
1054
+ return toBech32AccountId(id);
1055
+ }
1056
+ function accountIdsEqual(a, b) {
1057
+ let idA;
1058
+ let idB;
1059
+ try {
1060
+ idA = parseAccountId(a);
1061
+ idB = parseAccountId(b);
1062
+ return idA.toString() === idB.toString();
1063
+ } catch {
1064
+ return a === b;
1065
+ } finally {
1066
+ idA?.free?.();
1067
+ idB?.free?.();
1068
+ }
1069
+ }
1070
+
1071
+ // src/utils/noteFilters.ts
1072
+ var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
1073
+ function getNoteFilterType(status) {
1074
+ switch (status) {
1075
+ case "consumed":
1076
+ return import_miden_sdk7.NoteFilterTypes.Consumed;
1077
+ case "committed":
1078
+ return import_miden_sdk7.NoteFilterTypes.Committed;
1079
+ case "expected":
1080
+ return import_miden_sdk7.NoteFilterTypes.Expected;
1081
+ case "processing":
1082
+ return import_miden_sdk7.NoteFilterTypes.Processing;
1083
+ case "all":
1084
+ default:
1085
+ return import_miden_sdk7.NoteFilterTypes.All;
1086
+ }
1087
+ }
1088
+ function getNoteType(type) {
1089
+ switch (type) {
1090
+ case "private":
1091
+ return import_miden_sdk7.NoteType.Private;
1092
+ case "public":
1093
+ return import_miden_sdk7.NoteType.Public;
1094
+ default:
1095
+ return import_miden_sdk7.NoteType.Private;
1096
+ }
1097
+ }
1098
+ async function waitForTransactionCommit(client, runExclusiveSafe, txIdHex, maxWaitMs = 1e4, delayMs = 1e3) {
1099
+ const deadline = Date.now() + maxWaitMs;
1100
+ const targetHex = normalizeHex(txIdHex);
1101
+ while (Date.now() < deadline) {
1102
+ await runExclusiveSafe(() => client.syncState());
1103
+ const records = await runExclusiveSafe(
1104
+ () => client.getTransactions(import_miden_sdk7.TransactionFilter.all())
1105
+ );
1106
+ const record = records.find(
1107
+ (r) => normalizeHex(r.id().toHex()) === targetHex
1108
+ );
1109
+ if (record) {
1110
+ const status = record.transactionStatus();
1111
+ if (status.isCommitted()) {
1112
+ return;
1113
+ }
1114
+ if (status.isDiscarded()) {
1115
+ throw new Error("Transaction was discarded before commit");
1116
+ }
1117
+ }
1118
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1119
+ }
1120
+ throw new Error("Timeout waiting for transaction commit");
1121
+ }
1122
+ function normalizeHex(value) {
1123
+ const trimmed = value.trim();
1124
+ const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1125
+ return normalized.toLowerCase();
1126
+ }
1127
+
949
1128
  // src/hooks/useNotes.ts
950
1129
  function useNotes(options) {
951
1130
  const { client, isReady, runExclusive } = useMiden();
@@ -954,8 +1133,10 @@ function useNotes(options) {
954
1133
  const consumableNotes = useConsumableNotesStore();
955
1134
  const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
956
1135
  const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
957
- const setNotes = useMidenStore((state) => state.setNotes);
958
- const setConsumableNotes = useMidenStore((state) => state.setConsumableNotes);
1136
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1137
+ const setConsumableNotesIfChanged = useMidenStore(
1138
+ (state) => state.setConsumableNotesIfChanged
1139
+ );
959
1140
  const { lastSyncTime } = useSyncStateStore();
960
1141
  const [error, setError] = (0, import_react6.useState)(null);
961
1142
  const refetch = (0, import_react6.useCallback)(async () => {
@@ -966,7 +1147,7 @@ function useNotes(options) {
966
1147
  const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
967
1148
  async () => {
968
1149
  const filterType = getNoteFilterType(options?.status);
969
- const filter = new import_miden_sdk7.NoteFilter(filterType);
1150
+ const filter = new import_miden_sdk8.NoteFilter(filterType);
970
1151
  const notesResult = await client.getInputNotes(filter);
971
1152
  let consumableResult;
972
1153
  if (options?.accountId) {
@@ -981,8 +1162,8 @@ function useNotes(options) {
981
1162
  };
982
1163
  }
983
1164
  );
984
- setNotes(fetchedNotes);
985
- setConsumableNotes(fetchedConsumable);
1165
+ setNotesIfChanged(fetchedNotes);
1166
+ setConsumableNotesIfChanged(fetchedConsumable);
986
1167
  } catch (err) {
987
1168
  setError(err instanceof Error ? err : new Error(String(err)));
988
1169
  } finally {
@@ -995,8 +1176,8 @@ function useNotes(options) {
995
1176
  options?.status,
996
1177
  options?.accountId,
997
1178
  setLoadingNotes,
998
- setNotes,
999
- setConsumableNotes
1179
+ setNotesIfChanged,
1180
+ setConsumableNotesIfChanged
1000
1181
  ]);
1001
1182
  (0, import_react6.useEffect)(() => {
1002
1183
  if (isReady && notes.length === 0) {
@@ -1023,14 +1204,65 @@ function useNotes(options) {
1023
1204
  (assetId) => assetMetadata.get(assetId),
1024
1205
  [assetMetadata]
1025
1206
  );
1026
- const noteSummaries = (0, import_react6.useMemo)(
1027
- () => notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1028
- [notes, getMetadata]
1029
- );
1030
- const consumableNoteSummaries = (0, import_react6.useMemo)(
1031
- () => consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1032
- [consumableNotes, getMetadata]
1207
+ const normalizedSender = (0, import_react6.useMemo)(() => {
1208
+ if (!options?.sender) return null;
1209
+ try {
1210
+ return normalizeAccountId(options.sender);
1211
+ } catch {
1212
+ return options.sender;
1213
+ }
1214
+ }, [options?.sender]);
1215
+ const excludeIdsKey = (0, import_react6.useMemo)(() => {
1216
+ if (!options?.excludeIds || options.excludeIds.length === 0) return "";
1217
+ return [...options.excludeIds].sort().join("\0");
1218
+ }, [options?.excludeIds]);
1219
+ const filterBySender = (0, import_react6.useCallback)(
1220
+ (summaries, target) => {
1221
+ const cache = /* @__PURE__ */ new Map();
1222
+ return summaries.filter((s) => {
1223
+ if (!s.sender) return false;
1224
+ let normalized = cache.get(s.sender);
1225
+ if (normalized === void 0) {
1226
+ try {
1227
+ normalized = normalizeAccountId(s.sender);
1228
+ } catch {
1229
+ normalized = s.sender;
1230
+ }
1231
+ cache.set(s.sender, normalized);
1232
+ }
1233
+ return normalized === target;
1234
+ });
1235
+ },
1236
+ []
1033
1237
  );
1238
+ const noteSummaries = (0, import_react6.useMemo)(() => {
1239
+ let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
1240
+ if (normalizedSender) {
1241
+ summaries = filterBySender(summaries, normalizedSender);
1242
+ }
1243
+ if (excludeIdsKey) {
1244
+ const excludeSet = new Set(excludeIdsKey.split("\0"));
1245
+ summaries = summaries.filter((s) => !excludeSet.has(s.id));
1246
+ }
1247
+ return summaries;
1248
+ }, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
1249
+ const consumableNoteSummaries = (0, import_react6.useMemo)(() => {
1250
+ let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
1251
+ if (normalizedSender) {
1252
+ summaries = filterBySender(summaries, normalizedSender);
1253
+ }
1254
+ if (excludeIdsKey) {
1255
+ const excludeSet = new Set(excludeIdsKey.split("\0"));
1256
+ summaries = summaries.filter((s) => !excludeSet.has(s.id));
1257
+ }
1258
+ return summaries;
1259
+ }, [
1260
+ consumableNotes,
1261
+ getMetadata,
1262
+ normalizedSender,
1263
+ excludeIdsKey,
1264
+ filterBySender
1265
+ ]);
1034
1266
  return {
1035
1267
  notes,
1036
1268
  consumableNotes,
@@ -1041,46 +1273,246 @@ function useNotes(options) {
1041
1273
  refetch
1042
1274
  };
1043
1275
  }
1044
- function getNoteFilterType(status) {
1045
- switch (status) {
1046
- case "consumed":
1047
- return import_miden_sdk7.NoteFilterTypes.Consumed;
1048
- case "committed":
1049
- return import_miden_sdk7.NoteFilterTypes.Committed;
1050
- case "expected":
1051
- return import_miden_sdk7.NoteFilterTypes.Expected;
1052
- case "processing":
1053
- return import_miden_sdk7.NoteFilterTypes.Processing;
1054
- case "all":
1055
- default:
1056
- return import_miden_sdk7.NoteFilterTypes.All;
1276
+
1277
+ // src/hooks/useNoteStream.ts
1278
+ var import_react7 = require("react");
1279
+ var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
1280
+
1281
+ // src/utils/noteAttachment.ts
1282
+ var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
1283
+ function readNoteAttachment(note) {
1284
+ try {
1285
+ const metadata = note.metadata?.();
1286
+ if (!metadata) return null;
1287
+ const attachment = metadata.attachment?.();
1288
+ if (!attachment) return null;
1289
+ const kind = attachment.kind?.();
1290
+ if (!kind) return null;
1291
+ if (kind === import_miden_sdk9.NoteAttachmentKind.None) return null;
1292
+ if (kind === import_miden_sdk9.NoteAttachmentKind.Word) {
1293
+ const word = attachment.asWord?.();
1294
+ if (!word) return null;
1295
+ const u64s = word.toU64s();
1296
+ const values = Array.from(u64s).map(
1297
+ (v) => BigInt(v)
1298
+ );
1299
+ return { values, kind: "word" };
1300
+ }
1301
+ if (kind === import_miden_sdk9.NoteAttachmentKind.Array) {
1302
+ const arr = attachment.asArray?.();
1303
+ if (!arr) return null;
1304
+ const u64s = arr.toU64s();
1305
+ const values = Array.from(u64s).map(
1306
+ (v) => BigInt(v)
1307
+ );
1308
+ return { values, kind: "array" };
1309
+ }
1310
+ return null;
1311
+ } catch {
1312
+ return null;
1313
+ }
1314
+ }
1315
+ function createNoteAttachment(values) {
1316
+ const bigints = [];
1317
+ for (let i = 0; i < values.length; i++) {
1318
+ bigints.push(BigInt(values[i]));
1319
+ }
1320
+ if (bigints.length === 0) {
1321
+ return new import_miden_sdk9.NoteAttachment();
1322
+ }
1323
+ const scheme = import_miden_sdk9.NoteAttachmentScheme.none();
1324
+ if (bigints.length <= 4) {
1325
+ while (bigints.length < 4) {
1326
+ bigints.push(0n);
1327
+ }
1328
+ const word = new import_miden_sdk9.Word(BigUint64Array.from(bigints));
1329
+ return import_miden_sdk9.NoteAttachment.newWord(scheme, word);
1330
+ }
1331
+ while (bigints.length % 4 !== 0) {
1332
+ bigints.push(0n);
1333
+ }
1334
+ const words = [];
1335
+ for (let i = 0; i < bigints.length; i += 4) {
1336
+ words.push(new import_miden_sdk9.Word(BigUint64Array.from(bigints.slice(i, i + 4))));
1337
+ }
1338
+ const newArray = import_miden_sdk9.NoteAttachment["newArray"];
1339
+ if (typeof newArray !== "function") {
1340
+ throw new Error(
1341
+ "NoteAttachment.newArray is not available. Ensure @miden-sdk/miden-sdk >= 0.13.1."
1342
+ );
1057
1343
  }
1344
+ return newArray.call(import_miden_sdk9.NoteAttachment, scheme, words);
1058
1345
  }
1059
1346
 
1060
- // src/hooks/useTransactionHistory.ts
1061
- var import_react7 = require("react");
1062
- var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
1063
- function useTransactionHistory(options = {}) {
1347
+ // src/hooks/useNoteStream.ts
1348
+ function useNoteStream(options = {}) {
1064
1349
  const { client, isReady, runExclusive } = useMiden();
1065
1350
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1351
+ const allNotes = useNotesStore();
1352
+ const noteFirstSeen = useNoteFirstSeenStore();
1066
1353
  const { lastSyncTime } = useSyncStateStore();
1067
- const [records, setRecords] = (0, import_react7.useState)([]);
1354
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1068
1355
  const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1069
1356
  const [error, setError] = (0, import_react7.useState)(null);
1070
- const rawIds = (0, import_react7.useMemo)(() => {
1357
+ const handledIdsRef = (0, import_react7.useRef)(/* @__PURE__ */ new Set());
1358
+ const [handledVersion, setHandledVersion] = (0, import_react7.useState)(0);
1359
+ const status = options.status ?? "committed";
1360
+ const sender = options.sender ?? null;
1361
+ const since = options.since;
1362
+ const amountFilterRef = (0, import_react7.useRef)(options.amountFilter);
1363
+ amountFilterRef.current = options.amountFilter;
1364
+ const excludeIdsKey = (0, import_react7.useMemo)(() => {
1365
+ if (!options.excludeIds) return "";
1366
+ if (options.excludeIds instanceof Set)
1367
+ return Array.from(options.excludeIds).sort().join("\0");
1368
+ return [...options.excludeIds].sort().join("\0");
1369
+ }, [options.excludeIds]);
1370
+ const excludeIdSet = (0, import_react7.useMemo)(() => {
1371
+ if (!excludeIdsKey) return null;
1372
+ return new Set(excludeIdsKey.split("\0"));
1373
+ }, [excludeIdsKey]);
1374
+ const refetch = (0, import_react7.useCallback)(async () => {
1375
+ if (!client || !isReady) return;
1376
+ setIsLoading(true);
1377
+ setError(null);
1378
+ try {
1379
+ const filterType = getNoteFilterType(status);
1380
+ const filter = new import_miden_sdk10.NoteFilter(filterType);
1381
+ const fetched = await runExclusiveSafe(
1382
+ () => client.getInputNotes(filter)
1383
+ );
1384
+ setNotesIfChanged(fetched);
1385
+ } catch (err) {
1386
+ setError(err instanceof Error ? err : new Error(String(err)));
1387
+ } finally {
1388
+ setIsLoading(false);
1389
+ }
1390
+ }, [client, isReady, runExclusiveSafe, status, setNotesIfChanged]);
1391
+ (0, import_react7.useEffect)(() => {
1392
+ if (isReady) {
1393
+ refetch();
1394
+ }
1395
+ }, [isReady, lastSyncTime, refetch]);
1396
+ const streamedNotes = (0, import_react7.useMemo)(() => {
1397
+ void handledVersion;
1398
+ const result = [];
1399
+ let normalizedSender = null;
1400
+ if (sender) {
1401
+ try {
1402
+ normalizedSender = normalizeAccountId(sender);
1403
+ } catch {
1404
+ normalizedSender = sender;
1405
+ }
1406
+ }
1407
+ for (const record of allNotes) {
1408
+ const note = buildStreamedNote(record, noteFirstSeen);
1409
+ if (!note) continue;
1410
+ if (handledIdsRef.current.has(note.id)) continue;
1411
+ if (excludeIdSet && excludeIdSet.has(note.id)) continue;
1412
+ if (normalizedSender && note.sender !== normalizedSender) continue;
1413
+ if (since !== void 0 && note.firstSeenAt < since) continue;
1414
+ if (amountFilterRef.current && !amountFilterRef.current(note.amount))
1415
+ continue;
1416
+ result.push(note);
1417
+ }
1418
+ result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
1419
+ return result;
1420
+ }, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
1421
+ const latest = (0, import_react7.useMemo)(
1422
+ () => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
1423
+ [streamedNotes]
1424
+ );
1425
+ const markHandled = (0, import_react7.useCallback)((noteId) => {
1426
+ handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
1427
+ setHandledVersion((v) => v + 1);
1428
+ }, []);
1429
+ const markAllHandled = (0, import_react7.useCallback)(() => {
1430
+ const newSet = new Set(handledIdsRef.current);
1431
+ for (const note of streamedNotes) {
1432
+ newSet.add(note.id);
1433
+ }
1434
+ handledIdsRef.current = newSet;
1435
+ setHandledVersion((v) => v + 1);
1436
+ }, [streamedNotes]);
1437
+ const snapshot = (0, import_react7.useCallback)(() => {
1438
+ const ids = /* @__PURE__ */ new Set();
1439
+ for (const note of streamedNotes) {
1440
+ ids.add(note.id);
1441
+ }
1442
+ return { ids, timestamp: Date.now() };
1443
+ }, [streamedNotes]);
1444
+ return {
1445
+ notes: streamedNotes,
1446
+ latest,
1447
+ markHandled,
1448
+ markAllHandled,
1449
+ snapshot,
1450
+ isLoading,
1451
+ error
1452
+ };
1453
+ }
1454
+ function buildStreamedNote(record, noteFirstSeen) {
1455
+ try {
1456
+ const id = record.id().toString();
1457
+ const metadata = record.metadata?.();
1458
+ const senderHex = metadata?.sender?.()?.toString?.();
1459
+ const sender = senderHex ? toBech32AccountId(senderHex) : "";
1460
+ const assets = [];
1461
+ let primaryAmount = 0n;
1462
+ try {
1463
+ const details = record.details();
1464
+ const assetsList = details?.assets?.().fungibleAssets?.() ?? [];
1465
+ for (const asset of assetsList) {
1466
+ const assetId = asset.faucetId().toString();
1467
+ const amount = BigInt(asset.amount());
1468
+ assets.push({ assetId, amount });
1469
+ if (primaryAmount === 0n) {
1470
+ primaryAmount = amount;
1471
+ }
1472
+ }
1473
+ } catch {
1474
+ }
1475
+ const attachmentData = readNoteAttachment(record);
1476
+ const attachment = attachmentData ? attachmentData.values : null;
1477
+ const firstSeenAt = noteFirstSeen.get(id) ?? Date.now();
1478
+ return {
1479
+ id,
1480
+ sender,
1481
+ amount: primaryAmount,
1482
+ assets,
1483
+ record,
1484
+ firstSeenAt,
1485
+ attachment
1486
+ };
1487
+ } catch {
1488
+ return null;
1489
+ }
1490
+ }
1491
+
1492
+ // src/hooks/useTransactionHistory.ts
1493
+ var import_react8 = require("react");
1494
+ var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
1495
+ function useTransactionHistory(options = {}) {
1496
+ const { client, isReady, runExclusive } = useMiden();
1497
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1498
+ const { lastSyncTime } = useSyncStateStore();
1499
+ const [records, setRecords] = (0, import_react8.useState)([]);
1500
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
1501
+ const [error, setError] = (0, import_react8.useState)(null);
1502
+ const rawIds = (0, import_react8.useMemo)(() => {
1071
1503
  if (options.id) return [options.id];
1072
1504
  if (options.ids && options.ids.length > 0) return options.ids;
1073
1505
  return null;
1074
1506
  }, [options.id, options.ids]);
1075
- const idsHex = (0, import_react7.useMemo)(() => {
1507
+ const idsHex = (0, import_react8.useMemo)(() => {
1076
1508
  if (!rawIds) return null;
1077
1509
  return rawIds.map(
1078
- (id) => normalizeHex(typeof id === "string" ? id : id.toHex())
1510
+ (id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
1079
1511
  );
1080
1512
  }, [rawIds]);
1081
1513
  const filter = options.filter;
1082
1514
  const refreshOnSync = options.refreshOnSync !== false;
1083
- const refetch = (0, import_react7.useCallback)(async () => {
1515
+ const refetch = (0, import_react8.useCallback)(async () => {
1084
1516
  if (!client || !isReady) return;
1085
1517
  setIsLoading(true);
1086
1518
  setError(null);
@@ -1094,7 +1526,7 @@ function useTransactionHistory(options = {}) {
1094
1526
  () => client.getTransactions(resolvedFilter)
1095
1527
  );
1096
1528
  const filtered = localFilterHexes ? fetched.filter(
1097
- (record2) => localFilterHexes.includes(normalizeHex(record2.id().toHex()))
1529
+ (record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
1098
1530
  ) : fetched;
1099
1531
  setRecords(filtered);
1100
1532
  } catch (err) {
@@ -1103,19 +1535,19 @@ function useTransactionHistory(options = {}) {
1103
1535
  setIsLoading(false);
1104
1536
  }
1105
1537
  }, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
1106
- (0, import_react7.useEffect)(() => {
1538
+ (0, import_react8.useEffect)(() => {
1107
1539
  if (!isReady) return;
1108
1540
  refetch();
1109
1541
  }, [isReady, refetch]);
1110
- (0, import_react7.useEffect)(() => {
1542
+ (0, import_react8.useEffect)(() => {
1111
1543
  if (!isReady || !refreshOnSync || !lastSyncTime) return;
1112
1544
  refetch();
1113
1545
  }, [isReady, lastSyncTime, refreshOnSync, refetch]);
1114
- const record = (0, import_react7.useMemo)(() => {
1546
+ const record = (0, import_react8.useMemo)(() => {
1115
1547
  if (!idsHex || idsHex.length !== 1) return null;
1116
- return records.find((item) => normalizeHex(item.id().toHex()) === idsHex[0]) ?? null;
1548
+ return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
1117
1549
  }, [records, idsHex]);
1118
- const status = (0, import_react7.useMemo)(() => {
1550
+ const status = (0, import_react8.useMemo)(() => {
1119
1551
  if (!record) return null;
1120
1552
  const current = record.transactionStatus();
1121
1553
  if (current.isCommitted()) return "committed";
@@ -1137,29 +1569,29 @@ function buildFilter(filter, ids, idsHex) {
1137
1569
  return { filter };
1138
1570
  }
1139
1571
  if (!ids || ids.length === 0) {
1140
- return { filter: import_miden_sdk8.TransactionFilter.all() };
1572
+ return { filter: import_miden_sdk11.TransactionFilter.all() };
1141
1573
  }
1142
1574
  const allTransactionIds = ids.every((id) => typeof id !== "string");
1143
1575
  if (allTransactionIds) {
1144
- return { filter: import_miden_sdk8.TransactionFilter.ids(ids) };
1576
+ return { filter: import_miden_sdk11.TransactionFilter.ids(ids) };
1145
1577
  }
1146
1578
  return {
1147
- filter: import_miden_sdk8.TransactionFilter.all(),
1579
+ filter: import_miden_sdk11.TransactionFilter.all(),
1148
1580
  localFilterHexes: idsHex ?? []
1149
1581
  };
1150
1582
  }
1151
- function normalizeHex(value) {
1583
+ function normalizeHex2(value) {
1152
1584
  const trimmed = value.trim();
1153
1585
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1154
1586
  return normalized.toLowerCase();
1155
1587
  }
1156
1588
 
1157
1589
  // src/hooks/useSyncState.ts
1158
- var import_react8 = require("react");
1590
+ var import_react9 = require("react");
1159
1591
  function useSyncState() {
1160
1592
  const { sync: triggerSync } = useMiden();
1161
1593
  const syncState = useSyncStateStore();
1162
- const sync = (0, import_react8.useCallback)(async () => {
1594
+ const sync = (0, import_react9.useCallback)(async () => {
1163
1595
  await triggerSync();
1164
1596
  }, [triggerSync]);
1165
1597
  return {
@@ -1169,16 +1601,16 @@ function useSyncState() {
1169
1601
  }
1170
1602
 
1171
1603
  // src/hooks/useCreateWallet.ts
1172
- var import_react9 = require("react");
1173
- var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
1604
+ var import_react10 = require("react");
1605
+ var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
1174
1606
  function useCreateWallet() {
1175
1607
  const { client, isReady, sync, runExclusive } = useMiden();
1176
1608
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1177
1609
  const setAccounts = useMidenStore((state) => state.setAccounts);
1178
- const [wallet, setWallet] = (0, import_react9.useState)(null);
1179
- const [isCreating, setIsCreating] = (0, import_react9.useState)(false);
1180
- const [error, setError] = (0, import_react9.useState)(null);
1181
- const createWallet = (0, import_react9.useCallback)(
1610
+ const [wallet, setWallet] = (0, import_react10.useState)(null);
1611
+ const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
1612
+ const [error, setError] = (0, import_react10.useState)(null);
1613
+ const createWallet = (0, import_react10.useCallback)(
1182
1614
  async (options = {}) => {
1183
1615
  if (!client || !isReady) {
1184
1616
  throw new Error("Miden client is not ready");
@@ -1216,7 +1648,7 @@ function useCreateWallet() {
1216
1648
  },
1217
1649
  [client, isReady, runExclusive, setAccounts]
1218
1650
  );
1219
- const reset = (0, import_react9.useCallback)(() => {
1651
+ const reset = (0, import_react10.useCallback)(() => {
1220
1652
  setWallet(null);
1221
1653
  setIsCreating(false);
1222
1654
  setError(null);
@@ -1232,27 +1664,27 @@ function useCreateWallet() {
1232
1664
  function getStorageMode(mode) {
1233
1665
  switch (mode) {
1234
1666
  case "private":
1235
- return import_miden_sdk9.AccountStorageMode.private();
1667
+ return import_miden_sdk12.AccountStorageMode.private();
1236
1668
  case "public":
1237
- return import_miden_sdk9.AccountStorageMode.public();
1669
+ return import_miden_sdk12.AccountStorageMode.public();
1238
1670
  case "network":
1239
- return import_miden_sdk9.AccountStorageMode.network();
1671
+ return import_miden_sdk12.AccountStorageMode.network();
1240
1672
  default:
1241
- return import_miden_sdk9.AccountStorageMode.private();
1673
+ return import_miden_sdk12.AccountStorageMode.private();
1242
1674
  }
1243
1675
  }
1244
1676
 
1245
1677
  // src/hooks/useCreateFaucet.ts
1246
- var import_react10 = require("react");
1247
- var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
1678
+ var import_react11 = require("react");
1679
+ var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
1248
1680
  function useCreateFaucet() {
1249
1681
  const { client, isReady, runExclusive } = useMiden();
1250
1682
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1251
1683
  const setAccounts = useMidenStore((state) => state.setAccounts);
1252
- const [faucet, setFaucet] = (0, import_react10.useState)(null);
1253
- const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
1254
- const [error, setError] = (0, import_react10.useState)(null);
1255
- const createFaucet = (0, import_react10.useCallback)(
1684
+ const [faucet, setFaucet] = (0, import_react11.useState)(null);
1685
+ const [isCreating, setIsCreating] = (0, import_react11.useState)(false);
1686
+ const [error, setError] = (0, import_react11.useState)(null);
1687
+ const createFaucet = (0, import_react11.useCallback)(
1256
1688
  async (options) => {
1257
1689
  if (!client || !isReady) {
1258
1690
  throw new Error("Miden client is not ready");
@@ -1291,7 +1723,7 @@ function useCreateFaucet() {
1291
1723
  },
1292
1724
  [client, isReady, runExclusive, setAccounts]
1293
1725
  );
1294
- const reset = (0, import_react10.useCallback)(() => {
1726
+ const reset = (0, import_react11.useCallback)(() => {
1295
1727
  setFaucet(null);
1296
1728
  setIsCreating(false);
1297
1729
  setError(null);
@@ -1307,27 +1739,27 @@ function useCreateFaucet() {
1307
1739
  function getStorageMode2(mode) {
1308
1740
  switch (mode) {
1309
1741
  case "private":
1310
- return import_miden_sdk10.AccountStorageMode.private();
1742
+ return import_miden_sdk13.AccountStorageMode.private();
1311
1743
  case "public":
1312
- return import_miden_sdk10.AccountStorageMode.public();
1744
+ return import_miden_sdk13.AccountStorageMode.public();
1313
1745
  case "network":
1314
- return import_miden_sdk10.AccountStorageMode.network();
1746
+ return import_miden_sdk13.AccountStorageMode.network();
1315
1747
  default:
1316
- return import_miden_sdk10.AccountStorageMode.private();
1748
+ return import_miden_sdk13.AccountStorageMode.private();
1317
1749
  }
1318
1750
  }
1319
1751
 
1320
1752
  // src/hooks/useImportAccount.ts
1321
- var import_react11 = require("react");
1322
- var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
1753
+ var import_react12 = require("react");
1754
+ var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
1323
1755
  function useImportAccount() {
1324
1756
  const { client, isReady, runExclusive } = useMiden();
1325
1757
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1326
1758
  const setAccounts = useMidenStore((state) => state.setAccounts);
1327
- const [account, setAccount] = (0, import_react11.useState)(null);
1328
- const [isImporting, setIsImporting] = (0, import_react11.useState)(false);
1329
- const [error, setError] = (0, import_react11.useState)(null);
1330
- const importAccount = (0, import_react11.useCallback)(
1759
+ const [account, setAccount] = (0, import_react12.useState)(null);
1760
+ const [isImporting, setIsImporting] = (0, import_react12.useState)(false);
1761
+ const [error, setError] = (0, import_react12.useState)(null);
1762
+ const importAccount = (0, import_react12.useCallback)(
1331
1763
  async (options) => {
1332
1764
  if (!client || !isReady) {
1333
1765
  throw new Error("Miden client is not ready");
@@ -1422,7 +1854,7 @@ function useImportAccount() {
1422
1854
  },
1423
1855
  [client, isReady, runExclusive, setAccounts]
1424
1856
  );
1425
- const reset = (0, import_react11.useCallback)(() => {
1857
+ const reset = (0, import_react12.useCallback)(() => {
1426
1858
  setAccount(null);
1427
1859
  setIsImporting(false);
1428
1860
  setError(null);
@@ -1440,10 +1872,10 @@ function resolveAccountId(accountId) {
1440
1872
  }
1441
1873
  async function resolveAccountFile(file) {
1442
1874
  if (file instanceof Uint8Array) {
1443
- return import_miden_sdk11.AccountFile.deserialize(file);
1875
+ return import_miden_sdk14.AccountFile.deserialize(file);
1444
1876
  }
1445
1877
  if (file instanceof ArrayBuffer) {
1446
- return import_miden_sdk11.AccountFile.deserialize(new Uint8Array(file));
1878
+ return import_miden_sdk14.AccountFile.deserialize(new Uint8Array(file));
1447
1879
  }
1448
1880
  return file;
1449
1881
  }
@@ -1472,43 +1904,146 @@ function bytesEqual(left, right) {
1472
1904
  }
1473
1905
 
1474
1906
  // src/hooks/useSend.ts
1475
- var import_react12 = require("react");
1476
- var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
1907
+ var import_react13 = require("react");
1908
+ var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
1909
+
1910
+ // src/utils/errors.ts
1911
+ var MidenError = class extends Error {
1912
+ constructor(message, options) {
1913
+ super(message);
1914
+ this.name = "MidenError";
1915
+ this.code = options?.code ?? "UNKNOWN";
1916
+ if (options?.cause !== void 0) {
1917
+ this.cause = options.cause;
1918
+ }
1919
+ }
1920
+ };
1921
+ var ERROR_PATTERNS = [
1922
+ {
1923
+ test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
1924
+ code: "WASM_CLASS_MISMATCH",
1925
+ 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."
1926
+ },
1927
+ {
1928
+ test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
1929
+ code: "WASM_POINTER_CONSUMED",
1930
+ 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."
1931
+ },
1932
+ {
1933
+ test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
1934
+ code: "WASM_NOT_INITIALIZED",
1935
+ message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
1936
+ },
1937
+ {
1938
+ test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
1939
+ code: "WASM_SYNC_REQUIRED",
1940
+ message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
1941
+ }
1942
+ ];
1943
+ function wrapWasmError(e) {
1944
+ if (e instanceof MidenError) return e;
1945
+ const msg = e instanceof Error ? e.message : String(e);
1946
+ for (const pattern of ERROR_PATTERNS) {
1947
+ if (pattern.test(msg)) {
1948
+ return new MidenError(pattern.message, { cause: e, code: pattern.code });
1949
+ }
1950
+ }
1951
+ if (e instanceof Error) return e;
1952
+ return new Error(msg);
1953
+ }
1954
+
1955
+ // src/hooks/useSend.ts
1477
1956
  function useSend() {
1478
1957
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1479
1958
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1480
- const [result, setResult] = (0, import_react12.useState)(null);
1481
- const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
1482
- const [stage, setStage] = (0, import_react12.useState)("idle");
1483
- const [error, setError] = (0, import_react12.useState)(null);
1484
- const send = (0, import_react12.useCallback)(
1959
+ const isBusyRef = (0, import_react13.useRef)(false);
1960
+ const [result, setResult] = (0, import_react13.useState)(null);
1961
+ const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1962
+ const [stage, setStage] = (0, import_react13.useState)("idle");
1963
+ const [error, setError] = (0, import_react13.useState)(null);
1964
+ const send = (0, import_react13.useCallback)(
1485
1965
  async (options) => {
1486
1966
  if (!client || !isReady) {
1487
1967
  throw new Error("Miden client is not ready");
1488
1968
  }
1969
+ if (isBusyRef.current) {
1970
+ throw new MidenError(
1971
+ "A send is already in progress. Await the previous send before starting another.",
1972
+ { code: "SEND_BUSY" }
1973
+ );
1974
+ }
1975
+ isBusyRef.current = true;
1489
1976
  setIsLoading(true);
1490
1977
  setStage("executing");
1491
1978
  setError(null);
1492
1979
  try {
1980
+ if (!options.skipSync) {
1981
+ await sync();
1982
+ }
1493
1983
  const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1494
- const fromAccountId = parseAccountId(options.from);
1495
- const toAccountId = parseAccountId(options.to);
1984
+ let amount = options.amount;
1985
+ if (options.sendAll) {
1986
+ const resolvedAmount = await runExclusiveSafe(async () => {
1987
+ const fromId = parseAccountId(options.from);
1988
+ const account = await client.getAccount(fromId);
1989
+ if (!account) throw new Error("Account not found");
1990
+ const assetIdObj = parseAccountId(options.assetId);
1991
+ const balance = account.vault?.()?.getBalance?.(assetIdObj);
1992
+ if (balance === void 0 || balance === null) {
1993
+ throw new Error("Could not query account balance");
1994
+ }
1995
+ const bal = BigInt(balance);
1996
+ if (bal === 0n) {
1997
+ throw new Error("Account has zero balance for this asset");
1998
+ }
1999
+ return bal;
2000
+ });
2001
+ amount = resolvedAmount;
2002
+ }
2003
+ if (amount === void 0 || amount === null) {
2004
+ throw new Error("Amount is required (provide amount or sendAll)");
2005
+ }
1496
2006
  const assetId = options.assetId ?? options.faucetId ?? null;
1497
2007
  if (!assetId) {
1498
2008
  throw new Error("Asset ID is required");
1499
2009
  }
1500
- const assetIdObj = parseAccountId(assetId);
1501
- const txResult = await runExclusiveSafe(async () => {
1502
- const txRequest = client.newSendTransactionRequest(
1503
- fromAccountId,
1504
- toAccountId,
1505
- assetIdObj,
1506
- noteType,
1507
- options.amount,
1508
- options.recallHeight ?? null,
1509
- options.timelockHeight ?? null
2010
+ const hasAttachment = options.attachment !== void 0 && options.attachment !== null;
2011
+ if (hasAttachment && (options.recallHeight != null || options.timelockHeight != null)) {
2012
+ throw new Error(
2013
+ "recallHeight and timelockHeight are not supported when attachment is provided"
1510
2014
  );
1511
- return await client.executeTransaction(fromAccountId, txRequest);
2015
+ }
2016
+ const txResult = await runExclusiveSafe(async () => {
2017
+ const fromAccountId = parseAccountId(options.from);
2018
+ const toAccountId = parseAccountId(options.to);
2019
+ const assetIdObj = parseAccountId(assetId);
2020
+ let txRequest;
2021
+ if (hasAttachment) {
2022
+ const attachment = createNoteAttachment(options.attachment);
2023
+ const assets = new import_miden_sdk15.NoteAssets([
2024
+ new import_miden_sdk15.FungibleAsset(assetIdObj, amount)
2025
+ ]);
2026
+ const note = import_miden_sdk15.Note.createP2IDNote(
2027
+ fromAccountId,
2028
+ toAccountId,
2029
+ assets,
2030
+ noteType,
2031
+ attachment
2032
+ );
2033
+ txRequest = new import_miden_sdk15.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk15.OutputNoteArray([import_miden_sdk15.OutputNote.full(note)])).build();
2034
+ } else {
2035
+ txRequest = client.newSendTransactionRequest(
2036
+ fromAccountId,
2037
+ toAccountId,
2038
+ assetIdObj,
2039
+ noteType,
2040
+ amount,
2041
+ options.recallHeight ?? null,
2042
+ options.timelockHeight ?? null
2043
+ );
2044
+ }
2045
+ const execAccountId = parseAccountId(options.from);
2046
+ return await client.executeTransaction(execAccountId, txRequest);
1512
2047
  });
1513
2048
  setStage("proving");
1514
2049
  const provenTransaction = await runExclusiveSafe(
@@ -1518,22 +2053,31 @@ function useSend() {
1518
2053
  const submissionHeight = await runExclusiveSafe(
1519
2054
  () => client.submitProvenTransaction(provenTransaction, txResult)
1520
2055
  );
2056
+ const txIdHex = txResult.id().toHex();
2057
+ const txIdString = txResult.id().toString();
2058
+ let fullNote = null;
2059
+ if (noteType === import_miden_sdk15.NoteType.Private) {
2060
+ fullNote = extractFullNote(txResult);
2061
+ }
1521
2062
  await runExclusiveSafe(
1522
2063
  () => client.applyTransaction(txResult, submissionHeight)
1523
2064
  );
1524
- const txId = txResult.id();
1525
- await waitForTransactionCommit(client, runExclusiveSafe, txId);
1526
- if (noteType === import_miden_sdk12.NoteType.Private) {
1527
- const fullNote = extractFullNote(txResult);
2065
+ if (noteType === import_miden_sdk15.NoteType.Private) {
1528
2066
  if (!fullNote) {
1529
2067
  throw new Error("Missing full note for private send");
1530
2068
  }
1531
- const recipientAddress = parseAddress(options.to, toAccountId);
2069
+ await waitForTransactionCommit(
2070
+ client,
2071
+ runExclusiveSafe,
2072
+ txIdHex
2073
+ );
2074
+ const recipientAccountId = parseAccountId(options.to);
2075
+ const recipientAddress = parseAddress(options.to, recipientAccountId);
1532
2076
  await runExclusiveSafe(
1533
2077
  () => client.sendPrivateNote(fullNote, recipientAddress)
1534
2078
  );
1535
2079
  }
1536
- const txSummary = { transactionId: txResult.id().toString() };
2080
+ const txSummary = { transactionId: txIdString };
1537
2081
  setStage("complete");
1538
2082
  setResult(txSummary);
1539
2083
  await sync();
@@ -1545,11 +2089,12 @@ function useSend() {
1545
2089
  throw error2;
1546
2090
  } finally {
1547
2091
  setIsLoading(false);
2092
+ isBusyRef.current = false;
1548
2093
  }
1549
2094
  },
1550
2095
  [client, isReady, prover, runExclusive, sync]
1551
2096
  );
1552
- const reset = (0, import_react12.useCallback)(() => {
2097
+ const reset = (0, import_react13.useCallback)(() => {
1553
2098
  setResult(null);
1554
2099
  setIsLoading(false);
1555
2100
  setStage("idle");
@@ -1564,39 +2109,6 @@ function useSend() {
1564
2109
  reset
1565
2110
  };
1566
2111
  }
1567
- function getNoteType(type) {
1568
- switch (type) {
1569
- case "private":
1570
- return import_miden_sdk12.NoteType.Private;
1571
- case "public":
1572
- return import_miden_sdk12.NoteType.Public;
1573
- case "encrypted":
1574
- return import_miden_sdk12.NoteType.Encrypted;
1575
- default:
1576
- return import_miden_sdk12.NoteType.Private;
1577
- }
1578
- }
1579
- async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1580
- let waited = 0;
1581
- while (waited < maxWaitMs) {
1582
- await runExclusiveSafe(() => client.syncState());
1583
- const [record] = await runExclusiveSafe(
1584
- () => client.getTransactions(import_miden_sdk12.TransactionFilter.ids([txId]))
1585
- );
1586
- if (record) {
1587
- const status = record.transactionStatus();
1588
- if (status.isCommitted()) {
1589
- return;
1590
- }
1591
- if (status.isDiscarded()) {
1592
- throw new Error("Transaction was discarded before commit");
1593
- }
1594
- }
1595
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1596
- waited += delayMs;
1597
- }
1598
- throw new Error("Timeout waiting for transaction commit");
1599
- }
1600
2112
  function extractFullNote(txResult) {
1601
2113
  try {
1602
2114
  const executedTx = txResult.executedTransaction?.();
@@ -1609,16 +2121,17 @@ function extractFullNote(txResult) {
1609
2121
  }
1610
2122
 
1611
2123
  // src/hooks/useMultiSend.ts
1612
- var import_react13 = require("react");
1613
- var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
2124
+ var import_react14 = require("react");
2125
+ var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
1614
2126
  function useMultiSend() {
1615
2127
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1616
2128
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1617
- const [result, setResult] = (0, import_react13.useState)(null);
1618
- const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1619
- const [stage, setStage] = (0, import_react13.useState)("idle");
1620
- const [error, setError] = (0, import_react13.useState)(null);
1621
- const sendMany = (0, import_react13.useCallback)(
2129
+ const isBusyRef = (0, import_react14.useRef)(false);
2130
+ const [result, setResult] = (0, import_react14.useState)(null);
2131
+ const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
2132
+ const [stage, setStage] = (0, import_react14.useState)("idle");
2133
+ const [error, setError] = (0, import_react14.useState)(null);
2134
+ const sendMany = (0, import_react14.useCallback)(
1622
2135
  async (options) => {
1623
2136
  if (!client || !isReady) {
1624
2137
  throw new Error("Miden client is not ready");
@@ -1626,35 +2139,53 @@ function useMultiSend() {
1626
2139
  if (options.recipients.length === 0) {
1627
2140
  throw new Error("No recipients provided");
1628
2141
  }
2142
+ if (isBusyRef.current) {
2143
+ throw new MidenError(
2144
+ "A send is already in progress. Await the previous send before starting another.",
2145
+ { code: "SEND_BUSY" }
2146
+ );
2147
+ }
2148
+ isBusyRef.current = true;
1629
2149
  setIsLoading(true);
1630
2150
  setStage("executing");
1631
2151
  setError(null);
1632
2152
  try {
1633
- const noteType = getNoteType2(options.noteType ?? DEFAULTS.NOTE_TYPE);
1634
- const senderId = parseAccountId(options.from);
1635
- const assetId = parseAccountId(options.assetId);
1636
- const outputs = options.recipients.map(({ to, amount }) => {
1637
- const receiverId = parseAccountId(to);
1638
- const assets = new import_miden_sdk13.NoteAssets([new import_miden_sdk13.FungibleAsset(assetId, amount)]);
1639
- const note = import_miden_sdk13.Note.createP2IDNote(
1640
- senderId,
1641
- receiverId,
1642
- assets,
1643
- noteType,
1644
- new import_miden_sdk13.NoteAttachment()
1645
- );
1646
- const recipientAddress = parseAddress(to, receiverId);
1647
- return {
1648
- outputNote: import_miden_sdk13.OutputNote.full(note),
1649
- note,
1650
- recipientAddress
1651
- };
1652
- });
1653
- const txRequest = new import_miden_sdk13.TransactionRequestBuilder().withOwnOutputNotes(
1654
- new import_miden_sdk13.OutputNoteArray(outputs.map((o) => o.outputNote))
2153
+ if (!options.skipSync) {
2154
+ await sync();
2155
+ }
2156
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2157
+ const outputs = options.recipients.map(
2158
+ ({ to, amount, attachment, noteType: recipientNoteType }) => {
2159
+ const iterSenderId = parseAccountId(options.from);
2160
+ const iterAssetId = parseAccountId(options.assetId);
2161
+ const receiverId = parseAccountId(to);
2162
+ const assets = new import_miden_sdk16.NoteAssets([
2163
+ new import_miden_sdk16.FungibleAsset(iterAssetId, amount)
2164
+ ]);
2165
+ const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
2166
+ const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new import_miden_sdk16.NoteAttachment();
2167
+ const note = import_miden_sdk16.Note.createP2IDNote(
2168
+ iterSenderId,
2169
+ receiverId,
2170
+ assets,
2171
+ resolvedNoteType,
2172
+ noteAttachment
2173
+ );
2174
+ const recipientAddress = parseAddress(to, receiverId);
2175
+ return {
2176
+ outputNote: import_miden_sdk16.OutputNote.full(note),
2177
+ note,
2178
+ recipientAddress,
2179
+ noteType: resolvedNoteType
2180
+ };
2181
+ }
2182
+ );
2183
+ const txRequest = new import_miden_sdk16.TransactionRequestBuilder().withOwnOutputNotes(
2184
+ new import_miden_sdk16.OutputNoteArray(outputs.map((o) => o.outputNote))
1655
2185
  ).build();
2186
+ const txSenderId = parseAccountId(options.from);
1656
2187
  const txResult = await runExclusiveSafe(
1657
- () => client.executeTransaction(senderId, txRequest)
2188
+ () => client.executeTransaction(txSenderId, txRequest)
1658
2189
  );
1659
2190
  setStage("proving");
1660
2191
  const provenTransaction = await runExclusiveSafe(
@@ -1664,23 +2195,27 @@ function useMultiSend() {
1664
2195
  const submissionHeight = await runExclusiveSafe(
1665
2196
  () => client.submitProvenTransaction(provenTransaction, txResult)
1666
2197
  );
2198
+ const txIdHex = txResult.id().toHex();
2199
+ const txIdString = txResult.id().toString();
1667
2200
  await runExclusiveSafe(
1668
2201
  () => client.applyTransaction(txResult, submissionHeight)
1669
2202
  );
1670
- const txId = txResult.id();
1671
- if (noteType === import_miden_sdk13.NoteType.Private) {
1672
- await waitForTransactionCommit2(
2203
+ const hasPrivate = outputs.some((o) => o.noteType === import_miden_sdk16.NoteType.Private);
2204
+ if (hasPrivate) {
2205
+ await waitForTransactionCommit(
1673
2206
  client,
1674
2207
  runExclusiveSafe,
1675
- txId
2208
+ txIdHex
1676
2209
  );
1677
2210
  for (const output of outputs) {
1678
- await runExclusiveSafe(
1679
- () => client.sendPrivateNote(output.note, output.recipientAddress)
1680
- );
2211
+ if (output.noteType === import_miden_sdk16.NoteType.Private) {
2212
+ await runExclusiveSafe(
2213
+ () => client.sendPrivateNote(output.note, output.recipientAddress)
2214
+ );
2215
+ }
1681
2216
  }
1682
2217
  }
1683
- const txSummary = { transactionId: txId.toString() };
2218
+ const txSummary = { transactionId: txIdString };
1684
2219
  setStage("complete");
1685
2220
  setResult(txSummary);
1686
2221
  await sync();
@@ -1692,11 +2227,12 @@ function useMultiSend() {
1692
2227
  throw error2;
1693
2228
  } finally {
1694
2229
  setIsLoading(false);
2230
+ isBusyRef.current = false;
1695
2231
  }
1696
2232
  },
1697
2233
  [client, isReady, prover, runExclusive, sync]
1698
2234
  );
1699
- const reset = (0, import_react13.useCallback)(() => {
2235
+ const reset = (0, import_react14.useCallback)(() => {
1700
2236
  setResult(null);
1701
2237
  setIsLoading(false);
1702
2238
  setStage("idle");
@@ -1711,71 +2247,38 @@ function useMultiSend() {
1711
2247
  reset
1712
2248
  };
1713
2249
  }
1714
- function getNoteType2(type) {
1715
- switch (type) {
1716
- case "private":
1717
- return import_miden_sdk13.NoteType.Private;
1718
- case "public":
1719
- return import_miden_sdk13.NoteType.Public;
1720
- case "encrypted":
1721
- return import_miden_sdk13.NoteType.Encrypted;
1722
- default:
1723
- return import_miden_sdk13.NoteType.Private;
1724
- }
1725
- }
1726
- async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1727
- let waited = 0;
1728
- while (waited < maxWaitMs) {
1729
- await runExclusiveSafe(() => client.syncState());
1730
- const [record] = await runExclusiveSafe(
1731
- () => client.getTransactions(import_miden_sdk13.TransactionFilter.ids([txId]))
1732
- );
1733
- if (record) {
1734
- const status = record.transactionStatus();
1735
- if (status.isCommitted()) {
1736
- return;
1737
- }
1738
- if (status.isDiscarded()) {
1739
- throw new Error("Transaction was discarded before commit");
1740
- }
1741
- }
1742
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1743
- waited += delayMs;
1744
- }
1745
- throw new Error("Timeout waiting for transaction commit");
1746
- }
1747
2250
 
1748
2251
  // src/hooks/useInternalTransfer.ts
1749
- var import_react14 = require("react");
1750
- var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
2252
+ var import_react15 = require("react");
2253
+ var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
1751
2254
  function useInternalTransfer() {
1752
2255
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1753
2256
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1754
- const [result, setResult] = (0, import_react14.useState)(null);
1755
- const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
1756
- const [stage, setStage] = (0, import_react14.useState)("idle");
1757
- const [error, setError] = (0, import_react14.useState)(null);
1758
- const transferOnce = (0, import_react14.useCallback)(
2257
+ const [result, setResult] = (0, import_react15.useState)(null);
2258
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
2259
+ const [stage, setStage] = (0, import_react15.useState)("idle");
2260
+ const [error, setError] = (0, import_react15.useState)(null);
2261
+ const transferOnce = (0, import_react15.useCallback)(
1759
2262
  async (options) => {
1760
2263
  if (!client || !isReady) {
1761
2264
  throw new Error("Miden client is not ready");
1762
2265
  }
1763
- const noteType = getNoteType3(options.noteType ?? DEFAULTS.NOTE_TYPE);
2266
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1764
2267
  const senderId = parseAccountId(options.from);
1765
2268
  const receiverId = parseAccountId(options.to);
1766
2269
  const assetId = parseAccountId(options.assetId);
1767
- const assets = new import_miden_sdk14.NoteAssets([
1768
- new import_miden_sdk14.FungibleAsset(assetId, options.amount)
2270
+ const assets = new import_miden_sdk17.NoteAssets([
2271
+ new import_miden_sdk17.FungibleAsset(assetId, options.amount)
1769
2272
  ]);
1770
- const note = import_miden_sdk14.Note.createP2IDNote(
2273
+ const note = import_miden_sdk17.Note.createP2IDNote(
1771
2274
  senderId,
1772
2275
  receiverId,
1773
2276
  assets,
1774
2277
  noteType,
1775
- new import_miden_sdk14.NoteAttachment()
2278
+ new import_miden_sdk17.NoteAttachment()
1776
2279
  );
1777
2280
  const noteId = note.id().toString();
1778
- const createRequest = new import_miden_sdk14.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk14.OutputNoteArray([import_miden_sdk14.OutputNote.full(note)])).build();
2281
+ const createRequest = new import_miden_sdk17.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk17.OutputNoteArray([import_miden_sdk17.OutputNote.full(note)])).build();
1779
2282
  const createTxId = await runExclusiveSafe(
1780
2283
  () => prover ? client.submitNewTransactionWithProver(
1781
2284
  senderId,
@@ -1783,7 +2286,7 @@ function useInternalTransfer() {
1783
2286
  prover
1784
2287
  ) : client.submitNewTransaction(senderId, createRequest)
1785
2288
  );
1786
- const consumeRequest = new import_miden_sdk14.TransactionRequestBuilder().withInputNotes(new import_miden_sdk14.NoteAndArgsArray([new import_miden_sdk14.NoteAndArgs(note, null)])).build();
2289
+ const consumeRequest = new import_miden_sdk17.TransactionRequestBuilder().withInputNotes(new import_miden_sdk17.NoteAndArgsArray([new import_miden_sdk17.NoteAndArgs(note, null)])).build();
1787
2290
  const consumeTxId = await runExclusiveSafe(
1788
2291
  () => prover ? client.submitNewTransactionWithProver(
1789
2292
  receiverId,
@@ -1799,7 +2302,7 @@ function useInternalTransfer() {
1799
2302
  },
1800
2303
  [client, isReady, prover, runExclusiveSafe]
1801
2304
  );
1802
- const transfer = (0, import_react14.useCallback)(
2305
+ const transfer = (0, import_react15.useCallback)(
1803
2306
  async (options) => {
1804
2307
  if (!client || !isReady) {
1805
2308
  throw new Error("Miden client is not ready");
@@ -1825,7 +2328,7 @@ function useInternalTransfer() {
1825
2328
  },
1826
2329
  [client, isReady, sync, transferOnce]
1827
2330
  );
1828
- const transferChain = (0, import_react14.useCallback)(
2331
+ const transferChain = (0, import_react15.useCallback)(
1829
2332
  async (options) => {
1830
2333
  if (!client || !isReady) {
1831
2334
  throw new Error("Miden client is not ready");
@@ -1866,7 +2369,7 @@ function useInternalTransfer() {
1866
2369
  },
1867
2370
  [client, isReady, sync, transferOnce]
1868
2371
  );
1869
- const reset = (0, import_react14.useCallback)(() => {
2372
+ const reset = (0, import_react15.useCallback)(() => {
1870
2373
  setResult(null);
1871
2374
  setIsLoading(false);
1872
2375
  setStage("idle");
@@ -1882,47 +2385,35 @@ function useInternalTransfer() {
1882
2385
  reset
1883
2386
  };
1884
2387
  }
1885
- function getNoteType3(type) {
1886
- switch (type) {
1887
- case "private":
1888
- return import_miden_sdk14.NoteType.Private;
1889
- case "public":
1890
- return import_miden_sdk14.NoteType.Public;
1891
- case "encrypted":
1892
- return import_miden_sdk14.NoteType.Encrypted;
1893
- default:
1894
- return import_miden_sdk14.NoteType.Private;
1895
- }
1896
- }
1897
2388
 
1898
2389
  // src/hooks/useWaitForCommit.ts
1899
- var import_react15 = require("react");
1900
- var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
2390
+ var import_react16 = require("react");
2391
+ var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
1901
2392
  function useWaitForCommit() {
1902
2393
  const { client, isReady, runExclusive } = useMiden();
1903
2394
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1904
- const waitForCommit = (0, import_react15.useCallback)(
2395
+ const waitForCommit = (0, import_react16.useCallback)(
1905
2396
  async (txId, options) => {
1906
2397
  if (!client || !isReady) {
1907
2398
  throw new Error("Miden client is not ready");
1908
2399
  }
1909
2400
  const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
1910
2401
  const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
1911
- const targetHex = normalizeHex2(
2402
+ const targetHex = normalizeHex3(
1912
2403
  typeof txId === "string" ? txId : txId.toHex()
1913
2404
  );
1914
- let waited = 0;
1915
- while (waited < timeoutMs) {
2405
+ const deadline = Date.now() + timeoutMs;
2406
+ while (Date.now() < deadline) {
1916
2407
  await runExclusiveSafe(
1917
2408
  () => client.syncState()
1918
2409
  );
1919
2410
  const records = await runExclusiveSafe(
1920
2411
  () => client.getTransactions(
1921
- typeof txId === "string" ? import_miden_sdk15.TransactionFilter.all() : import_miden_sdk15.TransactionFilter.ids([txId])
2412
+ typeof txId === "string" ? import_miden_sdk18.TransactionFilter.all() : import_miden_sdk18.TransactionFilter.ids([txId])
1922
2413
  )
1923
2414
  );
1924
2415
  const record = records.find(
1925
- (item) => normalizeHex2(item.id().toHex()) === targetHex
2416
+ (item) => normalizeHex3(item.id().toHex()) === targetHex
1926
2417
  );
1927
2418
  if (record) {
1928
2419
  const status = record.transactionStatus();
@@ -1934,7 +2425,6 @@ function useWaitForCommit() {
1934
2425
  }
1935
2426
  }
1936
2427
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
1937
- waited += intervalMs;
1938
2428
  }
1939
2429
  throw new Error("Timeout waiting for transaction commit");
1940
2430
  },
@@ -1942,18 +2432,18 @@ function useWaitForCommit() {
1942
2432
  );
1943
2433
  return { waitForCommit };
1944
2434
  }
1945
- function normalizeHex2(value) {
2435
+ function normalizeHex3(value) {
1946
2436
  const trimmed = value.trim();
1947
2437
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1948
2438
  return normalized.toLowerCase();
1949
2439
  }
1950
2440
 
1951
2441
  // src/hooks/useWaitForNotes.ts
1952
- var import_react16 = require("react");
2442
+ var import_react17 = require("react");
1953
2443
  function useWaitForNotes() {
1954
2444
  const { client, isReady, runExclusive } = useMiden();
1955
2445
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1956
- const waitForConsumableNotes = (0, import_react16.useCallback)(
2446
+ const waitForConsumableNotes = (0, import_react17.useCallback)(
1957
2447
  async (options) => {
1958
2448
  if (!client || !isReady) {
1959
2449
  throw new Error("Miden client is not ready");
@@ -1964,7 +2454,9 @@ function useWaitForNotes() {
1964
2454
  const accountId = parseAccountId(options.accountId);
1965
2455
  let waited = 0;
1966
2456
  while (waited < timeoutMs) {
1967
- await runExclusiveSafe(() => client.syncState());
2457
+ await runExclusiveSafe(
2458
+ () => client.syncState()
2459
+ );
1968
2460
  const notes = await runExclusiveSafe(
1969
2461
  () => client.getConsumableNotes(accountId)
1970
2462
  );
@@ -1982,16 +2474,15 @@ function useWaitForNotes() {
1982
2474
  }
1983
2475
 
1984
2476
  // src/hooks/useMint.ts
1985
- var import_react17 = require("react");
1986
- var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
2477
+ var import_react18 = require("react");
1987
2478
  function useMint() {
1988
2479
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1989
2480
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1990
- const [result, setResult] = (0, import_react17.useState)(null);
1991
- const [isLoading, setIsLoading] = (0, import_react17.useState)(false);
1992
- const [stage, setStage] = (0, import_react17.useState)("idle");
1993
- const [error, setError] = (0, import_react17.useState)(null);
1994
- const mint = (0, import_react17.useCallback)(
2481
+ const [result, setResult] = (0, import_react18.useState)(null);
2482
+ const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
2483
+ const [stage, setStage] = (0, import_react18.useState)("idle");
2484
+ const [error, setError] = (0, import_react18.useState)(null);
2485
+ const mint = (0, import_react18.useCallback)(
1995
2486
  async (options) => {
1996
2487
  if (!client || !isReady) {
1997
2488
  throw new Error("Miden client is not ready");
@@ -2000,7 +2491,7 @@ function useMint() {
2000
2491
  setStage("executing");
2001
2492
  setError(null);
2002
2493
  try {
2003
- const noteType = getNoteType4(options.noteType ?? DEFAULTS.NOTE_TYPE);
2494
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2004
2495
  const targetAccountIdObj = parseAccountId(options.targetAccountId);
2005
2496
  const faucetIdObj = parseAccountId(options.faucetId);
2006
2497
  setStage("proving");
@@ -2033,7 +2524,7 @@ function useMint() {
2033
2524
  },
2034
2525
  [client, isReady, prover, runExclusive, sync]
2035
2526
  );
2036
- const reset = (0, import_react17.useCallback)(() => {
2527
+ const reset = (0, import_react18.useCallback)(() => {
2037
2528
  setResult(null);
2038
2529
  setIsLoading(false);
2039
2530
  setStage("idle");
@@ -2048,30 +2539,18 @@ function useMint() {
2048
2539
  reset
2049
2540
  };
2050
2541
  }
2051
- function getNoteType4(type) {
2052
- switch (type) {
2053
- case "private":
2054
- return import_miden_sdk16.NoteType.Private;
2055
- case "public":
2056
- return import_miden_sdk16.NoteType.Public;
2057
- case "encrypted":
2058
- return import_miden_sdk16.NoteType.Encrypted;
2059
- default:
2060
- return import_miden_sdk16.NoteType.Private;
2061
- }
2062
- }
2063
2542
 
2064
2543
  // src/hooks/useConsume.ts
2065
- var import_react18 = require("react");
2066
- var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
2544
+ var import_react19 = require("react");
2545
+ var import_miden_sdk19 = require("@miden-sdk/miden-sdk");
2067
2546
  function useConsume() {
2068
2547
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2069
2548
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2070
- const [result, setResult] = (0, import_react18.useState)(null);
2071
- const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
2072
- const [stage, setStage] = (0, import_react18.useState)("idle");
2073
- const [error, setError] = (0, import_react18.useState)(null);
2074
- const consume = (0, import_react18.useCallback)(
2549
+ const [result, setResult] = (0, import_react19.useState)(null);
2550
+ const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
2551
+ const [stage, setStage] = (0, import_react19.useState)("idle");
2552
+ const [error, setError] = (0, import_react19.useState)(null);
2553
+ const consume = (0, import_react19.useCallback)(
2075
2554
  async (options) => {
2076
2555
  if (!client || !isReady) {
2077
2556
  throw new Error("Miden client is not ready");
@@ -2087,9 +2566,9 @@ function useConsume() {
2087
2566
  setStage("proving");
2088
2567
  const txResult = await runExclusiveSafe(async () => {
2089
2568
  const noteIds = options.noteIds.map(
2090
- (noteId) => import_miden_sdk17.NoteId.fromHex(noteId)
2569
+ (noteId) => import_miden_sdk19.NoteId.fromHex(noteId)
2091
2570
  );
2092
- const filter = new import_miden_sdk17.NoteFilter(import_miden_sdk17.NoteFilterTypes.List, noteIds);
2571
+ const filter = new import_miden_sdk19.NoteFilter(import_miden_sdk19.NoteFilterTypes.List, noteIds);
2093
2572
  const noteRecords = await client.getInputNotes(filter);
2094
2573
  const notes = noteRecords.map((record) => record.toNote());
2095
2574
  if (notes.length === 0) {
@@ -2121,7 +2600,7 @@ function useConsume() {
2121
2600
  },
2122
2601
  [client, isReady, prover, runExclusive, sync]
2123
2602
  );
2124
- const reset = (0, import_react18.useCallback)(() => {
2603
+ const reset = (0, import_react19.useCallback)(() => {
2125
2604
  setResult(null);
2126
2605
  setIsLoading(false);
2127
2606
  setStage("idle");
@@ -2138,16 +2617,15 @@ function useConsume() {
2138
2617
  }
2139
2618
 
2140
2619
  // src/hooks/useSwap.ts
2141
- var import_react19 = require("react");
2142
- var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
2620
+ var import_react20 = require("react");
2143
2621
  function useSwap() {
2144
2622
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2145
2623
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2146
- const [result, setResult] = (0, import_react19.useState)(null);
2147
- const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
2148
- const [stage, setStage] = (0, import_react19.useState)("idle");
2149
- const [error, setError] = (0, import_react19.useState)(null);
2150
- const swap = (0, import_react19.useCallback)(
2624
+ const [result, setResult] = (0, import_react20.useState)(null);
2625
+ const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
2626
+ const [stage, setStage] = (0, import_react20.useState)("idle");
2627
+ const [error, setError] = (0, import_react20.useState)(null);
2628
+ const swap = (0, import_react20.useCallback)(
2151
2629
  async (options) => {
2152
2630
  if (!client || !isReady) {
2153
2631
  throw new Error("Miden client is not ready");
@@ -2156,8 +2634,8 @@ function useSwap() {
2156
2634
  setStage("executing");
2157
2635
  setError(null);
2158
2636
  try {
2159
- const noteType = getNoteType5(options.noteType ?? DEFAULTS.NOTE_TYPE);
2160
- const paybackNoteType = getNoteType5(
2637
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2638
+ const paybackNoteType = getNoteType(
2161
2639
  options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
2162
2640
  );
2163
2641
  const accountIdObj = parseAccountId(options.accountId);
@@ -2196,7 +2674,7 @@ function useSwap() {
2196
2674
  },
2197
2675
  [client, isReady, prover, runExclusive, sync]
2198
2676
  );
2199
- const reset = (0, import_react19.useCallback)(() => {
2677
+ const reset = (0, import_react20.useCallback)(() => {
2200
2678
  setResult(null);
2201
2679
  setIsLoading(false);
2202
2680
  setStage("idle");
@@ -2211,41 +2689,40 @@ function useSwap() {
2211
2689
  reset
2212
2690
  };
2213
2691
  }
2214
- function getNoteType5(type) {
2215
- switch (type) {
2216
- case "private":
2217
- return import_miden_sdk18.NoteType.Private;
2218
- case "public":
2219
- return import_miden_sdk18.NoteType.Public;
2220
- case "encrypted":
2221
- return import_miden_sdk18.NoteType.Encrypted;
2222
- default:
2223
- return import_miden_sdk18.NoteType.Private;
2224
- }
2225
- }
2226
2692
 
2227
2693
  // src/hooks/useTransaction.ts
2228
- var import_react20 = require("react");
2694
+ var import_react21 = require("react");
2229
2695
  function useTransaction() {
2230
2696
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2231
2697
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2232
- const [result, setResult] = (0, import_react20.useState)(null);
2233
- const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
2234
- const [stage, setStage] = (0, import_react20.useState)("idle");
2235
- const [error, setError] = (0, import_react20.useState)(null);
2236
- const execute = (0, import_react20.useCallback)(
2698
+ const isBusyRef = (0, import_react21.useRef)(false);
2699
+ const [result, setResult] = (0, import_react21.useState)(null);
2700
+ const [isLoading, setIsLoading] = (0, import_react21.useState)(false);
2701
+ const [stage, setStage] = (0, import_react21.useState)("idle");
2702
+ const [error, setError] = (0, import_react21.useState)(null);
2703
+ const execute = (0, import_react21.useCallback)(
2237
2704
  async (options) => {
2238
2705
  if (!client || !isReady) {
2239
2706
  throw new Error("Miden client is not ready");
2240
2707
  }
2708
+ if (isBusyRef.current) {
2709
+ throw new MidenError(
2710
+ "A transaction is already in progress. Await the previous transaction before starting another.",
2711
+ { code: "SEND_BUSY" }
2712
+ );
2713
+ }
2714
+ isBusyRef.current = true;
2241
2715
  setIsLoading(true);
2242
2716
  setStage("executing");
2243
2717
  setError(null);
2244
2718
  try {
2719
+ if (!options.skipSync) {
2720
+ await sync();
2721
+ }
2722
+ const txRequest = await resolveRequest(options.request, client);
2245
2723
  setStage("proving");
2246
2724
  const txResult = await runExclusiveSafe(async () => {
2247
2725
  const accountIdObj = resolveAccountId2(options.accountId);
2248
- const txRequest = await resolveRequest(options.request, client);
2249
2726
  const txId = prover ? await client.submitNewTransactionWithProver(
2250
2727
  accountIdObj,
2251
2728
  txRequest,
@@ -2264,11 +2741,12 @@ function useTransaction() {
2264
2741
  throw error2;
2265
2742
  } finally {
2266
2743
  setIsLoading(false);
2744
+ isBusyRef.current = false;
2267
2745
  }
2268
2746
  },
2269
2747
  [client, isReady, prover, runExclusive, sync]
2270
2748
  );
2271
- const reset = (0, import_react20.useCallback)(() => {
2749
+ const reset = (0, import_react21.useCallback)(() => {
2272
2750
  setResult(null);
2273
2751
  setIsLoading(false);
2274
2752
  setStage("idle");
@@ -2293,17 +2771,338 @@ async function resolveRequest(request, client) {
2293
2771
  return request;
2294
2772
  }
2295
2773
 
2774
+ // src/hooks/useSessionAccount.ts
2775
+ var import_react22 = require("react");
2776
+ var import_miden_sdk20 = require("@miden-sdk/miden-sdk");
2777
+ function useSessionAccount(options) {
2778
+ const { client, isReady, sync, runExclusive } = useMiden();
2779
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2780
+ const setAccounts = useMidenStore((state) => state.setAccounts);
2781
+ const [sessionAccountId, setSessionAccountId] = (0, import_react22.useState)(null);
2782
+ const [step, setStep] = (0, import_react22.useState)("idle");
2783
+ const [error, setError] = (0, import_react22.useState)(null);
2784
+ const cancelledRef = (0, import_react22.useRef)(false);
2785
+ const isBusyRef = (0, import_react22.useRef)(false);
2786
+ const storagePrefix = options.storagePrefix ?? "miden-session";
2787
+ const pollIntervalMs = options.pollIntervalMs ?? 3e3;
2788
+ const maxWaitMs = options.maxWaitMs ?? 6e4;
2789
+ const storageMode = options.walletOptions?.storageMode ?? "public";
2790
+ const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
2791
+ const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
2792
+ const fundRef = (0, import_react22.useRef)(options.fund);
2793
+ fundRef.current = options.fund;
2794
+ (0, import_react22.useEffect)(() => {
2795
+ try {
2796
+ const stored = localStorage.getItem(`${storagePrefix}:accountId`);
2797
+ const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
2798
+ if (stored && stored.length > 0) {
2799
+ const validationId = parseAccountId(stored);
2800
+ validationId?.free?.();
2801
+ setSessionAccountId(stored);
2802
+ if (storedReady === "true") {
2803
+ setStep("ready");
2804
+ }
2805
+ }
2806
+ } catch {
2807
+ localStorage.removeItem(`${storagePrefix}:accountId`);
2808
+ localStorage.removeItem(`${storagePrefix}:ready`);
2809
+ }
2810
+ }, [storagePrefix]);
2811
+ const initialize = (0, import_react22.useCallback)(async () => {
2812
+ if (!client || !isReady) {
2813
+ throw new Error("Miden client is not ready");
2814
+ }
2815
+ if (isBusyRef.current) {
2816
+ throw new MidenError(
2817
+ "Session account initialization is already in progress.",
2818
+ { code: "OPERATION_BUSY" }
2819
+ );
2820
+ }
2821
+ isBusyRef.current = true;
2822
+ cancelledRef.current = false;
2823
+ setError(null);
2824
+ try {
2825
+ let walletId = sessionAccountId;
2826
+ if (!walletId) {
2827
+ setStep("creating");
2828
+ const resolvedStorageMode = getStorageMode3(storageMode);
2829
+ const wallet = await runExclusiveSafe(async () => {
2830
+ const w = await client.newWallet(
2831
+ resolvedStorageMode,
2832
+ mutable,
2833
+ authScheme
2834
+ );
2835
+ ensureAccountBech32(w);
2836
+ const accounts = await client.getAccounts();
2837
+ setAccounts(accounts);
2838
+ return w;
2839
+ });
2840
+ if (cancelledRef.current) return;
2841
+ walletId = wallet.id().toString();
2842
+ setSessionAccountId(walletId);
2843
+ localStorage.setItem(`${storagePrefix}:accountId`, walletId);
2844
+ }
2845
+ setStep("funding");
2846
+ await fundRef.current(walletId);
2847
+ if (cancelledRef.current) return;
2848
+ setStep("consuming");
2849
+ await waitAndConsume(
2850
+ client,
2851
+ runExclusiveSafe,
2852
+ walletId,
2853
+ pollIntervalMs,
2854
+ maxWaitMs,
2855
+ cancelledRef
2856
+ );
2857
+ if (cancelledRef.current) return;
2858
+ setStep("ready");
2859
+ localStorage.setItem(`${storagePrefix}:ready`, "true");
2860
+ await sync();
2861
+ } catch (err) {
2862
+ if (!cancelledRef.current) {
2863
+ const error2 = err instanceof Error ? err : new Error(String(err));
2864
+ setError(error2);
2865
+ setStep("idle");
2866
+ throw error2;
2867
+ }
2868
+ } finally {
2869
+ isBusyRef.current = false;
2870
+ }
2871
+ }, [
2872
+ client,
2873
+ isReady,
2874
+ sync,
2875
+ runExclusiveSafe,
2876
+ sessionAccountId,
2877
+ storageMode,
2878
+ mutable,
2879
+ authScheme,
2880
+ storagePrefix,
2881
+ pollIntervalMs,
2882
+ maxWaitMs,
2883
+ setAccounts
2884
+ ]);
2885
+ const reset = (0, import_react22.useCallback)(() => {
2886
+ cancelledRef.current = true;
2887
+ isBusyRef.current = false;
2888
+ setSessionAccountId(null);
2889
+ setStep("idle");
2890
+ setError(null);
2891
+ localStorage.removeItem(`${storagePrefix}:accountId`);
2892
+ localStorage.removeItem(`${storagePrefix}:ready`);
2893
+ }, [storagePrefix]);
2894
+ return {
2895
+ initialize,
2896
+ sessionAccountId,
2897
+ isReady: step === "ready",
2898
+ step,
2899
+ error,
2900
+ reset
2901
+ };
2902
+ }
2903
+ function getStorageMode3(mode) {
2904
+ switch (mode) {
2905
+ case "private":
2906
+ return import_miden_sdk20.AccountStorageMode.private();
2907
+ case "public":
2908
+ return import_miden_sdk20.AccountStorageMode.public();
2909
+ default:
2910
+ return import_miden_sdk20.AccountStorageMode.public();
2911
+ }
2912
+ }
2913
+ async function waitAndConsume(client, runExclusiveSafe, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
2914
+ const deadline = Date.now() + maxWaitMs;
2915
+ while (Date.now() < deadline) {
2916
+ if (cancelledRef.current) return;
2917
+ await runExclusiveSafe(
2918
+ () => client.syncState()
2919
+ );
2920
+ if (cancelledRef.current) return;
2921
+ const consumed = await runExclusiveSafe(async () => {
2922
+ const accountIdObj = parseAccountId(walletId);
2923
+ const consumable = await client.getConsumableNotes(accountIdObj);
2924
+ if (consumable.length === 0) return false;
2925
+ const notes = consumable.map((c) => c.inputNoteRecord().toNote());
2926
+ const txRequest = client.newConsumeTransactionRequest(notes);
2927
+ const freshAccountId = parseAccountId(walletId);
2928
+ await client.submitNewTransaction(freshAccountId, txRequest);
2929
+ return true;
2930
+ });
2931
+ if (consumed) return;
2932
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2933
+ }
2934
+ throw new Error("Timeout waiting for session wallet funding");
2935
+ }
2936
+
2937
+ // src/utils/bytes.ts
2938
+ function bytesToBigInt(bytes) {
2939
+ let result = 0n;
2940
+ for (let i = 0; i < bytes.length; i++) {
2941
+ result = result << 8n | BigInt(bytes[i]);
2942
+ }
2943
+ return result;
2944
+ }
2945
+ function bigIntToBytes(value, length) {
2946
+ if (value < 0n) {
2947
+ throw new RangeError("bigIntToBytes: value must be non-negative");
2948
+ }
2949
+ const maxValue = (1n << BigInt(length * 8)) - 1n;
2950
+ if (value > maxValue) {
2951
+ throw new RangeError(
2952
+ `bigIntToBytes: value ${value} does not fit in ${length} byte(s) (max ${maxValue})`
2953
+ );
2954
+ }
2955
+ const bytes = new Uint8Array(length);
2956
+ let remaining = value;
2957
+ for (let i = length - 1; i >= 0; i--) {
2958
+ bytes[i] = Number(remaining & 0xffn);
2959
+ remaining >>= 8n;
2960
+ }
2961
+ return bytes;
2962
+ }
2963
+ function concatBytes(...arrays) {
2964
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
2965
+ const result = new Uint8Array(totalLength);
2966
+ let offset = 0;
2967
+ for (const arr of arrays) {
2968
+ result.set(arr, offset);
2969
+ offset += arr.length;
2970
+ }
2971
+ return result;
2972
+ }
2973
+
2974
+ // src/utils/walletDetection.ts
2975
+ async function waitForWalletDetection(adapter, timeoutMs = 5e3) {
2976
+ if (adapter.readyState === "Installed") return;
2977
+ return new Promise((resolve, reject) => {
2978
+ let settled = false;
2979
+ const settle = () => {
2980
+ if (settled) return;
2981
+ settled = true;
2982
+ clearTimeout(timer);
2983
+ adapter.off("readyStateChange", onReady);
2984
+ resolve();
2985
+ };
2986
+ const timer = setTimeout(() => {
2987
+ if (settled) return;
2988
+ settled = true;
2989
+ adapter.off("readyStateChange", onReady);
2990
+ reject(
2991
+ new Error(
2992
+ `Wallet extension not detected within ${timeoutMs}ms. Is the browser extension installed and enabled?`
2993
+ )
2994
+ );
2995
+ }, timeoutMs);
2996
+ const onReady = (state) => {
2997
+ if (state === "Installed") settle();
2998
+ };
2999
+ adapter.on("readyStateChange", onReady);
3000
+ if (adapter.readyState === "Installed") settle();
3001
+ });
3002
+ }
3003
+
3004
+ // src/utils/storage.ts
3005
+ async function migrateStorage(options) {
3006
+ if (typeof window === "undefined") return false;
3007
+ const versionKey = options.versionKey ?? "miden:storageVersion";
3008
+ const stored = localStorage.getItem(versionKey);
3009
+ if (stored === options.version) return false;
3010
+ if (options.onBeforeClear) {
3011
+ await options.onBeforeClear();
3012
+ }
3013
+ await clearMidenStorage();
3014
+ localStorage.setItem(versionKey, options.version);
3015
+ if (options.reloadOnClear !== false) {
3016
+ window.location.reload();
3017
+ }
3018
+ return true;
3019
+ }
3020
+ async function clearMidenStorage() {
3021
+ if (typeof indexedDB === "undefined") return;
3022
+ try {
3023
+ const databases = await indexedDB.databases();
3024
+ const midenDbs = databases.filter(
3025
+ (db) => db.name?.toLowerCase().includes("miden")
3026
+ );
3027
+ await Promise.all(
3028
+ midenDbs.map(
3029
+ (db) => new Promise((resolve, reject) => {
3030
+ if (!db.name) {
3031
+ resolve();
3032
+ return;
3033
+ }
3034
+ const req = indexedDB.deleteDatabase(db.name);
3035
+ req.onsuccess = () => resolve();
3036
+ req.onerror = () => reject(req.error);
3037
+ req.onblocked = () => {
3038
+ console.warn(
3039
+ `IndexedDB "${db.name}" delete was blocked \u2014 close other tabs using this database.`
3040
+ );
3041
+ resolve();
3042
+ };
3043
+ })
3044
+ )
3045
+ );
3046
+ } catch {
3047
+ }
3048
+ }
3049
+ function createMidenStorage(prefix) {
3050
+ const fullKey = (key) => `${prefix}:${key}`;
3051
+ return {
3052
+ get(key) {
3053
+ try {
3054
+ const raw = localStorage.getItem(fullKey(key));
3055
+ if (raw === null) return null;
3056
+ return JSON.parse(raw);
3057
+ } catch {
3058
+ return null;
3059
+ }
3060
+ },
3061
+ set(key, value) {
3062
+ try {
3063
+ localStorage.setItem(fullKey(key), JSON.stringify(value));
3064
+ } catch (e) {
3065
+ console.warn(`Failed to write localStorage key "${fullKey(key)}":`, e);
3066
+ }
3067
+ },
3068
+ remove(key) {
3069
+ localStorage.removeItem(fullKey(key));
3070
+ },
3071
+ clear() {
3072
+ const keysToRemove = [];
3073
+ for (let i = 0; i < localStorage.length; i++) {
3074
+ const k = localStorage.key(i);
3075
+ if (k?.startsWith(`${prefix}:`)) {
3076
+ keysToRemove.push(k);
3077
+ }
3078
+ }
3079
+ keysToRemove.forEach((k) => localStorage.removeItem(k));
3080
+ }
3081
+ };
3082
+ }
3083
+
2296
3084
  // src/index.ts
2297
3085
  installAccountBech32();
2298
3086
  // Annotate the CommonJS export names for ESM import in node:
2299
3087
  0 && (module.exports = {
2300
3088
  DEFAULTS,
3089
+ MidenError,
2301
3090
  MidenProvider,
2302
3091
  SignerContext,
3092
+ accountIdsEqual,
3093
+ bigIntToBytes,
3094
+ bytesToBigInt,
3095
+ clearMidenStorage,
3096
+ concatBytes,
3097
+ createMidenStorage,
3098
+ createNoteAttachment,
2303
3099
  formatAssetAmount,
2304
3100
  formatNoteSummary,
2305
3101
  getNoteSummary,
3102
+ migrateStorage,
3103
+ normalizeAccountId,
2306
3104
  parseAssetAmount,
3105
+ readNoteAttachment,
2307
3106
  toBech32AccountId,
2308
3107
  useAccount,
2309
3108
  useAccounts,
@@ -2317,13 +3116,17 @@ installAccountBech32();
2317
3116
  useMidenClient,
2318
3117
  useMint,
2319
3118
  useMultiSend,
3119
+ useNoteStream,
2320
3120
  useNotes,
2321
3121
  useSend,
3122
+ useSessionAccount,
2322
3123
  useSigner,
2323
3124
  useSwap,
2324
3125
  useSyncState,
2325
3126
  useTransaction,
2326
3127
  useTransactionHistory,
2327
3128
  useWaitForCommit,
2328
- useWaitForNotes
3129
+ useWaitForNotes,
3130
+ waitForWalletDetection,
3131
+ wrapWasmError
2329
3132
  });