@naculus/connect-appkit-core 0.9.0 → 0.11.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 +117 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +112 -27
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
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
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
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
|
|
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 =
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
return {
|
|
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);
|
|
@@ -1422,6 +1430,25 @@ function relativeExpiry(expiresAt, now, locale) {
|
|
|
1422
1430
|
}
|
|
1423
1431
|
return new Intl.RelativeTimeFormat(locale).format(value, unit);
|
|
1424
1432
|
}
|
|
1433
|
+
function absoluteUtc(timestamp, locale) {
|
|
1434
|
+
return new Intl.DateTimeFormat(locale, {
|
|
1435
|
+
year: "numeric",
|
|
1436
|
+
month: "short",
|
|
1437
|
+
day: "numeric",
|
|
1438
|
+
hour: "2-digit",
|
|
1439
|
+
minute: "2-digit",
|
|
1440
|
+
hourCycle: "h23",
|
|
1441
|
+
timeZone: "UTC",
|
|
1442
|
+
timeZoneName: "short"
|
|
1443
|
+
}).format(timestamp * 1e3);
|
|
1444
|
+
}
|
|
1445
|
+
function formatPeriodLength(seconds) {
|
|
1446
|
+
const [amount, unit] = seconds % 604800 === 0 ? [seconds / 604800, "week"] : seconds % 86400 === 0 ? [seconds / 86400, "day"] : seconds % 3600 === 0 ? [seconds / 3600, "hour"] : seconds % 60 === 0 ? [seconds / 60, "minute"] : [seconds, "second"];
|
|
1447
|
+
return `${amount} ${unit}${amount === 1 ? "" : "s"}`;
|
|
1448
|
+
}
|
|
1449
|
+
function formatAuthorizationEnforcement(enforcement) {
|
|
1450
|
+
return enforcement === "on-chain" ? "Limits enforced by the blockchain" : enforcement === "device" ? "Limits enforced by this device" : null;
|
|
1451
|
+
}
|
|
1425
1452
|
function describeAuthorization(input, options = {}) {
|
|
1426
1453
|
const now = options.now ?? Math.floor(Date.now() / 1e3);
|
|
1427
1454
|
const locale = options.locale ?? "en";
|
|
@@ -1431,10 +1458,11 @@ function describeAuthorization(input, options = {}) {
|
|
|
1431
1458
|
label,
|
|
1432
1459
|
principal: input.principal ?? null,
|
|
1433
1460
|
grants: input.grants.map((grant) => {
|
|
1434
|
-
const metadata =
|
|
1461
|
+
const [assetTrust, metadata] = trustedMetadata(grant.asset, options);
|
|
1435
1462
|
return {
|
|
1436
1463
|
asset: grant.asset,
|
|
1437
|
-
|
|
1464
|
+
assetTrust,
|
|
1465
|
+
assetLabel: metadata?.symbol || grant.asset.split(":").at(-1),
|
|
1438
1466
|
recipients: grant.recipients.map((full) => ({
|
|
1439
1467
|
shortened: full.length <= 14 ? full : `${full.slice(0, 6)}\u2026${full.slice(-6)}`,
|
|
1440
1468
|
full
|
|
@@ -1442,23 +1470,23 @@ function describeAuthorization(input, options = {}) {
|
|
|
1442
1470
|
perPayment: formatAuthorizationAmount(grant.maxPerPayment, metadata),
|
|
1443
1471
|
total: formatAuthorizationAmount(grant.maxTotal, metadata),
|
|
1444
1472
|
count: grant.maxCount ?? null,
|
|
1473
|
+
period: grant.period ? {
|
|
1474
|
+
amount: formatAuthorizationAmount(grant.period.amount, metadata),
|
|
1475
|
+
every: formatPeriodLength(grant.period.seconds),
|
|
1476
|
+
startsAt: absoluteUtc(grant.period.start, locale)
|
|
1477
|
+
} : null,
|
|
1445
1478
|
rails: grant.rails.map((r) => r.replace("-", " "))
|
|
1446
1479
|
};
|
|
1447
1480
|
}),
|
|
1448
1481
|
expiry: {
|
|
1449
1482
|
timestamp: input.expiresAt,
|
|
1450
|
-
absolute:
|
|
1451
|
-
year: "numeric",
|
|
1452
|
-
month: "short",
|
|
1453
|
-
day: "numeric",
|
|
1454
|
-
hour: "2-digit",
|
|
1455
|
-
minute: "2-digit",
|
|
1456
|
-
hourCycle: "h23",
|
|
1457
|
-
timeZone: "UTC",
|
|
1458
|
-
timeZoneName: "short"
|
|
1459
|
-
}).format(input.expiresAt * 1e3),
|
|
1483
|
+
absolute: absoluteUtc(input.expiresAt, locale),
|
|
1460
1484
|
relative: relativeExpiry(input.expiresAt, now, locale)
|
|
1461
1485
|
},
|
|
1486
|
+
enforcement: options.enforcement ?? null,
|
|
1487
|
+
enforcementLabel: formatAuthorizationEnforcement(
|
|
1488
|
+
options.enforcement ?? null
|
|
1489
|
+
),
|
|
1462
1490
|
warnings: flags.map(
|
|
1463
1491
|
(flag) => flag === "unrestricted-recipient-legacy" ? "This key can pay any recipient." : "This key can do more than shown here."
|
|
1464
1492
|
)
|
|
@@ -1472,6 +1500,7 @@ var REFUSAL_SENTENCES = {
|
|
|
1472
1500
|
"over-per-payment": "This amount exceeds the per-payment limit.",
|
|
1473
1501
|
"over-total": "This amount exceeds the remaining total limit.",
|
|
1474
1502
|
"over-count": "This authorization has reached its payment count limit.",
|
|
1503
|
+
"period-limit-exceeded": "This amount exceeds the limit for the current period.",
|
|
1475
1504
|
"rail-not-allowed": "This payment rail is not allowed.",
|
|
1476
1505
|
"invalid-authorization": "The authorization or spend request is invalid."
|
|
1477
1506
|
};
|
|
@@ -1487,7 +1516,7 @@ function explainSpend(authorization, request, options = {}) {
|
|
|
1487
1516
|
const remainingTotal = authorization.grants[verdict.grant].maxTotal - request.spentSoFar - request.amount;
|
|
1488
1517
|
const remainingTotalFormatted = formatAuthorizationAmount(
|
|
1489
1518
|
remainingTotal,
|
|
1490
|
-
|
|
1519
|
+
trustedMetadata(authorization.grants[verdict.grant].asset, options)[1]
|
|
1491
1520
|
);
|
|
1492
1521
|
return {
|
|
1493
1522
|
allowed: true,
|
|
@@ -1569,6 +1598,57 @@ function describePayment(input, result) {
|
|
|
1569
1598
|
};
|
|
1570
1599
|
}
|
|
1571
1600
|
|
|
1601
|
+
// src/x402-wallet.ts
|
|
1602
|
+
var import_connect_core18 = require("@naculus/connect-core");
|
|
1603
|
+
var import_payments_x402 = require("@naculus/payments-x402");
|
|
1604
|
+
function findX402Provider(session, sources) {
|
|
1605
|
+
if (!session) return null;
|
|
1606
|
+
if (session.walletType === "eip6963" || session.id.startsWith("eip6963-")) {
|
|
1607
|
+
return sources.injected?.find((wallet) => wallet.id === session.walletId)?.provider ?? null;
|
|
1608
|
+
}
|
|
1609
|
+
if (session.walletType === "walletconnect") {
|
|
1610
|
+
return sources.walletConnect ?? null;
|
|
1611
|
+
}
|
|
1612
|
+
return null;
|
|
1613
|
+
}
|
|
1614
|
+
function unavailable(reason) {
|
|
1615
|
+
return { provider: null, address: null, reason };
|
|
1616
|
+
}
|
|
1617
|
+
function resolveX402Wallet(session, provider) {
|
|
1618
|
+
if (!session) return unavailable("no-session");
|
|
1619
|
+
const namespace = session.namespaces.eip155;
|
|
1620
|
+
if (!namespace) return unavailable("not-evm");
|
|
1621
|
+
const isInjected = session.walletType === "eip6963" || session.id.startsWith("eip6963-");
|
|
1622
|
+
const isWalletConnect = session.walletType === "walletconnect";
|
|
1623
|
+
if (!isInjected && !isWalletConnect || !provider?.request) {
|
|
1624
|
+
return unavailable("unsupported-wallet-type");
|
|
1625
|
+
}
|
|
1626
|
+
for (const account of namespace.accounts) {
|
|
1627
|
+
const parsed = (0, import_connect_core18.parseCaip10)(account);
|
|
1628
|
+
const address = parsed?.namespace === "eip155" ? parsed.address : account;
|
|
1629
|
+
if ((0, import_connect_core18.isEvmAddress)(address)) {
|
|
1630
|
+
return {
|
|
1631
|
+
provider,
|
|
1632
|
+
address,
|
|
1633
|
+
reason: null
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
return unavailable("not-evm");
|
|
1638
|
+
}
|
|
1639
|
+
function createX402WalletSigner(session, provider, switchChain) {
|
|
1640
|
+
const resolved = resolveX402Wallet(session, provider);
|
|
1641
|
+
if (resolved.reason) return { signer: null, reason: resolved.reason };
|
|
1642
|
+
return {
|
|
1643
|
+
signer: (0, import_payments_x402.walletX402Signer)({
|
|
1644
|
+
provider: resolved.provider,
|
|
1645
|
+
address: resolved.address,
|
|
1646
|
+
switchChain
|
|
1647
|
+
}),
|
|
1648
|
+
reason: null
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1572
1652
|
// src/mpp-session.ts
|
|
1573
1653
|
function record2(value) {
|
|
1574
1654
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
@@ -1600,11 +1680,11 @@ function readMppRecoveryChannelId(error) {
|
|
|
1600
1680
|
}
|
|
1601
1681
|
|
|
1602
1682
|
// src/solana-session-key.ts
|
|
1603
|
-
var
|
|
1683
|
+
var import_connect_core19 = require("@naculus/connect-core");
|
|
1604
1684
|
function send(rpc) {
|
|
1605
1685
|
const sendTransaction = rpc.sendTransaction;
|
|
1606
1686
|
if (!sendTransaction) {
|
|
1607
|
-
throw new
|
|
1687
|
+
throw new import_connect_core19.WalletError(
|
|
1608
1688
|
"invalid_input",
|
|
1609
1689
|
"The Solana RPC must implement sendTransaction to approve or revoke."
|
|
1610
1690
|
);
|
|
@@ -1642,7 +1722,7 @@ function createSolanaSessionKeyFlow(deps) {
|
|
|
1642
1722
|
} catch (cause) {
|
|
1643
1723
|
await manager.revoke(draft.id).catch(() => {
|
|
1644
1724
|
});
|
|
1645
|
-
throw new
|
|
1725
|
+
throw new import_connect_core19.WalletError(
|
|
1646
1726
|
"rpc_error",
|
|
1647
1727
|
`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
1728
|
);
|
|
@@ -1653,7 +1733,7 @@ function createSolanaSessionKeyFlow(deps) {
|
|
|
1653
1733
|
async revoke(id) {
|
|
1654
1734
|
const key = (await list()).find((k) => k.id === id);
|
|
1655
1735
|
if (!key) {
|
|
1656
|
-
throw new
|
|
1736
|
+
throw new import_connect_core19.WalletError(
|
|
1657
1737
|
"invalid_input",
|
|
1658
1738
|
`No Solana session key ${id} for this owner.`
|
|
1659
1739
|
);
|
|
@@ -1665,7 +1745,7 @@ function createSolanaSessionKeyFlow(deps) {
|
|
|
1665
1745
|
rpc
|
|
1666
1746
|
);
|
|
1667
1747
|
const signed = await owner.signTransaction(transaction);
|
|
1668
|
-
const revocation = (0,
|
|
1748
|
+
const revocation = (0, import_connect_core19.verifySignedOwnerTransaction)(signed, {
|
|
1669
1749
|
kind: "revoke",
|
|
1670
1750
|
revocation: {
|
|
1671
1751
|
owner: key.owner,
|
|
@@ -1680,7 +1760,7 @@ function createSolanaSessionKeyFlow(deps) {
|
|
|
1680
1760
|
}
|
|
1681
1761
|
|
|
1682
1762
|
// src/web3-store.ts
|
|
1683
|
-
var
|
|
1763
|
+
var import_connect_core20 = require("@naculus/connect-core");
|
|
1684
1764
|
function withTimeout(promise, ms, label = "Operation") {
|
|
1685
1765
|
let timeoutId;
|
|
1686
1766
|
const timeout = new Promise((_, reject) => {
|
|
@@ -1702,7 +1782,7 @@ async function withRetry(fn, options) {
|
|
|
1702
1782
|
lastError = error;
|
|
1703
1783
|
if (attempt < options.maxRetries) {
|
|
1704
1784
|
const delay = options.baseDelay * 2 ** attempt;
|
|
1705
|
-
|
|
1785
|
+
import_connect_core20.logger.warn(
|
|
1706
1786
|
"appkit/core",
|
|
1707
1787
|
`Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`
|
|
1708
1788
|
);
|
|
@@ -1840,6 +1920,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
|
|
|
1840
1920
|
createNotification,
|
|
1841
1921
|
createNotificationSettingsStorage,
|
|
1842
1922
|
createSolanaSessionKeyFlow,
|
|
1923
|
+
createX402WalletSigner,
|
|
1843
1924
|
decodeRevertReason,
|
|
1844
1925
|
defaultSiwxDomain,
|
|
1845
1926
|
defaultSiwxUri,
|
|
@@ -1852,6 +1933,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
|
|
|
1852
1933
|
encodeErc20TransferFrom,
|
|
1853
1934
|
explainSpend,
|
|
1854
1935
|
fetchUserOperationReceipt,
|
|
1936
|
+
findX402Provider,
|
|
1855
1937
|
formatAuthorizationAmount,
|
|
1856
1938
|
getResolver,
|
|
1857
1939
|
getSharedSessionKeyManager,
|
|
@@ -1882,6 +1964,7 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
|
|
|
1882
1964
|
resolveRevertReason,
|
|
1883
1965
|
resolveSimulationEndpoint,
|
|
1884
1966
|
resolveUserOpChain,
|
|
1967
|
+
resolveX402Wallet,
|
|
1885
1968
|
sameExecutionIntent,
|
|
1886
1969
|
saveNotificationSettings,
|
|
1887
1970
|
selectChainCapabilities,
|