@miden-sdk/react 0.13.2 → 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)) {
@@ -506,9 +612,6 @@ function MidenProvider({
506
612
  }
507
613
  return;
508
614
  }
509
- if (!signerContext) {
510
- isInitializedRef.current = true;
511
- }
512
615
  let cancelled = false;
513
616
  const initClient = async () => {
514
617
  await runExclusive(async () => {
@@ -568,6 +671,9 @@ function MidenProvider({
568
671
  }
569
672
  }
570
673
  if (!cancelled) {
674
+ if (!signerContext) {
675
+ isInitializedRef.current = true;
676
+ }
571
677
  setClient(webClient);
572
678
  }
573
679
  } catch (error) {
@@ -582,6 +688,7 @@ function MidenProvider({
582
688
  initClient();
583
689
  return () => {
584
690
  cancelled = true;
691
+ isInitializedRef.current = false;
585
692
  };
586
693
  }, [
587
694
  runExclusive,
@@ -697,16 +804,6 @@ function useAccounts() {
697
804
  refetch
698
805
  };
699
806
  }
700
- function isFaucetId(accountId) {
701
- try {
702
- const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
703
- const firstByte = parseInt(hex.slice(0, 2), 16);
704
- const accountType = firstByte >> 4 & 3;
705
- return accountType === 2 || accountType === 3;
706
- } catch {
707
- return false;
708
- }
709
- }
710
807
 
711
808
  // src/hooks/useAccount.ts
712
809
  var import_react5 = require("react");
@@ -729,17 +826,12 @@ var getRpcClient = (rpcUrl) => {
729
826
  return null;
730
827
  }
731
828
  };
732
- var fetchAssetMetadata = async (client, rpcClient, assetId) => {
829
+ var fetchAssetMetadata = async (rpcClient, assetId) => {
733
830
  try {
734
831
  const accountId = parseAccountId(assetId);
735
- let account = await client.getAccount(accountId);
736
- if (!account && rpcClient) {
737
- try {
738
- const fetched = await rpcClient.getAccountDetails(accountId);
739
- account = fetched.account?.();
740
- } catch {
741
- }
742
- }
832
+ if (!isFaucetId(accountId)) return null;
833
+ const fetched = await rpcClient.getAccountDetails(accountId);
834
+ const account = fetched.account?.();
743
835
  if (!account) return null;
744
836
  const faucet = import_miden_sdk6.BasicFungibleFaucetComponent.fromAccount(account);
745
837
  const symbol = faucet.symbol().toString();
@@ -750,8 +842,6 @@ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
750
842
  }
751
843
  };
752
844
  function useAssetMetadata(assetIds = []) {
753
- const { client, isReady, runExclusive } = useMiden();
754
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
755
845
  const assetMetadata = useAssetMetadataStore();
756
846
  const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
757
847
  const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
@@ -761,32 +851,19 @@ function useAssetMetadata(assetIds = []) {
761
851
  [assetIds]
762
852
  );
763
853
  (0, import_react4.useEffect)(() => {
764
- if (!client || !isReady || uniqueAssetIds.length === 0) return;
854
+ if (!rpcClient || uniqueAssetIds.length === 0) return;
765
855
  uniqueAssetIds.forEach((assetId) => {
766
856
  const existing = assetMetadata.get(assetId);
767
857
  const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
768
858
  if (hasMetadata || inflight.has(assetId)) return;
769
- const promise = runExclusiveSafe(async () => {
770
- const metadata = await fetchAssetMetadata(
771
- client,
772
- rpcClient,
773
- assetId
774
- );
859
+ const promise = fetchAssetMetadata(rpcClient, assetId).then((metadata) => {
775
860
  setAssetMetadata(assetId, metadata ?? { assetId });
776
861
  }).finally(() => {
777
862
  inflight.delete(assetId);
778
863
  });
779
864
  inflight.set(assetId, promise);
780
865
  });
781
- }, [
782
- client,
783
- isReady,
784
- uniqueAssetIds,
785
- assetMetadata,
786
- runExclusiveSafe,
787
- setAssetMetadata,
788
- rpcClient
789
- ]);
866
+ }, [uniqueAssetIds, assetMetadata, setAssetMetadata, rpcClient]);
790
867
  return { assetMetadata };
791
868
  }
792
869
 
@@ -888,7 +965,7 @@ function useAccount(accountId) {
888
965
 
889
966
  // src/hooks/useNotes.ts
890
967
  var import_react6 = require("react");
891
- var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
968
+ var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
892
969
 
893
970
  // src/utils/amounts.ts
894
971
  var formatAssetAmount = (amount, decimals) => {
@@ -972,6 +1049,82 @@ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(
972
1049
  return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
973
1050
  };
974
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
+
975
1128
  // src/hooks/useNotes.ts
976
1129
  function useNotes(options) {
977
1130
  const { client, isReady, runExclusive } = useMiden();
@@ -980,8 +1133,10 @@ function useNotes(options) {
980
1133
  const consumableNotes = useConsumableNotesStore();
981
1134
  const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
982
1135
  const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
983
- const setNotes = useMidenStore((state) => state.setNotes);
984
- const setConsumableNotes = useMidenStore((state) => state.setConsumableNotes);
1136
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1137
+ const setConsumableNotesIfChanged = useMidenStore(
1138
+ (state) => state.setConsumableNotesIfChanged
1139
+ );
985
1140
  const { lastSyncTime } = useSyncStateStore();
986
1141
  const [error, setError] = (0, import_react6.useState)(null);
987
1142
  const refetch = (0, import_react6.useCallback)(async () => {
@@ -992,7 +1147,7 @@ function useNotes(options) {
992
1147
  const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
993
1148
  async () => {
994
1149
  const filterType = getNoteFilterType(options?.status);
995
- const filter = new import_miden_sdk7.NoteFilter(filterType);
1150
+ const filter = new import_miden_sdk8.NoteFilter(filterType);
996
1151
  const notesResult = await client.getInputNotes(filter);
997
1152
  let consumableResult;
998
1153
  if (options?.accountId) {
@@ -1007,8 +1162,8 @@ function useNotes(options) {
1007
1162
  };
1008
1163
  }
1009
1164
  );
1010
- setNotes(fetchedNotes);
1011
- setConsumableNotes(fetchedConsumable);
1165
+ setNotesIfChanged(fetchedNotes);
1166
+ setConsumableNotesIfChanged(fetchedConsumable);
1012
1167
  } catch (err) {
1013
1168
  setError(err instanceof Error ? err : new Error(String(err)));
1014
1169
  } finally {
@@ -1021,8 +1176,8 @@ function useNotes(options) {
1021
1176
  options?.status,
1022
1177
  options?.accountId,
1023
1178
  setLoadingNotes,
1024
- setNotes,
1025
- setConsumableNotes
1179
+ setNotesIfChanged,
1180
+ setConsumableNotesIfChanged
1026
1181
  ]);
1027
1182
  (0, import_react6.useEffect)(() => {
1028
1183
  if (isReady && notes.length === 0) {
@@ -1049,14 +1204,65 @@ function useNotes(options) {
1049
1204
  (assetId) => assetMetadata.get(assetId),
1050
1205
  [assetMetadata]
1051
1206
  );
1052
- const noteSummaries = (0, import_react6.useMemo)(
1053
- () => notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1054
- [notes, getMetadata]
1055
- );
1056
- const consumableNoteSummaries = (0, import_react6.useMemo)(
1057
- () => consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
1058
- [consumableNotes, getMetadata]
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
+ []
1059
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
+ ]);
1060
1266
  return {
1061
1267
  notes,
1062
1268
  consumableNotes,
@@ -1067,46 +1273,246 @@ function useNotes(options) {
1067
1273
  refetch
1068
1274
  };
1069
1275
  }
1070
- function getNoteFilterType(status) {
1071
- switch (status) {
1072
- case "consumed":
1073
- return import_miden_sdk7.NoteFilterTypes.Consumed;
1074
- case "committed":
1075
- return import_miden_sdk7.NoteFilterTypes.Committed;
1076
- case "expected":
1077
- return import_miden_sdk7.NoteFilterTypes.Expected;
1078
- case "processing":
1079
- return import_miden_sdk7.NoteFilterTypes.Processing;
1080
- case "all":
1081
- default:
1082
- return import_miden_sdk7.NoteFilterTypes.All;
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
+ );
1083
1343
  }
1344
+ return newArray.call(import_miden_sdk9.NoteAttachment, scheme, words);
1084
1345
  }
1085
1346
 
1086
- // src/hooks/useTransactionHistory.ts
1087
- var import_react7 = require("react");
1088
- var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
1089
- function useTransactionHistory(options = {}) {
1347
+ // src/hooks/useNoteStream.ts
1348
+ function useNoteStream(options = {}) {
1090
1349
  const { client, isReady, runExclusive } = useMiden();
1091
1350
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1351
+ const allNotes = useNotesStore();
1352
+ const noteFirstSeen = useNoteFirstSeenStore();
1092
1353
  const { lastSyncTime } = useSyncStateStore();
1093
- const [records, setRecords] = (0, import_react7.useState)([]);
1354
+ const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
1094
1355
  const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1095
1356
  const [error, setError] = (0, import_react7.useState)(null);
1096
- 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)(() => {
1097
1503
  if (options.id) return [options.id];
1098
1504
  if (options.ids && options.ids.length > 0) return options.ids;
1099
1505
  return null;
1100
1506
  }, [options.id, options.ids]);
1101
- const idsHex = (0, import_react7.useMemo)(() => {
1507
+ const idsHex = (0, import_react8.useMemo)(() => {
1102
1508
  if (!rawIds) return null;
1103
1509
  return rawIds.map(
1104
- (id) => normalizeHex(typeof id === "string" ? id : id.toHex())
1510
+ (id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
1105
1511
  );
1106
1512
  }, [rawIds]);
1107
1513
  const filter = options.filter;
1108
1514
  const refreshOnSync = options.refreshOnSync !== false;
1109
- const refetch = (0, import_react7.useCallback)(async () => {
1515
+ const refetch = (0, import_react8.useCallback)(async () => {
1110
1516
  if (!client || !isReady) return;
1111
1517
  setIsLoading(true);
1112
1518
  setError(null);
@@ -1120,7 +1526,7 @@ function useTransactionHistory(options = {}) {
1120
1526
  () => client.getTransactions(resolvedFilter)
1121
1527
  );
1122
1528
  const filtered = localFilterHexes ? fetched.filter(
1123
- (record2) => localFilterHexes.includes(normalizeHex(record2.id().toHex()))
1529
+ (record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
1124
1530
  ) : fetched;
1125
1531
  setRecords(filtered);
1126
1532
  } catch (err) {
@@ -1129,19 +1535,19 @@ function useTransactionHistory(options = {}) {
1129
1535
  setIsLoading(false);
1130
1536
  }
1131
1537
  }, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
1132
- (0, import_react7.useEffect)(() => {
1538
+ (0, import_react8.useEffect)(() => {
1133
1539
  if (!isReady) return;
1134
1540
  refetch();
1135
1541
  }, [isReady, refetch]);
1136
- (0, import_react7.useEffect)(() => {
1542
+ (0, import_react8.useEffect)(() => {
1137
1543
  if (!isReady || !refreshOnSync || !lastSyncTime) return;
1138
1544
  refetch();
1139
1545
  }, [isReady, lastSyncTime, refreshOnSync, refetch]);
1140
- const record = (0, import_react7.useMemo)(() => {
1546
+ const record = (0, import_react8.useMemo)(() => {
1141
1547
  if (!idsHex || idsHex.length !== 1) return null;
1142
- return records.find((item) => normalizeHex(item.id().toHex()) === idsHex[0]) ?? null;
1548
+ return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
1143
1549
  }, [records, idsHex]);
1144
- const status = (0, import_react7.useMemo)(() => {
1550
+ const status = (0, import_react8.useMemo)(() => {
1145
1551
  if (!record) return null;
1146
1552
  const current = record.transactionStatus();
1147
1553
  if (current.isCommitted()) return "committed";
@@ -1163,29 +1569,29 @@ function buildFilter(filter, ids, idsHex) {
1163
1569
  return { filter };
1164
1570
  }
1165
1571
  if (!ids || ids.length === 0) {
1166
- return { filter: import_miden_sdk8.TransactionFilter.all() };
1572
+ return { filter: import_miden_sdk11.TransactionFilter.all() };
1167
1573
  }
1168
1574
  const allTransactionIds = ids.every((id) => typeof id !== "string");
1169
1575
  if (allTransactionIds) {
1170
- return { filter: import_miden_sdk8.TransactionFilter.ids(ids) };
1576
+ return { filter: import_miden_sdk11.TransactionFilter.ids(ids) };
1171
1577
  }
1172
1578
  return {
1173
- filter: import_miden_sdk8.TransactionFilter.all(),
1579
+ filter: import_miden_sdk11.TransactionFilter.all(),
1174
1580
  localFilterHexes: idsHex ?? []
1175
1581
  };
1176
1582
  }
1177
- function normalizeHex(value) {
1583
+ function normalizeHex2(value) {
1178
1584
  const trimmed = value.trim();
1179
1585
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1180
1586
  return normalized.toLowerCase();
1181
1587
  }
1182
1588
 
1183
1589
  // src/hooks/useSyncState.ts
1184
- var import_react8 = require("react");
1590
+ var import_react9 = require("react");
1185
1591
  function useSyncState() {
1186
1592
  const { sync: triggerSync } = useMiden();
1187
1593
  const syncState = useSyncStateStore();
1188
- const sync = (0, import_react8.useCallback)(async () => {
1594
+ const sync = (0, import_react9.useCallback)(async () => {
1189
1595
  await triggerSync();
1190
1596
  }, [triggerSync]);
1191
1597
  return {
@@ -1195,16 +1601,16 @@ function useSyncState() {
1195
1601
  }
1196
1602
 
1197
1603
  // src/hooks/useCreateWallet.ts
1198
- var import_react9 = require("react");
1199
- 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");
1200
1606
  function useCreateWallet() {
1201
1607
  const { client, isReady, sync, runExclusive } = useMiden();
1202
1608
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1203
1609
  const setAccounts = useMidenStore((state) => state.setAccounts);
1204
- const [wallet, setWallet] = (0, import_react9.useState)(null);
1205
- const [isCreating, setIsCreating] = (0, import_react9.useState)(false);
1206
- const [error, setError] = (0, import_react9.useState)(null);
1207
- const createWallet = (0, import_react9.useCallback)(
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)(
1208
1614
  async (options = {}) => {
1209
1615
  if (!client || !isReady) {
1210
1616
  throw new Error("Miden client is not ready");
@@ -1242,7 +1648,7 @@ function useCreateWallet() {
1242
1648
  },
1243
1649
  [client, isReady, runExclusive, setAccounts]
1244
1650
  );
1245
- const reset = (0, import_react9.useCallback)(() => {
1651
+ const reset = (0, import_react10.useCallback)(() => {
1246
1652
  setWallet(null);
1247
1653
  setIsCreating(false);
1248
1654
  setError(null);
@@ -1258,27 +1664,27 @@ function useCreateWallet() {
1258
1664
  function getStorageMode(mode) {
1259
1665
  switch (mode) {
1260
1666
  case "private":
1261
- return import_miden_sdk9.AccountStorageMode.private();
1667
+ return import_miden_sdk12.AccountStorageMode.private();
1262
1668
  case "public":
1263
- return import_miden_sdk9.AccountStorageMode.public();
1669
+ return import_miden_sdk12.AccountStorageMode.public();
1264
1670
  case "network":
1265
- return import_miden_sdk9.AccountStorageMode.network();
1671
+ return import_miden_sdk12.AccountStorageMode.network();
1266
1672
  default:
1267
- return import_miden_sdk9.AccountStorageMode.private();
1673
+ return import_miden_sdk12.AccountStorageMode.private();
1268
1674
  }
1269
1675
  }
1270
1676
 
1271
1677
  // src/hooks/useCreateFaucet.ts
1272
- var import_react10 = require("react");
1273
- 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");
1274
1680
  function useCreateFaucet() {
1275
1681
  const { client, isReady, runExclusive } = useMiden();
1276
1682
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1277
1683
  const setAccounts = useMidenStore((state) => state.setAccounts);
1278
- const [faucet, setFaucet] = (0, import_react10.useState)(null);
1279
- const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
1280
- const [error, setError] = (0, import_react10.useState)(null);
1281
- const createFaucet = (0, import_react10.useCallback)(
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)(
1282
1688
  async (options) => {
1283
1689
  if (!client || !isReady) {
1284
1690
  throw new Error("Miden client is not ready");
@@ -1317,7 +1723,7 @@ function useCreateFaucet() {
1317
1723
  },
1318
1724
  [client, isReady, runExclusive, setAccounts]
1319
1725
  );
1320
- const reset = (0, import_react10.useCallback)(() => {
1726
+ const reset = (0, import_react11.useCallback)(() => {
1321
1727
  setFaucet(null);
1322
1728
  setIsCreating(false);
1323
1729
  setError(null);
@@ -1333,27 +1739,27 @@ function useCreateFaucet() {
1333
1739
  function getStorageMode2(mode) {
1334
1740
  switch (mode) {
1335
1741
  case "private":
1336
- return import_miden_sdk10.AccountStorageMode.private();
1742
+ return import_miden_sdk13.AccountStorageMode.private();
1337
1743
  case "public":
1338
- return import_miden_sdk10.AccountStorageMode.public();
1744
+ return import_miden_sdk13.AccountStorageMode.public();
1339
1745
  case "network":
1340
- return import_miden_sdk10.AccountStorageMode.network();
1746
+ return import_miden_sdk13.AccountStorageMode.network();
1341
1747
  default:
1342
- return import_miden_sdk10.AccountStorageMode.private();
1748
+ return import_miden_sdk13.AccountStorageMode.private();
1343
1749
  }
1344
1750
  }
1345
1751
 
1346
1752
  // src/hooks/useImportAccount.ts
1347
- var import_react11 = require("react");
1348
- 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");
1349
1755
  function useImportAccount() {
1350
1756
  const { client, isReady, runExclusive } = useMiden();
1351
1757
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1352
1758
  const setAccounts = useMidenStore((state) => state.setAccounts);
1353
- const [account, setAccount] = (0, import_react11.useState)(null);
1354
- const [isImporting, setIsImporting] = (0, import_react11.useState)(false);
1355
- const [error, setError] = (0, import_react11.useState)(null);
1356
- const importAccount = (0, import_react11.useCallback)(
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)(
1357
1763
  async (options) => {
1358
1764
  if (!client || !isReady) {
1359
1765
  throw new Error("Miden client is not ready");
@@ -1448,7 +1854,7 @@ function useImportAccount() {
1448
1854
  },
1449
1855
  [client, isReady, runExclusive, setAccounts]
1450
1856
  );
1451
- const reset = (0, import_react11.useCallback)(() => {
1857
+ const reset = (0, import_react12.useCallback)(() => {
1452
1858
  setAccount(null);
1453
1859
  setIsImporting(false);
1454
1860
  setError(null);
@@ -1466,10 +1872,10 @@ function resolveAccountId(accountId) {
1466
1872
  }
1467
1873
  async function resolveAccountFile(file) {
1468
1874
  if (file instanceof Uint8Array) {
1469
- return import_miden_sdk11.AccountFile.deserialize(file);
1875
+ return import_miden_sdk14.AccountFile.deserialize(file);
1470
1876
  }
1471
1877
  if (file instanceof ArrayBuffer) {
1472
- return import_miden_sdk11.AccountFile.deserialize(new Uint8Array(file));
1878
+ return import_miden_sdk14.AccountFile.deserialize(new Uint8Array(file));
1473
1879
  }
1474
1880
  return file;
1475
1881
  }
@@ -1498,43 +1904,146 @@ function bytesEqual(left, right) {
1498
1904
  }
1499
1905
 
1500
1906
  // src/hooks/useSend.ts
1501
- var import_react12 = require("react");
1502
- 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
1503
1956
  function useSend() {
1504
1957
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1505
1958
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1506
- const [result, setResult] = (0, import_react12.useState)(null);
1507
- const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
1508
- const [stage, setStage] = (0, import_react12.useState)("idle");
1509
- const [error, setError] = (0, import_react12.useState)(null);
1510
- const send = (0, import_react12.useCallback)(
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)(
1511
1965
  async (options) => {
1512
1966
  if (!client || !isReady) {
1513
1967
  throw new Error("Miden client is not ready");
1514
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;
1515
1976
  setIsLoading(true);
1516
1977
  setStage("executing");
1517
1978
  setError(null);
1518
1979
  try {
1980
+ if (!options.skipSync) {
1981
+ await sync();
1982
+ }
1519
1983
  const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1520
- const fromAccountId = parseAccountId(options.from);
1521
- 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
+ }
1522
2006
  const assetId = options.assetId ?? options.faucetId ?? null;
1523
2007
  if (!assetId) {
1524
2008
  throw new Error("Asset ID is required");
1525
2009
  }
1526
- const assetIdObj = parseAccountId(assetId);
1527
- const txResult = await runExclusiveSafe(async () => {
1528
- const txRequest = client.newSendTransactionRequest(
1529
- fromAccountId,
1530
- toAccountId,
1531
- assetIdObj,
1532
- noteType,
1533
- options.amount,
1534
- options.recallHeight ?? null,
1535
- options.timelockHeight ?? null
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"
1536
2014
  );
1537
- 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);
1538
2047
  });
1539
2048
  setStage("proving");
1540
2049
  const provenTransaction = await runExclusiveSafe(
@@ -1544,22 +2053,31 @@ function useSend() {
1544
2053
  const submissionHeight = await runExclusiveSafe(
1545
2054
  () => client.submitProvenTransaction(provenTransaction, txResult)
1546
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
+ }
1547
2062
  await runExclusiveSafe(
1548
2063
  () => client.applyTransaction(txResult, submissionHeight)
1549
2064
  );
1550
- const txId = txResult.id();
1551
- await waitForTransactionCommit(client, runExclusiveSafe, txId);
1552
- if (noteType === import_miden_sdk12.NoteType.Private) {
1553
- const fullNote = extractFullNote(txResult);
2065
+ if (noteType === import_miden_sdk15.NoteType.Private) {
1554
2066
  if (!fullNote) {
1555
2067
  throw new Error("Missing full note for private send");
1556
2068
  }
1557
- 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);
1558
2076
  await runExclusiveSafe(
1559
2077
  () => client.sendPrivateNote(fullNote, recipientAddress)
1560
2078
  );
1561
2079
  }
1562
- const txSummary = { transactionId: txResult.id().toString() };
2080
+ const txSummary = { transactionId: txIdString };
1563
2081
  setStage("complete");
1564
2082
  setResult(txSummary);
1565
2083
  await sync();
@@ -1571,11 +2089,12 @@ function useSend() {
1571
2089
  throw error2;
1572
2090
  } finally {
1573
2091
  setIsLoading(false);
2092
+ isBusyRef.current = false;
1574
2093
  }
1575
2094
  },
1576
2095
  [client, isReady, prover, runExclusive, sync]
1577
2096
  );
1578
- const reset = (0, import_react12.useCallback)(() => {
2097
+ const reset = (0, import_react13.useCallback)(() => {
1579
2098
  setResult(null);
1580
2099
  setIsLoading(false);
1581
2100
  setStage("idle");
@@ -1590,39 +2109,6 @@ function useSend() {
1590
2109
  reset
1591
2110
  };
1592
2111
  }
1593
- function getNoteType(type) {
1594
- switch (type) {
1595
- case "private":
1596
- return import_miden_sdk12.NoteType.Private;
1597
- case "public":
1598
- return import_miden_sdk12.NoteType.Public;
1599
- case "encrypted":
1600
- return import_miden_sdk12.NoteType.Encrypted;
1601
- default:
1602
- return import_miden_sdk12.NoteType.Private;
1603
- }
1604
- }
1605
- async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1606
- let waited = 0;
1607
- while (waited < maxWaitMs) {
1608
- await runExclusiveSafe(() => client.syncState());
1609
- const [record] = await runExclusiveSafe(
1610
- () => client.getTransactions(import_miden_sdk12.TransactionFilter.ids([txId]))
1611
- );
1612
- if (record) {
1613
- const status = record.transactionStatus();
1614
- if (status.isCommitted()) {
1615
- return;
1616
- }
1617
- if (status.isDiscarded()) {
1618
- throw new Error("Transaction was discarded before commit");
1619
- }
1620
- }
1621
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1622
- waited += delayMs;
1623
- }
1624
- throw new Error("Timeout waiting for transaction commit");
1625
- }
1626
2112
  function extractFullNote(txResult) {
1627
2113
  try {
1628
2114
  const executedTx = txResult.executedTransaction?.();
@@ -1635,16 +2121,17 @@ function extractFullNote(txResult) {
1635
2121
  }
1636
2122
 
1637
2123
  // src/hooks/useMultiSend.ts
1638
- var import_react13 = require("react");
1639
- 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");
1640
2126
  function useMultiSend() {
1641
2127
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1642
2128
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1643
- const [result, setResult] = (0, import_react13.useState)(null);
1644
- const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1645
- const [stage, setStage] = (0, import_react13.useState)("idle");
1646
- const [error, setError] = (0, import_react13.useState)(null);
1647
- const sendMany = (0, import_react13.useCallback)(
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)(
1648
2135
  async (options) => {
1649
2136
  if (!client || !isReady) {
1650
2137
  throw new Error("Miden client is not ready");
@@ -1652,35 +2139,53 @@ function useMultiSend() {
1652
2139
  if (options.recipients.length === 0) {
1653
2140
  throw new Error("No recipients provided");
1654
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;
1655
2149
  setIsLoading(true);
1656
2150
  setStage("executing");
1657
2151
  setError(null);
1658
2152
  try {
1659
- const noteType = getNoteType2(options.noteType ?? DEFAULTS.NOTE_TYPE);
1660
- const senderId = parseAccountId(options.from);
1661
- const assetId = parseAccountId(options.assetId);
1662
- const outputs = options.recipients.map(({ to, amount }) => {
1663
- const receiverId = parseAccountId(to);
1664
- const assets = new import_miden_sdk13.NoteAssets([new import_miden_sdk13.FungibleAsset(assetId, amount)]);
1665
- const note = import_miden_sdk13.Note.createP2IDNote(
1666
- senderId,
1667
- receiverId,
1668
- assets,
1669
- noteType,
1670
- new import_miden_sdk13.NoteAttachment()
1671
- );
1672
- const recipientAddress = parseAddress(to, receiverId);
1673
- return {
1674
- outputNote: import_miden_sdk13.OutputNote.full(note),
1675
- note,
1676
- recipientAddress
1677
- };
1678
- });
1679
- const txRequest = new import_miden_sdk13.TransactionRequestBuilder().withOwnOutputNotes(
1680
- new import_miden_sdk13.OutputNoteArray(outputs.map((o) => o.outputNote))
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))
1681
2185
  ).build();
2186
+ const txSenderId = parseAccountId(options.from);
1682
2187
  const txResult = await runExclusiveSafe(
1683
- () => client.executeTransaction(senderId, txRequest)
2188
+ () => client.executeTransaction(txSenderId, txRequest)
1684
2189
  );
1685
2190
  setStage("proving");
1686
2191
  const provenTransaction = await runExclusiveSafe(
@@ -1690,23 +2195,27 @@ function useMultiSend() {
1690
2195
  const submissionHeight = await runExclusiveSafe(
1691
2196
  () => client.submitProvenTransaction(provenTransaction, txResult)
1692
2197
  );
2198
+ const txIdHex = txResult.id().toHex();
2199
+ const txIdString = txResult.id().toString();
1693
2200
  await runExclusiveSafe(
1694
2201
  () => client.applyTransaction(txResult, submissionHeight)
1695
2202
  );
1696
- const txId = txResult.id();
1697
- if (noteType === import_miden_sdk13.NoteType.Private) {
1698
- await waitForTransactionCommit2(
2203
+ const hasPrivate = outputs.some((o) => o.noteType === import_miden_sdk16.NoteType.Private);
2204
+ if (hasPrivate) {
2205
+ await waitForTransactionCommit(
1699
2206
  client,
1700
2207
  runExclusiveSafe,
1701
- txId
2208
+ txIdHex
1702
2209
  );
1703
2210
  for (const output of outputs) {
1704
- await runExclusiveSafe(
1705
- () => client.sendPrivateNote(output.note, output.recipientAddress)
1706
- );
2211
+ if (output.noteType === import_miden_sdk16.NoteType.Private) {
2212
+ await runExclusiveSafe(
2213
+ () => client.sendPrivateNote(output.note, output.recipientAddress)
2214
+ );
2215
+ }
1707
2216
  }
1708
2217
  }
1709
- const txSummary = { transactionId: txId.toString() };
2218
+ const txSummary = { transactionId: txIdString };
1710
2219
  setStage("complete");
1711
2220
  setResult(txSummary);
1712
2221
  await sync();
@@ -1718,11 +2227,12 @@ function useMultiSend() {
1718
2227
  throw error2;
1719
2228
  } finally {
1720
2229
  setIsLoading(false);
2230
+ isBusyRef.current = false;
1721
2231
  }
1722
2232
  },
1723
2233
  [client, isReady, prover, runExclusive, sync]
1724
2234
  );
1725
- const reset = (0, import_react13.useCallback)(() => {
2235
+ const reset = (0, import_react14.useCallback)(() => {
1726
2236
  setResult(null);
1727
2237
  setIsLoading(false);
1728
2238
  setStage("idle");
@@ -1737,71 +2247,38 @@ function useMultiSend() {
1737
2247
  reset
1738
2248
  };
1739
2249
  }
1740
- function getNoteType2(type) {
1741
- switch (type) {
1742
- case "private":
1743
- return import_miden_sdk13.NoteType.Private;
1744
- case "public":
1745
- return import_miden_sdk13.NoteType.Public;
1746
- case "encrypted":
1747
- return import_miden_sdk13.NoteType.Encrypted;
1748
- default:
1749
- return import_miden_sdk13.NoteType.Private;
1750
- }
1751
- }
1752
- async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1753
- let waited = 0;
1754
- while (waited < maxWaitMs) {
1755
- await runExclusiveSafe(() => client.syncState());
1756
- const [record] = await runExclusiveSafe(
1757
- () => client.getTransactions(import_miden_sdk13.TransactionFilter.ids([txId]))
1758
- );
1759
- if (record) {
1760
- const status = record.transactionStatus();
1761
- if (status.isCommitted()) {
1762
- return;
1763
- }
1764
- if (status.isDiscarded()) {
1765
- throw new Error("Transaction was discarded before commit");
1766
- }
1767
- }
1768
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1769
- waited += delayMs;
1770
- }
1771
- throw new Error("Timeout waiting for transaction commit");
1772
- }
1773
2250
 
1774
2251
  // src/hooks/useInternalTransfer.ts
1775
- var import_react14 = require("react");
1776
- 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");
1777
2254
  function useInternalTransfer() {
1778
2255
  const { client, isReady, sync, runExclusive, prover } = useMiden();
1779
2256
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1780
- const [result, setResult] = (0, import_react14.useState)(null);
1781
- const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
1782
- const [stage, setStage] = (0, import_react14.useState)("idle");
1783
- const [error, setError] = (0, import_react14.useState)(null);
1784
- const transferOnce = (0, import_react14.useCallback)(
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)(
1785
2262
  async (options) => {
1786
2263
  if (!client || !isReady) {
1787
2264
  throw new Error("Miden client is not ready");
1788
2265
  }
1789
- const noteType = getNoteType3(options.noteType ?? DEFAULTS.NOTE_TYPE);
2266
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1790
2267
  const senderId = parseAccountId(options.from);
1791
2268
  const receiverId = parseAccountId(options.to);
1792
2269
  const assetId = parseAccountId(options.assetId);
1793
- const assets = new import_miden_sdk14.NoteAssets([
1794
- 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)
1795
2272
  ]);
1796
- const note = import_miden_sdk14.Note.createP2IDNote(
2273
+ const note = import_miden_sdk17.Note.createP2IDNote(
1797
2274
  senderId,
1798
2275
  receiverId,
1799
2276
  assets,
1800
2277
  noteType,
1801
- new import_miden_sdk14.NoteAttachment()
2278
+ new import_miden_sdk17.NoteAttachment()
1802
2279
  );
1803
2280
  const noteId = note.id().toString();
1804
- const createRequest = new import_miden_sdk14.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk14.OutputNoteArray([import_miden_sdk14.OutputNote.full(note)])).build();
2281
+ const createRequest = new import_miden_sdk17.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk17.OutputNoteArray([import_miden_sdk17.OutputNote.full(note)])).build();
1805
2282
  const createTxId = await runExclusiveSafe(
1806
2283
  () => prover ? client.submitNewTransactionWithProver(
1807
2284
  senderId,
@@ -1809,7 +2286,7 @@ function useInternalTransfer() {
1809
2286
  prover
1810
2287
  ) : client.submitNewTransaction(senderId, createRequest)
1811
2288
  );
1812
- 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();
1813
2290
  const consumeTxId = await runExclusiveSafe(
1814
2291
  () => prover ? client.submitNewTransactionWithProver(
1815
2292
  receiverId,
@@ -1825,7 +2302,7 @@ function useInternalTransfer() {
1825
2302
  },
1826
2303
  [client, isReady, prover, runExclusiveSafe]
1827
2304
  );
1828
- const transfer = (0, import_react14.useCallback)(
2305
+ const transfer = (0, import_react15.useCallback)(
1829
2306
  async (options) => {
1830
2307
  if (!client || !isReady) {
1831
2308
  throw new Error("Miden client is not ready");
@@ -1851,7 +2328,7 @@ function useInternalTransfer() {
1851
2328
  },
1852
2329
  [client, isReady, sync, transferOnce]
1853
2330
  );
1854
- const transferChain = (0, import_react14.useCallback)(
2331
+ const transferChain = (0, import_react15.useCallback)(
1855
2332
  async (options) => {
1856
2333
  if (!client || !isReady) {
1857
2334
  throw new Error("Miden client is not ready");
@@ -1892,7 +2369,7 @@ function useInternalTransfer() {
1892
2369
  },
1893
2370
  [client, isReady, sync, transferOnce]
1894
2371
  );
1895
- const reset = (0, import_react14.useCallback)(() => {
2372
+ const reset = (0, import_react15.useCallback)(() => {
1896
2373
  setResult(null);
1897
2374
  setIsLoading(false);
1898
2375
  setStage("idle");
@@ -1908,47 +2385,35 @@ function useInternalTransfer() {
1908
2385
  reset
1909
2386
  };
1910
2387
  }
1911
- function getNoteType3(type) {
1912
- switch (type) {
1913
- case "private":
1914
- return import_miden_sdk14.NoteType.Private;
1915
- case "public":
1916
- return import_miden_sdk14.NoteType.Public;
1917
- case "encrypted":
1918
- return import_miden_sdk14.NoteType.Encrypted;
1919
- default:
1920
- return import_miden_sdk14.NoteType.Private;
1921
- }
1922
- }
1923
2388
 
1924
2389
  // src/hooks/useWaitForCommit.ts
1925
- var import_react15 = require("react");
1926
- 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");
1927
2392
  function useWaitForCommit() {
1928
2393
  const { client, isReady, runExclusive } = useMiden();
1929
2394
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1930
- const waitForCommit = (0, import_react15.useCallback)(
2395
+ const waitForCommit = (0, import_react16.useCallback)(
1931
2396
  async (txId, options) => {
1932
2397
  if (!client || !isReady) {
1933
2398
  throw new Error("Miden client is not ready");
1934
2399
  }
1935
2400
  const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
1936
2401
  const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
1937
- const targetHex = normalizeHex2(
2402
+ const targetHex = normalizeHex3(
1938
2403
  typeof txId === "string" ? txId : txId.toHex()
1939
2404
  );
1940
- let waited = 0;
1941
- while (waited < timeoutMs) {
2405
+ const deadline = Date.now() + timeoutMs;
2406
+ while (Date.now() < deadline) {
1942
2407
  await runExclusiveSafe(
1943
2408
  () => client.syncState()
1944
2409
  );
1945
2410
  const records = await runExclusiveSafe(
1946
2411
  () => client.getTransactions(
1947
- 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])
1948
2413
  )
1949
2414
  );
1950
2415
  const record = records.find(
1951
- (item) => normalizeHex2(item.id().toHex()) === targetHex
2416
+ (item) => normalizeHex3(item.id().toHex()) === targetHex
1952
2417
  );
1953
2418
  if (record) {
1954
2419
  const status = record.transactionStatus();
@@ -1960,7 +2425,6 @@ function useWaitForCommit() {
1960
2425
  }
1961
2426
  }
1962
2427
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
1963
- waited += intervalMs;
1964
2428
  }
1965
2429
  throw new Error("Timeout waiting for transaction commit");
1966
2430
  },
@@ -1968,18 +2432,18 @@ function useWaitForCommit() {
1968
2432
  );
1969
2433
  return { waitForCommit };
1970
2434
  }
1971
- function normalizeHex2(value) {
2435
+ function normalizeHex3(value) {
1972
2436
  const trimmed = value.trim();
1973
2437
  const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1974
2438
  return normalized.toLowerCase();
1975
2439
  }
1976
2440
 
1977
2441
  // src/hooks/useWaitForNotes.ts
1978
- var import_react16 = require("react");
2442
+ var import_react17 = require("react");
1979
2443
  function useWaitForNotes() {
1980
2444
  const { client, isReady, runExclusive } = useMiden();
1981
2445
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1982
- const waitForConsumableNotes = (0, import_react16.useCallback)(
2446
+ const waitForConsumableNotes = (0, import_react17.useCallback)(
1983
2447
  async (options) => {
1984
2448
  if (!client || !isReady) {
1985
2449
  throw new Error("Miden client is not ready");
@@ -1990,7 +2454,9 @@ function useWaitForNotes() {
1990
2454
  const accountId = parseAccountId(options.accountId);
1991
2455
  let waited = 0;
1992
2456
  while (waited < timeoutMs) {
1993
- await runExclusiveSafe(() => client.syncState());
2457
+ await runExclusiveSafe(
2458
+ () => client.syncState()
2459
+ );
1994
2460
  const notes = await runExclusiveSafe(
1995
2461
  () => client.getConsumableNotes(accountId)
1996
2462
  );
@@ -2008,16 +2474,15 @@ function useWaitForNotes() {
2008
2474
  }
2009
2475
 
2010
2476
  // src/hooks/useMint.ts
2011
- var import_react17 = require("react");
2012
- var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
2477
+ var import_react18 = require("react");
2013
2478
  function useMint() {
2014
2479
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2015
2480
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2016
- const [result, setResult] = (0, import_react17.useState)(null);
2017
- const [isLoading, setIsLoading] = (0, import_react17.useState)(false);
2018
- const [stage, setStage] = (0, import_react17.useState)("idle");
2019
- const [error, setError] = (0, import_react17.useState)(null);
2020
- const mint = (0, import_react17.useCallback)(
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)(
2021
2486
  async (options) => {
2022
2487
  if (!client || !isReady) {
2023
2488
  throw new Error("Miden client is not ready");
@@ -2026,7 +2491,7 @@ function useMint() {
2026
2491
  setStage("executing");
2027
2492
  setError(null);
2028
2493
  try {
2029
- const noteType = getNoteType4(options.noteType ?? DEFAULTS.NOTE_TYPE);
2494
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2030
2495
  const targetAccountIdObj = parseAccountId(options.targetAccountId);
2031
2496
  const faucetIdObj = parseAccountId(options.faucetId);
2032
2497
  setStage("proving");
@@ -2059,7 +2524,7 @@ function useMint() {
2059
2524
  },
2060
2525
  [client, isReady, prover, runExclusive, sync]
2061
2526
  );
2062
- const reset = (0, import_react17.useCallback)(() => {
2527
+ const reset = (0, import_react18.useCallback)(() => {
2063
2528
  setResult(null);
2064
2529
  setIsLoading(false);
2065
2530
  setStage("idle");
@@ -2074,30 +2539,18 @@ function useMint() {
2074
2539
  reset
2075
2540
  };
2076
2541
  }
2077
- function getNoteType4(type) {
2078
- switch (type) {
2079
- case "private":
2080
- return import_miden_sdk16.NoteType.Private;
2081
- case "public":
2082
- return import_miden_sdk16.NoteType.Public;
2083
- case "encrypted":
2084
- return import_miden_sdk16.NoteType.Encrypted;
2085
- default:
2086
- return import_miden_sdk16.NoteType.Private;
2087
- }
2088
- }
2089
2542
 
2090
2543
  // src/hooks/useConsume.ts
2091
- var import_react18 = require("react");
2092
- 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");
2093
2546
  function useConsume() {
2094
2547
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2095
2548
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2096
- const [result, setResult] = (0, import_react18.useState)(null);
2097
- const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
2098
- const [stage, setStage] = (0, import_react18.useState)("idle");
2099
- const [error, setError] = (0, import_react18.useState)(null);
2100
- const consume = (0, import_react18.useCallback)(
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)(
2101
2554
  async (options) => {
2102
2555
  if (!client || !isReady) {
2103
2556
  throw new Error("Miden client is not ready");
@@ -2113,9 +2566,9 @@ function useConsume() {
2113
2566
  setStage("proving");
2114
2567
  const txResult = await runExclusiveSafe(async () => {
2115
2568
  const noteIds = options.noteIds.map(
2116
- (noteId) => import_miden_sdk17.NoteId.fromHex(noteId)
2569
+ (noteId) => import_miden_sdk19.NoteId.fromHex(noteId)
2117
2570
  );
2118
- 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);
2119
2572
  const noteRecords = await client.getInputNotes(filter);
2120
2573
  const notes = noteRecords.map((record) => record.toNote());
2121
2574
  if (notes.length === 0) {
@@ -2147,7 +2600,7 @@ function useConsume() {
2147
2600
  },
2148
2601
  [client, isReady, prover, runExclusive, sync]
2149
2602
  );
2150
- const reset = (0, import_react18.useCallback)(() => {
2603
+ const reset = (0, import_react19.useCallback)(() => {
2151
2604
  setResult(null);
2152
2605
  setIsLoading(false);
2153
2606
  setStage("idle");
@@ -2164,16 +2617,15 @@ function useConsume() {
2164
2617
  }
2165
2618
 
2166
2619
  // src/hooks/useSwap.ts
2167
- var import_react19 = require("react");
2168
- var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
2620
+ var import_react20 = require("react");
2169
2621
  function useSwap() {
2170
2622
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2171
2623
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2172
- const [result, setResult] = (0, import_react19.useState)(null);
2173
- const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
2174
- const [stage, setStage] = (0, import_react19.useState)("idle");
2175
- const [error, setError] = (0, import_react19.useState)(null);
2176
- const swap = (0, import_react19.useCallback)(
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)(
2177
2629
  async (options) => {
2178
2630
  if (!client || !isReady) {
2179
2631
  throw new Error("Miden client is not ready");
@@ -2182,8 +2634,8 @@ function useSwap() {
2182
2634
  setStage("executing");
2183
2635
  setError(null);
2184
2636
  try {
2185
- const noteType = getNoteType5(options.noteType ?? DEFAULTS.NOTE_TYPE);
2186
- const paybackNoteType = getNoteType5(
2637
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
2638
+ const paybackNoteType = getNoteType(
2187
2639
  options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
2188
2640
  );
2189
2641
  const accountIdObj = parseAccountId(options.accountId);
@@ -2222,7 +2674,7 @@ function useSwap() {
2222
2674
  },
2223
2675
  [client, isReady, prover, runExclusive, sync]
2224
2676
  );
2225
- const reset = (0, import_react19.useCallback)(() => {
2677
+ const reset = (0, import_react20.useCallback)(() => {
2226
2678
  setResult(null);
2227
2679
  setIsLoading(false);
2228
2680
  setStage("idle");
@@ -2237,41 +2689,40 @@ function useSwap() {
2237
2689
  reset
2238
2690
  };
2239
2691
  }
2240
- function getNoteType5(type) {
2241
- switch (type) {
2242
- case "private":
2243
- return import_miden_sdk18.NoteType.Private;
2244
- case "public":
2245
- return import_miden_sdk18.NoteType.Public;
2246
- case "encrypted":
2247
- return import_miden_sdk18.NoteType.Encrypted;
2248
- default:
2249
- return import_miden_sdk18.NoteType.Private;
2250
- }
2251
- }
2252
2692
 
2253
2693
  // src/hooks/useTransaction.ts
2254
- var import_react20 = require("react");
2694
+ var import_react21 = require("react");
2255
2695
  function useTransaction() {
2256
2696
  const { client, isReady, sync, runExclusive, prover } = useMiden();
2257
2697
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2258
- const [result, setResult] = (0, import_react20.useState)(null);
2259
- const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
2260
- const [stage, setStage] = (0, import_react20.useState)("idle");
2261
- const [error, setError] = (0, import_react20.useState)(null);
2262
- const execute = (0, import_react20.useCallback)(
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)(
2263
2704
  async (options) => {
2264
2705
  if (!client || !isReady) {
2265
2706
  throw new Error("Miden client is not ready");
2266
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;
2267
2715
  setIsLoading(true);
2268
2716
  setStage("executing");
2269
2717
  setError(null);
2270
2718
  try {
2719
+ if (!options.skipSync) {
2720
+ await sync();
2721
+ }
2722
+ const txRequest = await resolveRequest(options.request, client);
2271
2723
  setStage("proving");
2272
2724
  const txResult = await runExclusiveSafe(async () => {
2273
2725
  const accountIdObj = resolveAccountId2(options.accountId);
2274
- const txRequest = await resolveRequest(options.request, client);
2275
2726
  const txId = prover ? await client.submitNewTransactionWithProver(
2276
2727
  accountIdObj,
2277
2728
  txRequest,
@@ -2290,11 +2741,12 @@ function useTransaction() {
2290
2741
  throw error2;
2291
2742
  } finally {
2292
2743
  setIsLoading(false);
2744
+ isBusyRef.current = false;
2293
2745
  }
2294
2746
  },
2295
2747
  [client, isReady, prover, runExclusive, sync]
2296
2748
  );
2297
- const reset = (0, import_react20.useCallback)(() => {
2749
+ const reset = (0, import_react21.useCallback)(() => {
2298
2750
  setResult(null);
2299
2751
  setIsLoading(false);
2300
2752
  setStage("idle");
@@ -2319,17 +2771,338 @@ async function resolveRequest(request, client) {
2319
2771
  return request;
2320
2772
  }
2321
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
+
2322
3084
  // src/index.ts
2323
3085
  installAccountBech32();
2324
3086
  // Annotate the CommonJS export names for ESM import in node:
2325
3087
  0 && (module.exports = {
2326
3088
  DEFAULTS,
3089
+ MidenError,
2327
3090
  MidenProvider,
2328
3091
  SignerContext,
3092
+ accountIdsEqual,
3093
+ bigIntToBytes,
3094
+ bytesToBigInt,
3095
+ clearMidenStorage,
3096
+ concatBytes,
3097
+ createMidenStorage,
3098
+ createNoteAttachment,
2329
3099
  formatAssetAmount,
2330
3100
  formatNoteSummary,
2331
3101
  getNoteSummary,
3102
+ migrateStorage,
3103
+ normalizeAccountId,
2332
3104
  parseAssetAmount,
3105
+ readNoteAttachment,
2333
3106
  toBech32AccountId,
2334
3107
  useAccount,
2335
3108
  useAccounts,
@@ -2343,13 +3116,17 @@ installAccountBech32();
2343
3116
  useMidenClient,
2344
3117
  useMint,
2345
3118
  useMultiSend,
3119
+ useNoteStream,
2346
3120
  useNotes,
2347
3121
  useSend,
3122
+ useSessionAccount,
2348
3123
  useSigner,
2349
3124
  useSwap,
2350
3125
  useSyncState,
2351
3126
  useTransaction,
2352
3127
  useTransactionHistory,
2353
3128
  useWaitForCommit,
2354
- useWaitForNotes
3129
+ useWaitForNotes,
3130
+ waitForWalletDetection,
3131
+ wrapWasmError
2355
3132
  });