@naculus/connect-appkit-core 0.9.0 → 0.10.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.cjs CHANGED
@@ -44,6 +44,7 @@ __export(src_exports, {
44
44
  createNotification: () => createNotification,
45
45
  createNotificationSettingsStorage: () => createNotificationSettingsStorage,
46
46
  createSolanaSessionKeyFlow: () => createSolanaSessionKeyFlow,
47
+ createX402WalletSigner: () => createX402WalletSigner,
47
48
  decodeRevertReason: () => decodeRevertReason,
48
49
  defaultSiwxDomain: () => defaultSiwxDomain,
49
50
  defaultSiwxUri: () => defaultSiwxUri,
@@ -56,6 +57,7 @@ __export(src_exports, {
56
57
  encodeErc20TransferFrom: () => encodeErc20TransferFrom,
57
58
  explainSpend: () => explainSpend,
58
59
  fetchUserOperationReceipt: () => fetchUserOperationReceipt,
60
+ findX402Provider: () => findX402Provider,
59
61
  formatAuthorizationAmount: () => formatAuthorizationAmount,
60
62
  getResolver: () => getResolver,
61
63
  getSharedSessionKeyManager: () => getSharedSessionKeyManager,
@@ -86,6 +88,7 @@ __export(src_exports, {
86
88
  resolveRevertReason: () => resolveRevertReason,
87
89
  resolveSimulationEndpoint: () => resolveSimulationEndpoint,
88
90
  resolveUserOpChain: () => resolveUserOpChain,
91
+ resolveX402Wallet: () => resolveX402Wallet,
89
92
  sameExecutionIntent: () => sameExecutionIntent,
90
93
  saveNotificationSettings: () => saveNotificationSettings,
91
94
  selectChainCapabilities: () => selectChainCapabilities,
@@ -1381,39 +1384,44 @@ function createDelegationPolicyFlow(deps) {
1381
1384
 
1382
1385
  // src/authorization.ts
1383
1386
  var import_connect_core17 = require("@naculus/connect-core");
1384
- function assetAddress(asset) {
1385
- return asset.split(/[:/]/).at(-1);
1386
- }
1387
1387
  function groupDigits(value) {
1388
1388
  let out = "";
1389
1389
  for (let i = 0; i < value.length; i++)
1390
1390
  out += (i && (value.length - i) % 3 === 0 ? "," : "") + value[i];
1391
1391
  return out;
1392
1392
  }
1393
- function trimTrailingZeros(value) {
1394
- let end = value.length;
1395
- while (value[end - 1] === "0") end--;
1396
- return value.slice(0, end);
1393
+ function trustedMetadata(asset, options) {
1394
+ const trust = !options.trustedAssets ? "unchecked" : options.trustedAssets.some(
1395
+ (t) => canonicalAssetId(t) === canonicalAssetId(asset)
1396
+ ) ? "trusted" : "unverified";
1397
+ return [trust, trust === "unverified" ? void 0 : options.assets?.[asset]];
1398
+ }
1399
+ function canonicalAssetId(asset) {
1400
+ return asset.replace(
1401
+ /^(eip155:[^/]+\/erc20:)(.+)$/,
1402
+ (_, prefix, reference) => prefix + reference.toLowerCase()
1403
+ );
1397
1404
  }
1398
1405
  function formatAuthorizationAmount(amount, metadata) {
1399
1406
  const baseUnits = amount.toString();
1400
- if (!metadata || !metadata.symbol || !Number.isSafeInteger(metadata.decimals) || metadata.decimals < 0 || metadata.decimals > 255) {
1407
+ if (!metadata?.symbol || !Number.isSafeInteger(metadata.decimals) || metadata.decimals < 0 || metadata.decimals > 255) {
1401
1408
  return {
1402
1409
  formatted: `${groupDigits(baseUnits)} base units`
1403
1410
  };
1404
1411
  }
1405
1412
  const decimals = metadata.decimals;
1406
1413
  const padded = baseUnits.padStart(decimals + 1, "0");
1407
- const integer = decimals === 0 ? padded : padded.slice(0, -decimals);
1408
- const fraction = decimals === 0 ? "" : trimTrailingZeros(padded.slice(-decimals));
1409
- const value = `${groupDigits(integer)}${fraction ? `.${fraction}` : ""}`;
1410
- return { formatted: `${value} ${metadata.symbol}` };
1414
+ const integer = padded.slice(0, decimals ? -decimals : void 0);
1415
+ let fraction = decimals ? padded.slice(-decimals) : "";
1416
+ while (fraction.endsWith("0")) fraction = fraction.slice(0, -1);
1417
+ return {
1418
+ formatted: `${groupDigits(integer)}${fraction ? `.${fraction}` : ""} ${metadata.symbol}`
1419
+ };
1411
1420
  }
1412
1421
  function relativeExpiry(expiresAt, now, locale) {
1413
1422
  const seconds = expiresAt - now;
1414
1423
  const absolute = Math.abs(seconds);
1415
- const divisor = absolute >= 31536e3 ? 31536e3 : absolute >= 2592e3 ? 2592e3 : absolute >= 86400 ? 86400 : absolute >= 3600 ? 3600 : absolute >= 60 ? 60 : 1;
1416
- const unit = divisor === 31536e3 ? "year" : divisor === 2592e3 ? "month" : divisor === 86400 ? "day" : divisor === 3600 ? "hour" : divisor === 60 ? "minute" : "second";
1424
+ const [divisor, unit] = absolute >= 31536e3 ? [31536e3, "year"] : absolute >= 2592e3 ? [2592e3, "month"] : absolute >= 86400 ? [86400, "day"] : absolute >= 3600 ? [3600, "hour"] : absolute >= 60 ? [60, "minute"] : [1, "second"];
1417
1425
  const value = Math.round(seconds / divisor);
1418
1426
  if (typeof Intl.RelativeTimeFormat !== "function") {
1419
1427
  const count = Math.abs(value);
@@ -1431,10 +1439,11 @@ function describeAuthorization(input, options = {}) {
1431
1439
  label,
1432
1440
  principal: input.principal ?? null,
1433
1441
  grants: input.grants.map((grant) => {
1434
- const metadata = options.assets?.[grant.asset];
1442
+ const [assetTrust, metadata] = trustedMetadata(grant.asset, options);
1435
1443
  return {
1436
1444
  asset: grant.asset,
1437
- assetLabel: metadata?.symbol || assetAddress(grant.asset),
1445
+ assetTrust,
1446
+ assetLabel: metadata?.symbol || grant.asset.split(":").at(-1),
1438
1447
  recipients: grant.recipients.map((full) => ({
1439
1448
  shortened: full.length <= 14 ? full : `${full.slice(0, 6)}\u2026${full.slice(-6)}`,
1440
1449
  full
@@ -1487,7 +1496,7 @@ function explainSpend(authorization, request, options = {}) {
1487
1496
  const remainingTotal = authorization.grants[verdict.grant].maxTotal - request.spentSoFar - request.amount;
1488
1497
  const remainingTotalFormatted = formatAuthorizationAmount(
1489
1498
  remainingTotal,
1490
- options.assets?.[authorization.grants[verdict.grant].asset]
1499
+ trustedMetadata(authorization.grants[verdict.grant].asset, options)[1]
1491
1500
  );
1492
1501
  return {
1493
1502
  allowed: true,
@@ -1569,6 +1578,57 @@ function describePayment(input, result) {
1569
1578
  };
1570
1579
  }
1571
1580
 
1581
+ // src/x402-wallet.ts
1582
+ var import_connect_core18 = require("@naculus/connect-core");
1583
+ var import_payments_x402 = require("@naculus/payments-x402");
1584
+ function findX402Provider(session, sources) {
1585
+ if (!session) return null;
1586
+ if (session.walletType === "eip6963" || session.id.startsWith("eip6963-")) {
1587
+ return sources.injected?.find((wallet) => wallet.id === session.walletId)?.provider ?? null;
1588
+ }
1589
+ if (session.walletType === "walletconnect") {
1590
+ return sources.walletConnect ?? null;
1591
+ }
1592
+ return null;
1593
+ }
1594
+ function unavailable(reason) {
1595
+ return { provider: null, address: null, reason };
1596
+ }
1597
+ function resolveX402Wallet(session, provider) {
1598
+ if (!session) return unavailable("no-session");
1599
+ const namespace = session.namespaces.eip155;
1600
+ if (!namespace) return unavailable("not-evm");
1601
+ const isInjected = session.walletType === "eip6963" || session.id.startsWith("eip6963-");
1602
+ const isWalletConnect = session.walletType === "walletconnect";
1603
+ if (!isInjected && !isWalletConnect || !provider?.request) {
1604
+ return unavailable("unsupported-wallet-type");
1605
+ }
1606
+ for (const account of namespace.accounts) {
1607
+ const parsed = (0, import_connect_core18.parseCaip10)(account);
1608
+ const address = parsed?.namespace === "eip155" ? parsed.address : account;
1609
+ if ((0, import_connect_core18.isEvmAddress)(address)) {
1610
+ return {
1611
+ provider,
1612
+ address,
1613
+ reason: null
1614
+ };
1615
+ }
1616
+ }
1617
+ return unavailable("not-evm");
1618
+ }
1619
+ function createX402WalletSigner(session, provider, switchChain) {
1620
+ const resolved = resolveX402Wallet(session, provider);
1621
+ if (resolved.reason) return { signer: null, reason: resolved.reason };
1622
+ return {
1623
+ signer: (0, import_payments_x402.walletX402Signer)({
1624
+ provider: resolved.provider,
1625
+ address: resolved.address,
1626
+ switchChain
1627
+ }),
1628
+ reason: null
1629
+ };
1630
+ }
1631
+
1572
1632
  // src/mpp-session.ts
1573
1633
  function record2(value) {
1574
1634
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
@@ -1600,11 +1660,11 @@ function readMppRecoveryChannelId(error) {
1600
1660
  }
1601
1661
 
1602
1662
  // src/solana-session-key.ts
1603
- var import_connect_core18 = require("@naculus/connect-core");
1663
+ var import_connect_core19 = require("@naculus/connect-core");
1604
1664
  function send(rpc) {
1605
1665
  const sendTransaction = rpc.sendTransaction;
1606
1666
  if (!sendTransaction) {
1607
- throw new import_connect_core18.WalletError(
1667
+ throw new import_connect_core19.WalletError(
1608
1668
  "invalid_input",
1609
1669
  "The Solana RPC must implement sendTransaction to approve or revoke."
1610
1670
  );
@@ -1642,7 +1702,7 @@ function createSolanaSessionKeyFlow(deps) {
1642
1702
  } catch (cause) {
1643
1703
  await manager.revoke(draft.id).catch(() => {
1644
1704
  });
1645
- throw new import_connect_core18.WalletError(
1705
+ throw new import_connect_core19.WalletError(
1646
1706
  "rpc_error",
1647
1707
  `The approval could not be confirmed as sent (${cause instanceof Error ? cause.message : String(cause)}); the key is revoked here. Call revoke("${draft.id}") to send the on-chain Revoke in case it landed.`
1648
1708
  );
@@ -1653,7 +1713,7 @@ function createSolanaSessionKeyFlow(deps) {
1653
1713
  async revoke(id) {
1654
1714
  const key = (await list()).find((k) => k.id === id);
1655
1715
  if (!key) {
1656
- throw new import_connect_core18.WalletError(
1716
+ throw new import_connect_core19.WalletError(
1657
1717
  "invalid_input",
1658
1718
  `No Solana session key ${id} for this owner.`
1659
1719
  );
@@ -1665,7 +1725,7 @@ function createSolanaSessionKeyFlow(deps) {
1665
1725
  rpc
1666
1726
  );
1667
1727
  const signed = await owner.signTransaction(transaction);
1668
- const revocation = (0, import_connect_core18.verifySignedOwnerTransaction)(signed, {
1728
+ const revocation = (0, import_connect_core19.verifySignedOwnerTransaction)(signed, {
1669
1729
  kind: "revoke",
1670
1730
  revocation: {
1671
1731
  owner: key.owner,
@@ -1680,7 +1740,7 @@ function createSolanaSessionKeyFlow(deps) {
1680
1740
  }
1681
1741
 
1682
1742
  // src/web3-store.ts
1683
- var import_connect_core19 = require("@naculus/connect-core");
1743
+ var import_connect_core20 = require("@naculus/connect-core");
1684
1744
  function withTimeout(promise, ms, label = "Operation") {
1685
1745
  let timeoutId;
1686
1746
  const timeout = new Promise((_, reject) => {
@@ -1702,7 +1762,7 @@ async function withRetry(fn, options) {
1702
1762
  lastError = error;
1703
1763
  if (attempt < options.maxRetries) {
1704
1764
  const delay = options.baseDelay * 2 ** attempt;
1705
- import_connect_core19.logger.warn(
1765
+ import_connect_core20.logger.warn(
1706
1766
  "appkit/core",
1707
1767
  `Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`
1708
1768
  );
@@ -1840,6 +1900,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
1840
1900
  createNotification,
1841
1901
  createNotificationSettingsStorage,
1842
1902
  createSolanaSessionKeyFlow,
1903
+ createX402WalletSigner,
1843
1904
  decodeRevertReason,
1844
1905
  defaultSiwxDomain,
1845
1906
  defaultSiwxUri,
@@ -1852,6 +1913,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
1852
1913
  encodeErc20TransferFrom,
1853
1914
  explainSpend,
1854
1915
  fetchUserOperationReceipt,
1916
+ findX402Provider,
1855
1917
  formatAuthorizationAmount,
1856
1918
  getResolver,
1857
1919
  getSharedSessionKeyManager,
@@ -1882,6 +1944,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
1882
1944
  resolveRevertReason,
1883
1945
  resolveSimulationEndpoint,
1884
1946
  resolveUserOpChain,
1947
+ resolveX402Wallet,
1885
1948
  sameExecutionIntent,
1886
1949
  saveNotificationSettings,
1887
1950
  selectChainCapabilities,