@asseteragmbh/wallet-connector 0.2.4 → 0.2.5

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.cjs CHANGED
@@ -10,6 +10,7 @@ function isSignInHint(value) {
10
10
  return SIGN_IN_HINTS.includes(value);
11
11
  }
12
12
  var MESSAGE_PREFIX = "assetera-wallet:";
13
+ var HOLD_MAX_MS = 3e5;
13
14
  var SUPPORTED_METHODS = [
14
15
  "eth_requestAccounts",
15
16
  "eth_accounts",
@@ -95,6 +96,9 @@ function isRequestMessage(value) {
95
96
  function isDisconnectMessage(value) {
96
97
  return hasType(value, "disconnect");
97
98
  }
99
+ function isHoldMessage(value) {
100
+ return hasType(value, "hold") && typeof value.hold === "boolean";
101
+ }
98
102
  var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
99
103
  function isOnboardedMessage(value) {
100
104
  return hasType(value, "onboarded") && typeof value.address === "string" && EVM_ADDRESS_RE.test(value.address) && typeof value.chain === "string" && // `created` is new; an older wallet sent `status` instead and always created or reused a wallet.
@@ -180,6 +184,9 @@ function createAsseteraWalletProvider(options) {
180
184
  const listeners = /* @__PURE__ */ new Map();
181
185
  let closeTimer = null;
182
186
  let requestsSent = 0;
187
+ let popupReady = false;
188
+ const holds = /* @__PURE__ */ new Set();
189
+ const preparedHolds = /* @__PURE__ */ new Map();
183
190
  function currentChainId() {
184
191
  return chainIdHex ?? toHexChainId(defaultChainId);
185
192
  }
@@ -214,6 +221,34 @@ function createAsseteraWalletProvider(options) {
214
221
  function removeEventListener(event, listener) {
215
222
  listeners.get(event)?.delete(listener);
216
223
  }
224
+ function postHold(hold) {
225
+ const active = popup;
226
+ if (!active || active.closed || !popupReady) return;
227
+ const message = {
228
+ type: `${MESSAGE_PREFIX}hold`,
229
+ v: PROTOCOL_VERSION,
230
+ hold
231
+ };
232
+ active.postMessage(message, walletOrigin);
233
+ }
234
+ function addHold(token) {
235
+ const wasEmpty = holds.size === 0;
236
+ holds.add(token);
237
+ if (wasEmpty) postHold(true);
238
+ }
239
+ function removeHold(token) {
240
+ if (!holds.delete(token)) return false;
241
+ return holds.size === 0;
242
+ }
243
+ function endPreparedHolds(sequence) {
244
+ let emptied = false;
245
+ for (const [token, registeredAt] of preparedHolds) {
246
+ if (registeredAt >= sequence) continue;
247
+ preparedHolds.delete(token);
248
+ if (removeHold(token)) emptied = true;
249
+ }
250
+ if (emptied) postHold(false);
251
+ }
217
252
  function stopClosePolling() {
218
253
  if (closeTimer !== null) {
219
254
  clearInterval(closeTimer);
@@ -227,7 +262,10 @@ function createAsseteraWalletProvider(options) {
227
262
  }, CLOSE_POLL_MS);
228
263
  }
229
264
  function rejectAllPending(error) {
230
- for (const request2 of pending.values()) request2.reject(error);
265
+ for (const request2 of pending.values()) {
266
+ request2.reject(error);
267
+ endPreparedHolds(request2.sequence);
268
+ }
231
269
  pending.clear();
232
270
  }
233
271
  function handlePopupClosed() {
@@ -235,6 +273,7 @@ function createAsseteraWalletProvider(options) {
235
273
  stopClosePolling();
236
274
  const closedPopup = popup;
237
275
  popup = null;
276
+ popupReady = false;
238
277
  const closedReady = ready;
239
278
  ready = createDeferred();
240
279
  const error = disconnectedError();
@@ -257,12 +296,13 @@ function createAsseteraWalletProvider(options) {
257
296
  );
258
297
  if (!opened) return null;
259
298
  popup = opened;
299
+ popupReady = false;
260
300
  ready = createDeferred();
261
301
  walletDisconnected = false;
262
302
  startClosePolling();
263
303
  return opened;
264
304
  }
265
- function sendRequest(method, params) {
305
+ function sendRequest(method, params, sequence) {
266
306
  const active = popup;
267
307
  if (!active || active.closed) return Promise.reject(disconnectedError());
268
308
  const id = crypto.randomUUID();
@@ -274,7 +314,7 @@ function createAsseteraWalletProvider(options) {
274
314
  ...params === void 0 ? {} : { params }
275
315
  };
276
316
  return new Promise((resolve, reject) => {
277
- pending.set(id, { resolve, reject });
317
+ pending.set(id, { resolve, reject, sequence });
278
318
  active.postMessage(message, walletOrigin);
279
319
  });
280
320
  }
@@ -282,6 +322,7 @@ function createAsseteraWalletProvider(options) {
282
322
  const request2 = pending.get(message.id);
283
323
  if (!request2) return;
284
324
  pending.delete(message.id);
325
+ endPreparedHolds(request2.sequence);
285
326
  if ("error" in message) {
286
327
  request2.reject(new ProviderRpcError(message.error.code, message.error.message, message.error.data));
287
328
  } else {
@@ -322,6 +363,8 @@ function createAsseteraWalletProvider(options) {
322
363
  if (popup === null || event.source !== popup) return;
323
364
  const data = event.data;
324
365
  if (isReadyMessage(data)) {
366
+ popupReady = true;
367
+ if (holds.size > 0) postHold(true);
325
368
  ready.resolve(void 0);
326
369
  return;
327
370
  }
@@ -361,9 +404,10 @@ function createAsseteraWalletProvider(options) {
361
404
  if (method === "eth_chainId") return Promise.resolve(currentChainId());
362
405
  if (method === "eth_requestAccounts") {
363
406
  requestsSent += 1;
407
+ const sequence2 = requestsSent;
364
408
  const active2 = openPopup();
365
409
  if (!active2) return Promise.reject(blockedError());
366
- return ready.promise.then(() => sendRequest("eth_requestAccounts", params)).then((result) => {
410
+ return ready.promise.then(() => sendRequest("eth_requestAccounts", params, sequence2)).then((result) => {
367
411
  accounts = Array.isArray(result) ? result : [];
368
412
  emit("accountsChanged", [...accounts]);
369
413
  emit("connect", { chainId: currentChainId() });
@@ -379,10 +423,11 @@ function createAsseteraWalletProvider(options) {
379
423
  );
380
424
  }
381
425
  requestsSent += 1;
426
+ const sequence = requestsSent;
382
427
  const active = openPopup();
383
428
  if (!active) return Promise.reject(blockedError());
384
429
  if (SIGNING_METHODS.has(method)) active.focus();
385
- return ready.promise.then(() => sendRequest(method, params));
430
+ return ready.promise.then(() => sendRequest(method, params, sequence));
386
431
  }
387
432
  function disconnect() {
388
433
  const active = popup;
@@ -396,6 +441,9 @@ function createAsseteraWalletProvider(options) {
396
441
  }
397
442
  stopClosePolling();
398
443
  popup = null;
444
+ popupReady = false;
445
+ holds.clear();
446
+ preparedHolds.clear();
399
447
  const closedReady = ready;
400
448
  ready = createDeferred();
401
449
  closedReady.reject(disconnectedError("Disconnected from the Assetera Wallet."));
@@ -411,16 +459,49 @@ function createAsseteraWalletProvider(options) {
411
459
  if (!active) return { opened: false, release: () => {
412
460
  } };
413
461
  const sentAtPrepare = requestsSent;
462
+ const token = /* @__PURE__ */ Symbol("assetera-wallet-prepare");
463
+ preparedHolds.set(token, sentAtPrepare);
464
+ addHold(token);
414
465
  let released = false;
415
466
  return {
416
467
  opened: true,
417
468
  release() {
418
469
  if (released) return;
419
470
  released = true;
420
- if (existed || popup !== active || active.closed) return;
421
- if (requestsSent !== sentAtPrepare || pending.size > 0) return;
422
- active.close();
423
- handlePopupClosed();
471
+ preparedHolds.delete(token);
472
+ const emptied = removeHold(token);
473
+ const canClose = emptied && !existed && popup === active && !active.closed && requestsSent === sentAtPrepare && pending.size === 0;
474
+ if (canClose) {
475
+ active.close();
476
+ handlePopupClosed();
477
+ return;
478
+ }
479
+ if (emptied) postHold(false);
480
+ }
481
+ };
482
+ }
483
+ function holdPopup() {
484
+ const existed = popup !== null && !popup.closed;
485
+ const active = typeof window === "undefined" ? null : openPopup();
486
+ if (!active) return { opened: false, release: () => {
487
+ } };
488
+ const token = /* @__PURE__ */ Symbol("assetera-wallet-hold");
489
+ const sentAtHold = requestsSent;
490
+ addHold(token);
491
+ let released = false;
492
+ return {
493
+ opened: true,
494
+ release() {
495
+ if (released) return;
496
+ released = true;
497
+ const emptied = removeHold(token);
498
+ const canClose = emptied && !existed && popup === active && !active.closed && requestsSent === sentAtHold && pending.size === 0;
499
+ if (canClose) {
500
+ active.close();
501
+ handlePopupClosed();
502
+ return;
503
+ }
504
+ if (emptied) postHold(false);
424
505
  }
425
506
  };
426
507
  }
@@ -443,7 +524,8 @@ function createAsseteraWalletProvider(options) {
443
524
  disconnect,
444
525
  lastSecurityStatus,
445
526
  lastAccountNames,
446
- prepareSigning
527
+ prepareSigning,
528
+ holdPopup
447
529
  };
448
530
  }
449
531
 
@@ -896,6 +978,7 @@ function openAsseteraWalletManager(options) {
896
978
  }
897
979
 
898
980
  exports.CONNECT_PATH = CONNECT_PATH;
981
+ exports.HOLD_MAX_MS = HOLD_MAX_MS;
899
982
  exports.MANAGE_PATH = MANAGE_PATH;
900
983
  exports.MESSAGE_PREFIX = MESSAGE_PREFIX;
901
984
  exports.ManagerError = ManagerError;
@@ -912,6 +995,7 @@ exports.isAccountsMessage = isAccountsMessage;
912
995
  exports.isCaip2EvmChain = isCaip2EvmChain;
913
996
  exports.isDisconnectMessage = isDisconnectMessage;
914
997
  exports.isEventMessage = isEventMessage;
998
+ exports.isHoldMessage = isHoldMessage;
915
999
  exports.isOnboardCancelledMessage = isOnboardCancelledMessage;
916
1000
  exports.isOnboardedMessage = isOnboardedMessage;
917
1001
  exports.isReadyMessage = isReadyMessage;