@asseteragmbh/wallet-connector 0.2.4 → 0.2.6

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.
@@ -106,11 +110,12 @@ function isOnboardCancelledMessage(value) {
106
110
  function isCaip2EvmChain(value) {
107
111
  return /^eip155:\d{1,32}$/.test(value);
108
112
  }
109
- function connectUrl(walletUrl, partnerOrigin, signIn) {
113
+ function connectUrl(walletUrl, partnerOrigin, signIn, chainId) {
110
114
  const url = new URL(CONNECT_PATH, walletUrl);
111
115
  url.searchParams.set("origin", partnerOrigin);
112
116
  url.searchParams.set("v", String(PROTOCOL_VERSION));
113
117
  if (signIn !== void 0) url.searchParams.set("signIn", signIn);
118
+ if (chainId !== void 0) url.searchParams.set("chainId", chainId);
114
119
  return url.toString();
115
120
  }
116
121
  function onboardUrl(walletUrl, partnerOrigin, options) {
@@ -180,6 +185,9 @@ function createAsseteraWalletProvider(options) {
180
185
  const listeners = /* @__PURE__ */ new Map();
181
186
  let closeTimer = null;
182
187
  let requestsSent = 0;
188
+ let popupReady = false;
189
+ const holds = /* @__PURE__ */ new Set();
190
+ const preparedHolds = /* @__PURE__ */ new Map();
183
191
  function currentChainId() {
184
192
  return chainIdHex ?? toHexChainId(defaultChainId);
185
193
  }
@@ -214,6 +222,34 @@ function createAsseteraWalletProvider(options) {
214
222
  function removeEventListener(event, listener) {
215
223
  listeners.get(event)?.delete(listener);
216
224
  }
225
+ function postHold(hold) {
226
+ const active = popup;
227
+ if (!active || active.closed || !popupReady) return;
228
+ const message = {
229
+ type: `${MESSAGE_PREFIX}hold`,
230
+ v: PROTOCOL_VERSION,
231
+ hold
232
+ };
233
+ active.postMessage(message, walletOrigin);
234
+ }
235
+ function addHold(token) {
236
+ const wasEmpty = holds.size === 0;
237
+ holds.add(token);
238
+ if (wasEmpty) postHold(true);
239
+ }
240
+ function removeHold(token) {
241
+ if (!holds.delete(token)) return false;
242
+ return holds.size === 0;
243
+ }
244
+ function endPreparedHolds(sequence) {
245
+ let emptied = false;
246
+ for (const [token, registeredAt] of preparedHolds) {
247
+ if (registeredAt >= sequence) continue;
248
+ preparedHolds.delete(token);
249
+ if (removeHold(token)) emptied = true;
250
+ }
251
+ if (emptied) postHold(false);
252
+ }
217
253
  function stopClosePolling() {
218
254
  if (closeTimer !== null) {
219
255
  clearInterval(closeTimer);
@@ -227,7 +263,10 @@ function createAsseteraWalletProvider(options) {
227
263
  }, CLOSE_POLL_MS);
228
264
  }
229
265
  function rejectAllPending(error) {
230
- for (const request2 of pending.values()) request2.reject(error);
266
+ for (const request2 of pending.values()) {
267
+ request2.reject(error);
268
+ endPreparedHolds(request2.sequence);
269
+ }
231
270
  pending.clear();
232
271
  }
233
272
  function handlePopupClosed() {
@@ -235,6 +274,7 @@ function createAsseteraWalletProvider(options) {
235
274
  stopClosePolling();
236
275
  const closedPopup = popup;
237
276
  popup = null;
277
+ popupReady = false;
238
278
  const closedReady = ready;
239
279
  ready = createDeferred();
240
280
  const error = disconnectedError();
@@ -251,18 +291,19 @@ function createAsseteraWalletProvider(options) {
251
291
  }
252
292
  if (typeof window === "undefined") return null;
253
293
  const opened = window.open(
254
- connectUrl(options.walletUrl, window.location.origin, options.signIn),
294
+ connectUrl(options.walletUrl, window.location.origin, options.signIn, currentChainId()),
255
295
  POPUP_NAME,
256
296
  popupFeatures
257
297
  );
258
298
  if (!opened) return null;
259
299
  popup = opened;
300
+ popupReady = false;
260
301
  ready = createDeferred();
261
302
  walletDisconnected = false;
262
303
  startClosePolling();
263
304
  return opened;
264
305
  }
265
- function sendRequest(method, params) {
306
+ function sendRequest(method, params, sequence) {
266
307
  const active = popup;
267
308
  if (!active || active.closed) return Promise.reject(disconnectedError());
268
309
  const id = crypto.randomUUID();
@@ -274,7 +315,7 @@ function createAsseteraWalletProvider(options) {
274
315
  ...params === void 0 ? {} : { params }
275
316
  };
276
317
  return new Promise((resolve, reject) => {
277
- pending.set(id, { resolve, reject });
318
+ pending.set(id, { resolve, reject, sequence });
278
319
  active.postMessage(message, walletOrigin);
279
320
  });
280
321
  }
@@ -282,6 +323,7 @@ function createAsseteraWalletProvider(options) {
282
323
  const request2 = pending.get(message.id);
283
324
  if (!request2) return;
284
325
  pending.delete(message.id);
326
+ endPreparedHolds(request2.sequence);
285
327
  if ("error" in message) {
286
328
  request2.reject(new ProviderRpcError(message.error.code, message.error.message, message.error.data));
287
329
  } else {
@@ -322,6 +364,8 @@ function createAsseteraWalletProvider(options) {
322
364
  if (popup === null || event.source !== popup) return;
323
365
  const data = event.data;
324
366
  if (isReadyMessage(data)) {
367
+ popupReady = true;
368
+ if (holds.size > 0) postHold(true);
325
369
  ready.resolve(void 0);
326
370
  return;
327
371
  }
@@ -361,9 +405,10 @@ function createAsseteraWalletProvider(options) {
361
405
  if (method === "eth_chainId") return Promise.resolve(currentChainId());
362
406
  if (method === "eth_requestAccounts") {
363
407
  requestsSent += 1;
408
+ const sequence2 = requestsSent;
364
409
  const active2 = openPopup();
365
410
  if (!active2) return Promise.reject(blockedError());
366
- return ready.promise.then(() => sendRequest("eth_requestAccounts", params)).then((result) => {
411
+ return ready.promise.then(() => sendRequest("eth_requestAccounts", params, sequence2)).then((result) => {
367
412
  accounts = Array.isArray(result) ? result : [];
368
413
  emit("accountsChanged", [...accounts]);
369
414
  emit("connect", { chainId: currentChainId() });
@@ -379,10 +424,11 @@ function createAsseteraWalletProvider(options) {
379
424
  );
380
425
  }
381
426
  requestsSent += 1;
427
+ const sequence = requestsSent;
382
428
  const active = openPopup();
383
429
  if (!active) return Promise.reject(blockedError());
384
430
  if (SIGNING_METHODS.has(method)) active.focus();
385
- return ready.promise.then(() => sendRequest(method, params));
431
+ return ready.promise.then(() => sendRequest(method, params, sequence));
386
432
  }
387
433
  function disconnect() {
388
434
  const active = popup;
@@ -396,6 +442,9 @@ function createAsseteraWalletProvider(options) {
396
442
  }
397
443
  stopClosePolling();
398
444
  popup = null;
445
+ popupReady = false;
446
+ holds.clear();
447
+ preparedHolds.clear();
399
448
  const closedReady = ready;
400
449
  ready = createDeferred();
401
450
  closedReady.reject(disconnectedError("Disconnected from the Assetera Wallet."));
@@ -411,16 +460,49 @@ function createAsseteraWalletProvider(options) {
411
460
  if (!active) return { opened: false, release: () => {
412
461
  } };
413
462
  const sentAtPrepare = requestsSent;
463
+ const token = /* @__PURE__ */ Symbol("assetera-wallet-prepare");
464
+ preparedHolds.set(token, sentAtPrepare);
465
+ addHold(token);
414
466
  let released = false;
415
467
  return {
416
468
  opened: true,
417
469
  release() {
418
470
  if (released) return;
419
471
  released = true;
420
- if (existed || popup !== active || active.closed) return;
421
- if (requestsSent !== sentAtPrepare || pending.size > 0) return;
422
- active.close();
423
- handlePopupClosed();
472
+ preparedHolds.delete(token);
473
+ const emptied = removeHold(token);
474
+ const canClose = emptied && !existed && popup === active && !active.closed && requestsSent === sentAtPrepare && pending.size === 0;
475
+ if (canClose) {
476
+ active.close();
477
+ handlePopupClosed();
478
+ return;
479
+ }
480
+ if (emptied) postHold(false);
481
+ }
482
+ };
483
+ }
484
+ function holdPopup() {
485
+ const existed = popup !== null && !popup.closed;
486
+ const active = typeof window === "undefined" ? null : openPopup();
487
+ if (!active) return { opened: false, release: () => {
488
+ } };
489
+ const token = /* @__PURE__ */ Symbol("assetera-wallet-hold");
490
+ const sentAtHold = requestsSent;
491
+ addHold(token);
492
+ let released = false;
493
+ return {
494
+ opened: true,
495
+ release() {
496
+ if (released) return;
497
+ released = true;
498
+ const emptied = removeHold(token);
499
+ const canClose = emptied && !existed && popup === active && !active.closed && requestsSent === sentAtHold && pending.size === 0;
500
+ if (canClose) {
501
+ active.close();
502
+ handlePopupClosed();
503
+ return;
504
+ }
505
+ if (emptied) postHold(false);
424
506
  }
425
507
  };
426
508
  }
@@ -443,7 +525,8 @@ function createAsseteraWalletProvider(options) {
443
525
  disconnect,
444
526
  lastSecurityStatus,
445
527
  lastAccountNames,
446
- prepareSigning
528
+ prepareSigning,
529
+ holdPopup
447
530
  };
448
531
  }
449
532
 
@@ -896,6 +979,7 @@ function openAsseteraWalletManager(options) {
896
979
  }
897
980
 
898
981
  exports.CONNECT_PATH = CONNECT_PATH;
982
+ exports.HOLD_MAX_MS = HOLD_MAX_MS;
899
983
  exports.MANAGE_PATH = MANAGE_PATH;
900
984
  exports.MESSAGE_PREFIX = MESSAGE_PREFIX;
901
985
  exports.ManagerError = ManagerError;
@@ -912,6 +996,7 @@ exports.isAccountsMessage = isAccountsMessage;
912
996
  exports.isCaip2EvmChain = isCaip2EvmChain;
913
997
  exports.isDisconnectMessage = isDisconnectMessage;
914
998
  exports.isEventMessage = isEventMessage;
999
+ exports.isHoldMessage = isHoldMessage;
915
1000
  exports.isOnboardCancelledMessage = isOnboardCancelledMessage;
916
1001
  exports.isOnboardedMessage = isOnboardedMessage;
917
1002
  exports.isReadyMessage = isReadyMessage;