@lydianpay/lydianconnect 1.4.0 → 1.5.0

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.d.cts CHANGED
@@ -46,6 +46,13 @@ interface Connection {
46
46
  readonly account: string;
47
47
  /** CAIP-2 chain id, e.g. "eip155:1". */
48
48
  readonly chainId: string;
49
+ /**
50
+ * The CAIP-2 chains the wallet's session granted, across all namespaces.
51
+ * WalletConnect only — SDK and injected connections leave it undefined, since
52
+ * switching (`wallet_switchEthereumChain`) has no approval concept and any
53
+ * chain in the provider's family is reachable anyway.
54
+ */
55
+ readonly approvedChains?: readonly string[];
49
56
  request<T = unknown>(args: {
50
57
  method: string;
51
58
  params?: unknown;
@@ -67,13 +74,28 @@ interface LydianConnectConfig extends AppConfig {
67
74
  /** WalletConnect Cloud project id — powers the fallback. */
68
75
  walletConnectProjectId: string;
69
76
  }
70
- interface ConnectInput {
77
+ /**
78
+ * Input to {@link LydianConnect.connect} — one of two operations:
79
+ *
80
+ * - `chainId` **pins**: requests target that chain and EVM wallets switch onto it.
81
+ * - `chains` **discovers**: propose several chains, the wallet approves a subset
82
+ * (see {@link Connection.approvedChains}), nothing is pinned. Connect again
83
+ * with `chainId` once the user picks one — a WalletConnect session that
84
+ * approved it is reused without a second prompt.
85
+ */
86
+ type ConnectInput = {
71
87
  walletId: string;
72
88
  /** Chain to connect on — a number (EVM, e.g. 137) or a CAIP-2 id ('eip155:137'). */
73
89
  chainId: number | string;
74
90
  /** Cancel a pending connection. */
75
91
  signal?: AbortSignal;
76
- }
92
+ } | {
93
+ walletId: string;
94
+ /** Chains to discover across — same formats as `chainId`; must be non-empty. */
95
+ chains: readonly (number | string)[];
96
+ /** Cancel a pending connection. */
97
+ signal?: AbortSignal;
98
+ };
77
99
  type LydianConnectEvent =
78
100
  /**
79
101
  * WalletConnect only — the wc: URI.
package/dist/index.d.ts CHANGED
@@ -46,6 +46,13 @@ interface Connection {
46
46
  readonly account: string;
47
47
  /** CAIP-2 chain id, e.g. "eip155:1". */
48
48
  readonly chainId: string;
49
+ /**
50
+ * The CAIP-2 chains the wallet's session granted, across all namespaces.
51
+ * WalletConnect only — SDK and injected connections leave it undefined, since
52
+ * switching (`wallet_switchEthereumChain`) has no approval concept and any
53
+ * chain in the provider's family is reachable anyway.
54
+ */
55
+ readonly approvedChains?: readonly string[];
49
56
  request<T = unknown>(args: {
50
57
  method: string;
51
58
  params?: unknown;
@@ -67,13 +74,28 @@ interface LydianConnectConfig extends AppConfig {
67
74
  /** WalletConnect Cloud project id — powers the fallback. */
68
75
  walletConnectProjectId: string;
69
76
  }
70
- interface ConnectInput {
77
+ /**
78
+ * Input to {@link LydianConnect.connect} — one of two operations:
79
+ *
80
+ * - `chainId` **pins**: requests target that chain and EVM wallets switch onto it.
81
+ * - `chains` **discovers**: propose several chains, the wallet approves a subset
82
+ * (see {@link Connection.approvedChains}), nothing is pinned. Connect again
83
+ * with `chainId` once the user picks one — a WalletConnect session that
84
+ * approved it is reused without a second prompt.
85
+ */
86
+ type ConnectInput = {
71
87
  walletId: string;
72
88
  /** Chain to connect on — a number (EVM, e.g. 137) or a CAIP-2 id ('eip155:137'). */
73
89
  chainId: number | string;
74
90
  /** Cancel a pending connection. */
75
91
  signal?: AbortSignal;
76
- }
92
+ } | {
93
+ walletId: string;
94
+ /** Chains to discover across — same formats as `chainId`; must be non-empty. */
95
+ chains: readonly (number | string)[];
96
+ /** Cancel a pending connection. */
97
+ signal?: AbortSignal;
98
+ };
77
99
  type LydianConnectEvent =
78
100
  /**
79
101
  * WalletConnect only — the wc: URI.
package/dist/index.js CHANGED
@@ -150,6 +150,20 @@ function buildNamespace(chainId) {
150
150
  }
151
151
  };
152
152
  }
153
+ function buildNamespaces(chains) {
154
+ const byName = /* @__PURE__ */ new Map();
155
+ chains.forEach((chain) => {
156
+ const single = buildNamespace(chain);
157
+ const caip = single.value.chains?.[0];
158
+ const merged = byName.get(single.name);
159
+ if (!merged) {
160
+ byName.set(single.name, single);
161
+ } else if (caip && !merged.value.chains?.includes(caip)) {
162
+ merged.value.chains = [...merged.value.chains ?? [], caip];
163
+ }
164
+ });
165
+ return [...byName.values()];
166
+ }
153
167
 
154
168
  // node_modules/@lydianpay/lydianconnect-catalog/dist/index.js
155
169
  var ICON_BASE = "https://wallet-assets.lydian.com/wallets";
@@ -247,7 +261,7 @@ var WALLET_CATALOG = WALLETS.map((w) => ({
247
261
 
248
262
  // src/core/connector.ts
249
263
  function requestedChain(req) {
250
- return req.namespace.value.chains?.[0];
264
+ return req.pinned;
251
265
  }
252
266
  var BaseConnector = class {
253
267
  constructor() {
@@ -607,9 +621,8 @@ function rpcFor2(provider) {
607
621
  return ({ method, params }) => rpc(provider, method, params);
608
622
  }
609
623
  function evmChainIds(req) {
610
- const wanted = req.namespace.value.chains?.[0];
611
- const n = wanted ? Number(wanted.split(":")[1]) : NaN;
612
- return Number.isFinite(n) && n > 0 ? [n] : void 0;
624
+ const ids = (req.namespace.value.chains ?? []).map((chain) => Number(chain.split(":")[1])).filter((n) => Number.isFinite(n) && n > 0);
625
+ return ids.length > 0 ? ids : void 0;
613
626
  }
614
627
 
615
628
  // src/connectors/injected/connector.ts
@@ -1303,8 +1316,11 @@ var WalletConnectConnector = class extends BaseConnector {
1303
1316
  const client = await this.getClient();
1304
1317
  const reused = await this.tryReuse(client, req);
1305
1318
  if (reused) return reused;
1319
+ const proposed = [req.namespace, ...req.extraNamespaces ?? []];
1306
1320
  const { uri, approval } = await client.connect({
1307
- requiredNamespaces: { [req.namespace.name]: req.namespace.value }
1321
+ optionalNamespaces: Object.fromEntries(
1322
+ proposed.map((ns) => [ns.name, ns.value])
1323
+ )
1308
1324
  });
1309
1325
  if (!uri) throw new Error("WalletConnect did not return a pairing URI");
1310
1326
  const link = isMobile() ? this.links[req.walletId] : void 0;
@@ -1336,7 +1352,8 @@ var WalletConnectConnector = class extends BaseConnector {
1336
1352
  client,
1337
1353
  req.walletId,
1338
1354
  session,
1339
- req.namespace
1355
+ req.namespace,
1356
+ req.pinned
1340
1357
  );
1341
1358
  this.topics.set(req.walletId, session.topic);
1342
1359
  this.persist();
@@ -1403,21 +1420,32 @@ var WalletConnectConnector = class extends BaseConnector {
1403
1420
  return null;
1404
1421
  }
1405
1422
  const ns = session.namespaces[req.namespace.name];
1406
- const wanted = req.namespace.value.chains?.[0];
1407
- if (!ns || wanted && !ns.chains?.includes(wanted)) return null;
1408
- return this.toConnection(client, req.walletId, session, req.namespace);
1423
+ if (!ns) return null;
1424
+ if (req.pinned && !grantedChains(ns).includes(req.pinned)) return null;
1425
+ return this.toConnection(
1426
+ client,
1427
+ req.walletId,
1428
+ session,
1429
+ req.namespace,
1430
+ req.pinned
1431
+ );
1409
1432
  }
1410
- toConnection(client, walletId, session, namespace) {
1433
+ toConnection(client, walletId, session, namespace, wanted) {
1411
1434
  const ns = session.namespaces[namespace.name];
1412
1435
  const account = (ns?.accounts ?? []).map((a) => a.split(":")[2]).find((a) => !!a) ?? "";
1413
- const approved = ns?.chains?.length ? ns.chains : (ns?.accounts ?? []).map((a) => a.split(":").slice(0, 2).join(":"));
1414
- const wanted = namespace.value.chains?.[0];
1436
+ const approved = grantedChains(ns);
1415
1437
  const chainId = wanted && approved.includes(wanted) ? wanted : approved[0] ?? `${namespace.name}:1`;
1438
+ const approvedChains = [
1439
+ ...new Set(
1440
+ Object.values(session.namespaces).flatMap((n) => grantedChains(n))
1441
+ )
1442
+ ];
1416
1443
  const topic = session.topic;
1417
1444
  return {
1418
1445
  walletId,
1419
1446
  account,
1420
1447
  chainId,
1448
+ approvedChains,
1421
1449
  request: (args) => client.request({
1422
1450
  topic,
1423
1451
  chainId,
@@ -1478,6 +1506,11 @@ var WalletConnectConnector = class extends BaseConnector {
1478
1506
  }
1479
1507
  }
1480
1508
  };
1509
+ function grantedChains(ns) {
1510
+ if (!ns) return [];
1511
+ if (ns.chains?.length) return ns.chains;
1512
+ return (ns.accounts ?? []).map((a) => a.split(":").slice(0, 2).join(":"));
1513
+ }
1481
1514
  function firstNamespace(session) {
1482
1515
  const name = Object.keys(session.namespaces)[0];
1483
1516
  if (!name) return null;
@@ -1522,14 +1555,35 @@ var LydianConnect = class {
1522
1555
  return this.manager.init();
1523
1556
  }
1524
1557
  async connect(input) {
1525
- if (input.chainId === void 0 || input.chainId === null) {
1558
+ const chains = "chains" in input ? input.chains : void 0;
1559
+ const chainId = "chainId" in input ? input.chainId : void 0;
1560
+ if (chains !== void 0 && chainId !== void 0) {
1561
+ throw new Error(
1562
+ "connect() takes either chainId (pinned) or chains (discovery), not both"
1563
+ );
1564
+ }
1565
+ if (chains !== void 0) {
1566
+ const [primary, ...extra] = buildNamespaces(chains);
1567
+ if (!primary) {
1568
+ throw new Error("connect() discovery requires a non-empty chains list");
1569
+ }
1570
+ return this.manager.connect({
1571
+ walletId: input.walletId,
1572
+ namespace: primary,
1573
+ extraNamespaces: extra.length > 0 ? extra : void 0,
1574
+ signal: input.signal
1575
+ });
1576
+ }
1577
+ if (chainId === void 0 || chainId === null) {
1526
1578
  throw new Error(
1527
- 'connect() requires a chainId (a number like 137 or an "eip155:<id>" string)'
1579
+ 'connect() requires a chainId (a number like 137 or an "eip155:<id>" string) or a chains list'
1528
1580
  );
1529
1581
  }
1582
+ const namespace = buildNamespace(chainId);
1530
1583
  return this.manager.connect({
1531
1584
  walletId: input.walletId,
1532
- namespace: buildNamespace(input.chainId),
1585
+ namespace,
1586
+ pinned: namespace.value.chains?.[0],
1533
1587
  signal: input.signal
1534
1588
  });
1535
1589
  }