@usebutr/core 0.5.0 → 1.1.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.ts +469 -320
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +235 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/types/account.ts","../src/types/capabilities.ts","../src/types/platform.ts","../src/types/chains-by-platform.ts","../src/types/connector.ts","../src/types/wallet.ts","../src/types/discoverer.ts","../src/types/errors.ts","../src/storage/persistence.ts","../src/storage/snapshot.ts","../src/types/manager.ts","../src/types/signer.ts","../src/wallet-source.ts","../src/store/reducer.ts","../src/store/shadow-adapter.ts","../src/storage/browser-storage-driver.ts","../src/storage/cookie-storage-driver.ts","../src/storage/wallet-storage.ts","../src/store/wallet-store.ts","../src/group-by-platform.ts","../src/sign-in/sign-in-flow.ts","../src/wallet-equal.ts","../src/logger.ts","../src/sanitize-icon.ts","../src/encoding/bytes.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { createStore } from "zustand/vanilla";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
+
//#region src/types/account.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build butr's `Account` shape from a wallet address and a resolved
|
|
7
|
+
* `ChainBase`. The composite id (`<chain>:<address>`) is what the
|
|
8
|
+
* reducer uses to compare accounts across refreshes, so every adapter
|
|
9
|
+
* must build accounts through this helper (or keep the format
|
|
10
|
+
* byte-identical).
|
|
11
|
+
*/
|
|
12
|
+
const buildAccount = (address, chain) => ({
|
|
13
|
+
chain,
|
|
14
|
+
id: `${chain.id}:${address}`,
|
|
15
|
+
walletAddress: address
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
4
19
|
//#region src/types/chains-by-platform.ts
|
|
5
20
|
/**
|
|
6
21
|
* Build a fully-populated `ChainsByPlatform` from a partial. Platforms
|
|
@@ -106,7 +121,7 @@ const mapConnectionError = (raw) => {
|
|
|
106
121
|
};
|
|
107
122
|
|
|
108
123
|
//#endregion
|
|
109
|
-
//#region src/types/
|
|
124
|
+
//#region src/types/platform.ts
|
|
110
125
|
/**
|
|
111
126
|
* Canonical list of supported chain platforms. The single runtime source
|
|
112
127
|
* of truth: `ChainPlatform` is derived from it, and storage validators
|
|
@@ -121,18 +136,6 @@ const CHAIN_PLATFORMS = [
|
|
|
121
136
|
"bitcoin",
|
|
122
137
|
"polkadot"
|
|
123
138
|
];
|
|
124
|
-
/**
|
|
125
|
-
* Build butr's `Account` shape from a wallet address and a resolved
|
|
126
|
-
* `ChainBase`. The composite id (`<chain>:<address>`) is what the
|
|
127
|
-
* reducer uses to compare accounts across refreshes, so every adapter
|
|
128
|
-
* must build accounts through this helper (or keep the format
|
|
129
|
-
* byte-identical).
|
|
130
|
-
*/
|
|
131
|
-
const buildAccount = (address, chain) => ({
|
|
132
|
-
chain,
|
|
133
|
-
id: `${chain.id}:${address}`,
|
|
134
|
-
walletAddress: address
|
|
135
|
-
});
|
|
136
139
|
|
|
137
140
|
//#endregion
|
|
138
141
|
//#region src/wallet-source.ts
|
|
@@ -586,8 +589,6 @@ const createConnectorLifecycle = (handlers) => {
|
|
|
586
589
|
case "disconnected":
|
|
587
590
|
detach(connectorId);
|
|
588
591
|
handlers.onDisconnected(connectorId, connector.chainPlatform);
|
|
589
|
-
break;
|
|
590
|
-
default:
|
|
591
592
|
}
|
|
592
593
|
});
|
|
593
594
|
unsubscribers.set(connectorId, unsub);
|
|
@@ -1188,7 +1189,7 @@ const createWalletStore = (config) => {
|
|
|
1188
1189
|
|
|
1189
1190
|
//#endregion
|
|
1190
1191
|
//#region src/storage/cookie-storage-driver.ts
|
|
1191
|
-
const DEFAULT_MAX_AGE_SECONDS =
|
|
1192
|
+
const DEFAULT_MAX_AGE_SECONDS = 2592e3;
|
|
1192
1193
|
const encode = (value) => encodeURIComponent(value);
|
|
1193
1194
|
const decode = (value) => decodeURIComponent(value);
|
|
1194
1195
|
const readCookies = () => {
|
|
@@ -1383,51 +1384,43 @@ const readWalletSnapshot = (source, options = {}) => {
|
|
|
1383
1384
|
};
|
|
1384
1385
|
|
|
1385
1386
|
//#endregion
|
|
1386
|
-
//#region src/
|
|
1387
|
+
//#region src/group-by-platform.ts
|
|
1387
1388
|
/**
|
|
1388
|
-
*
|
|
1389
|
-
* share the same adapter instance, active account address, and active
|
|
1390
|
-
* account chain id. Used by `useStoreWithEqualityFn` consumers
|
|
1391
|
-
* (active-wallet, selected-wallet, useWalletEntry) to suppress spurious
|
|
1392
|
-
* re-renders when the underlying Map churns but the resolved entry
|
|
1393
|
-
* hasn't changed.
|
|
1389
|
+
* Bucket a flat list into per-platform groups.
|
|
1394
1390
|
*
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1391
|
+
* A multi-chain wallet announces one adapter per platform it speaks, so
|
|
1392
|
+
* discovery hands back a flat list where a single brand appears several
|
|
1393
|
+
* times. Any app targeting more than one chain has to bucket that list
|
|
1394
|
+
* before rendering, and hand-rolled versions drift: butr's own demos
|
|
1395
|
+
* carried a copy that reimplemented `CHAIN_PLATFORMS` as a local
|
|
1396
|
+
* ordering constant.
|
|
1399
1397
|
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
|
|
1404
|
-
const walletEqual = (a, b) => {
|
|
1405
|
-
if (a === b) return true;
|
|
1406
|
-
if (!a || !b) return false;
|
|
1407
|
-
return a.connector === b.connector && a.account.walletAddress === b.account.walletAddress && a.account.chain.id === b.account.chain.id;
|
|
1408
|
-
};
|
|
1409
|
-
|
|
1410
|
-
//#endregion
|
|
1411
|
-
//#region src/sanitize-icon.ts
|
|
1412
|
-
/**
|
|
1413
|
-
* Normalize a wallet-announced icon string.
|
|
1398
|
+
* Keys are inserted in `CHAIN_PLATFORMS` order and platforms with no
|
|
1399
|
+
* members are omitted, so the result is directly iterable for rendering
|
|
1400
|
+
* (`[...groups]`) as well as addressable for lookup (`groups.get("evm")`)
|
|
1401
|
+
* without a further emptiness filter.
|
|
1414
1402
|
*
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1421
|
-
*
|
|
1422
|
-
* Trims surrounding whitespace and treats an all-whitespace (or empty)
|
|
1423
|
-
* icon as absent, so consumers get either a usable string or
|
|
1424
|
-
* `undefined`: never a blank or malformed one. `undefined` passes
|
|
1425
|
-
* through untouched.
|
|
1403
|
+
* `getPlatform` exists because the discriminant sits at a different depth
|
|
1404
|
+
* depending on the input: a discovered `WalletAdapter` carries
|
|
1405
|
+
* `chainPlatform` at the top level, a pool entry nests it under
|
|
1406
|
+
* `connector`. React consumers should reach for
|
|
1407
|
+
* `useDiscoveredWalletsByPlatform` / `useConnectedWalletsByPlatform`
|
|
1408
|
+
* instead, which bind the accessor for them.
|
|
1426
1409
|
*/
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1410
|
+
const groupByPlatform = (items, getPlatform) => {
|
|
1411
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1412
|
+
for (const item of items) {
|
|
1413
|
+
const platform = getPlatform(item);
|
|
1414
|
+
const bucket = buckets.get(platform);
|
|
1415
|
+
if (bucket === void 0) buckets.set(platform, [item]);
|
|
1416
|
+
else bucket.push(item);
|
|
1417
|
+
}
|
|
1418
|
+
const ordered = /* @__PURE__ */ new Map();
|
|
1419
|
+
for (const platform of CHAIN_PLATFORMS) {
|
|
1420
|
+
const bucket = buckets.get(platform);
|
|
1421
|
+
if (bucket !== void 0) ordered.set(platform, bucket);
|
|
1422
|
+
}
|
|
1423
|
+
return ordered;
|
|
1431
1424
|
};
|
|
1432
1425
|
|
|
1433
1426
|
//#endregion
|
|
@@ -1448,6 +1441,10 @@ const sanitizeIcon = (icon) => {
|
|
|
1448
1441
|
* - {@link bytesToHexPrefixed} returns `0x`-prefixed hex (EVM, Polkadot).
|
|
1449
1442
|
* - {@link hexToBytes} tolerantly strips an optional `0x` (all callers).
|
|
1450
1443
|
*/
|
|
1444
|
+
/** Bitcoin/Solana alphabet; omits the visually ambiguous `0`, `O`, `I`, `l`. */
|
|
1445
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1446
|
+
const BASE58_INDEX = /* @__PURE__ */ new Map();
|
|
1447
|
+
for (let i = 0; i < 58; i += 1) BASE58_INDEX.set(BASE58_ALPHABET[i] ?? "", i);
|
|
1451
1448
|
/** Bare lowercase hex, no `0x` prefix (Bitcoin, Ledger). */
|
|
1452
1449
|
const bytesToHex = (bytes) => {
|
|
1453
1450
|
let hex = "";
|
|
@@ -1488,7 +1485,188 @@ const bytesToBase64 = (bytes) => {
|
|
|
1488
1485
|
for (const byte of bytes) binary += String.fromCodePoint(byte);
|
|
1489
1486
|
return btoa(binary);
|
|
1490
1487
|
};
|
|
1488
|
+
/**
|
|
1489
|
+
* `Uint8Array` → base58 (Solana addresses and signatures). Leading zero
|
|
1490
|
+
* bytes are significant in base58 and survive the BigInt round-trip only
|
|
1491
|
+
* because they're re-prefixed as `1`s afterwards.
|
|
1492
|
+
*/
|
|
1493
|
+
const bytesToBase58 = (bytes) => {
|
|
1494
|
+
let intVal = 0n;
|
|
1495
|
+
for (const byte of bytes) intVal = intVal << 8n | BigInt(byte);
|
|
1496
|
+
let out = "";
|
|
1497
|
+
while (intVal > 0n) {
|
|
1498
|
+
const remainder = intVal % 58n;
|
|
1499
|
+
intVal /= 58n;
|
|
1500
|
+
out = BASE58_ALPHABET[Number(remainder)] + out;
|
|
1501
|
+
}
|
|
1502
|
+
for (const byte of bytes) {
|
|
1503
|
+
if (byte !== 0) break;
|
|
1504
|
+
out = `1${out}`;
|
|
1505
|
+
}
|
|
1506
|
+
return out;
|
|
1507
|
+
};
|
|
1508
|
+
/** Decode base58 into raw bytes. Throws on characters outside the alphabet
|
|
1509
|
+
* rather than silently dropping them. */
|
|
1510
|
+
const base58ToBytes = (input) => {
|
|
1511
|
+
let intVal = 0n;
|
|
1512
|
+
let leadingZeros = 0;
|
|
1513
|
+
let stillLeading = true;
|
|
1514
|
+
for (const char of input) {
|
|
1515
|
+
if (stillLeading && char === "1") leadingZeros += 1;
|
|
1516
|
+
else stillLeading = false;
|
|
1517
|
+
const digit = BASE58_INDEX.get(char);
|
|
1518
|
+
if (digit === void 0) throw new Error(`Invalid base58 character "${char}"`);
|
|
1519
|
+
intVal = intVal * 58n + BigInt(digit);
|
|
1520
|
+
}
|
|
1521
|
+
const bytes = [];
|
|
1522
|
+
const byteMask = 255n;
|
|
1523
|
+
while (intVal > 0n) {
|
|
1524
|
+
bytes.unshift(Number(intVal & byteMask));
|
|
1525
|
+
intVal >>= 8n;
|
|
1526
|
+
}
|
|
1527
|
+
for (let i = 0; i < leadingZeros; i += 1) bytes.unshift(0);
|
|
1528
|
+
return Uint8Array.from(bytes);
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
//#endregion
|
|
1532
|
+
//#region src/sign-in/sign-in-flow.ts
|
|
1533
|
+
/** Thrown before any wallet interaction when the wallet can't sign at
|
|
1534
|
+
* all. Distinct from a rejection: nothing was asked of the user, so UI
|
|
1535
|
+
* should say "this wallet can't sign in" rather than "you declined". */
|
|
1536
|
+
var SignInUnsupportedError = class extends Error {
|
|
1537
|
+
connectorId;
|
|
1538
|
+
constructor(connectorId) {
|
|
1539
|
+
super(`Wallet "${connectorId}" reports capabilities.signMessage === false, so it cannot sign in.`);
|
|
1540
|
+
this.connectorId = connectorId;
|
|
1541
|
+
this.name = "SignInUnsupportedError";
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1544
|
+
const defaultBuildMessage = ({ account, nonce }) => `${account.walletAddress} signs in.\nNonce: ${nonce}`;
|
|
1545
|
+
/**
|
|
1546
|
+
* Build a reusable sign-in flow: nonce, capability gate, signature,
|
|
1547
|
+
* encoding, verification.
|
|
1548
|
+
*
|
|
1549
|
+
* Every wallet-auth app writes this same sequence, and the parts that
|
|
1550
|
+
* are easy to get wrong are the ones that aren't about the app: which
|
|
1551
|
+
* capability flag gates the attempt, whether a Solana wallet should take
|
|
1552
|
+
* the SIWS path instead, and which bytes to base64 for the server (the
|
|
1553
|
+
* wallet's `signedMessage`, not the input). This owns those; you own the
|
|
1554
|
+
* nonce endpoint, the message format, and the verifier.
|
|
1555
|
+
*
|
|
1556
|
+
* ```ts
|
|
1557
|
+
* const { signIn } = createSignInFlow({
|
|
1558
|
+
* getNonce: () => fetch("/api/nonce").then((r) => r.text()),
|
|
1559
|
+
* verify: (result) =>
|
|
1560
|
+
* fetch("/api/verify", { body: JSON.stringify(result), method: "POST" }).then(() => {}),
|
|
1561
|
+
* });
|
|
1562
|
+
*
|
|
1563
|
+
* await signIn(wallet);
|
|
1564
|
+
* ```
|
|
1565
|
+
*
|
|
1566
|
+
* Solana wallets advertising `solana:signIn` take the SIWS path
|
|
1567
|
+
* automatically, so `result.signedMessage` holds the wallet-composed
|
|
1568
|
+
* SIWS statement and `result.message` is absent. Set
|
|
1569
|
+
* `preferSignMessage` to opt out.
|
|
1570
|
+
*/
|
|
1571
|
+
const createSignInFlow = (options) => {
|
|
1572
|
+
const buildMessage = options.buildMessage ?? defaultBuildMessage;
|
|
1573
|
+
const sign = async (wallet, account) => {
|
|
1574
|
+
const { connector } = wallet;
|
|
1575
|
+
const signingAccount = account ?? wallet.account;
|
|
1576
|
+
if (!connector.capabilities.signMessage) throw new SignInUnsupportedError(connector.id);
|
|
1577
|
+
const nonce = await options.getNonce({
|
|
1578
|
+
account: signingAccount,
|
|
1579
|
+
wallet
|
|
1580
|
+
});
|
|
1581
|
+
if (options.preferSignMessage !== true && connector.chainPlatform === "svm" && connector.capabilities.signIn && connector.signIn !== void 0) {
|
|
1582
|
+
const output = await connector.signIn({ nonce });
|
|
1583
|
+
return {
|
|
1584
|
+
account: output.account,
|
|
1585
|
+
nonce,
|
|
1586
|
+
signature: output.signature,
|
|
1587
|
+
signatureBase64: bytesToBase64(output.signature),
|
|
1588
|
+
signedMessage: output.signedMessage,
|
|
1589
|
+
signedMessageBase64: bytesToBase64(output.signedMessage),
|
|
1590
|
+
wallet
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
const message = buildMessage({
|
|
1594
|
+
account: signingAccount,
|
|
1595
|
+
nonce,
|
|
1596
|
+
wallet
|
|
1597
|
+
});
|
|
1598
|
+
const { signature, signedMessage } = await connector.signMessage(new TextEncoder().encode(message), signingAccount);
|
|
1599
|
+
return {
|
|
1600
|
+
account: signingAccount,
|
|
1601
|
+
message,
|
|
1602
|
+
nonce,
|
|
1603
|
+
signature,
|
|
1604
|
+
signatureBase64: bytesToBase64(signature),
|
|
1605
|
+
signedMessage,
|
|
1606
|
+
signedMessageBase64: bytesToBase64(signedMessage),
|
|
1607
|
+
wallet
|
|
1608
|
+
};
|
|
1609
|
+
};
|
|
1610
|
+
return { signIn: async (wallet, account) => {
|
|
1611
|
+
const result = await sign(wallet, account);
|
|
1612
|
+
await options.verify(result);
|
|
1613
|
+
return result;
|
|
1614
|
+
} };
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
//#endregion
|
|
1618
|
+
//#region src/wallet-equal.ts
|
|
1619
|
+
/**
|
|
1620
|
+
* Two wallet snapshots are equivalent for selector purposes iff they
|
|
1621
|
+
* share the same adapter instance, active account address, and active
|
|
1622
|
+
* account chain id. Used by `useStoreWithEqualityFn` consumers
|
|
1623
|
+
* (active-wallet, selected-wallet, useWalletEntry) to suppress spurious
|
|
1624
|
+
* re-renders when the underlying Map churns but the resolved entry
|
|
1625
|
+
* hasn't changed.
|
|
1626
|
+
*
|
|
1627
|
+
* The adapter is compared by reference, not by `connector.id`: hydration
|
|
1628
|
+
* replaces a shadow adapter with the live one under an unchanged id and
|
|
1629
|
+
* address, so an id comparison reports "equal" and leaves consumers
|
|
1630
|
+
* holding a placeholder whose every method throws ShadowConnectorError.
|
|
1631
|
+
*
|
|
1632
|
+
* Hoisted to its own module so the equivalence rule lives in one place;
|
|
1633
|
+
* if we ever extend the snapshot (e.g. to consider `accounts.length`),
|
|
1634
|
+
* every selector hook picks up the new rule for free.
|
|
1635
|
+
*/
|
|
1636
|
+
const walletEqual = (a, b) => {
|
|
1637
|
+
if (a === b) return true;
|
|
1638
|
+
if (!a || !b) return false;
|
|
1639
|
+
return a.connector === b.connector && a.account.walletAddress === b.account.walletAddress && a.account.chain.id === b.account.chain.id;
|
|
1640
|
+
};
|
|
1641
|
+
|
|
1642
|
+
//#endregion
|
|
1643
|
+
//#region src/sanitize-icon.ts
|
|
1644
|
+
/**
|
|
1645
|
+
* Normalize a wallet-announced icon string.
|
|
1646
|
+
*
|
|
1647
|
+
* Wallets announce their icon through external metadata; EIP-6963
|
|
1648
|
+
* `providerInfo.icon`, Wallet Standard `wallet.icon`. That value is
|
|
1649
|
+
* not under butr's control, and some wallets ship data-URI icons with
|
|
1650
|
+
* surrounding whitespace (a newline left over from a pretty-printed
|
|
1651
|
+
* manifest). Strict consumers reject it: Next.js's `<Image>` throws
|
|
1652
|
+
* because `src` must not start with a control character.
|
|
1653
|
+
*
|
|
1654
|
+
* Trims surrounding whitespace and treats an all-whitespace (or empty)
|
|
1655
|
+
* icon as absent, so consumers get either a usable string or
|
|
1656
|
+
* `undefined`: never a blank or malformed one. `undefined` passes
|
|
1657
|
+
* through untouched.
|
|
1658
|
+
*
|
|
1659
|
+
* **Discovery already applies this.** Every adapter butr discovers has
|
|
1660
|
+
* had its icon sanitized at construction, so `Connector.icon` is safe to
|
|
1661
|
+
* render as-is. Reach for this helper only when building adapter or
|
|
1662
|
+
* `ConnectorMeta` metadata yourself from a source butr didn't produce.
|
|
1663
|
+
*/
|
|
1664
|
+
const sanitizeIcon = (icon) => {
|
|
1665
|
+
if (icon === void 0) return;
|
|
1666
|
+
const trimmed = icon.trim();
|
|
1667
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1668
|
+
};
|
|
1491
1669
|
|
|
1492
1670
|
//#endregion
|
|
1493
|
-
export { CHAIN_PLATFORMS, EMPTY_SNAPSHOT, ShadowConnectorError, WalletStorage, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createWalletSource, createWalletStore, hexToBytes, isShadowAdapter, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
1671
|
+
export { CHAIN_PLATFORMS, EMPTY_SNAPSHOT, ShadowConnectorError, SignInUnsupportedError, WalletStorage, base58ToBytes, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase58, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createSignInFlow, createWalletSource, createWalletStore, groupByPlatform, hexToBytes, isShadowAdapter, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
1494
1672
|
//# sourceMappingURL=index.js.map
|