@yeying-community/web3-bs 1.0.12 → 1.0.14

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/README.md CHANGED
@@ -22,7 +22,7 @@ npm install @yeying-community/web3-bs
22
22
 
23
23
  - `getProvider` / `requireProvider`
24
24
  - `watchProvider`
25
- - `requestAccounts` / `focusPendingApproval` / `getAccounts` / `getPreferredAccount` / `watchAccounts`
25
+ - `requestAccounts` / `focusPendingApproval` / `getAccounts` / `getPreferredAccount` / `resolveWalletAccount` / `watchAccounts`
26
26
  - `getChainId` / `getBalance`
27
27
  - `onAccountsChanged` / `onChainChanged`
28
28
  - `classifyWalletError` / `isUserRejectedWalletAction` / `isWalletReconnectError`
@@ -30,6 +30,14 @@ npm install @yeying-community/web3-bs
30
30
  `requestAccounts` 默认会复用同一 provider 上尚未完成的连接请求,避免用户重复点击时触发多个钱包授权弹窗。
31
31
  当钱包已经存在待确认的连接、签名或解锁窗口时,可调用 `focusPendingApproval` 将该窗口重新拉到前台,而不是再发起一次新的请求。
32
32
 
33
+ `resolveWalletAccount` 用于处理“应用传入期望地址”和“钱包当前地址”之间的关系:
34
+ - 未传 `expectedAccount`:直接采用钱包当前地址,返回 `status: "wallet"`
35
+ - 传了且与钱包当前地址一致:返回 `status: "matched"`
36
+ - 传了但与钱包当前地址不一致:返回 `status: "mismatch"`
37
+ - 钱包当前没有可用地址:返回 `status: "unavailable"`
38
+
39
+ 它只返回结构化决策结果,不负责弹窗、toast 或业务状态写入,适合在登录、授权、签名前由应用自行决定是继续使用当前钱包地址,还是要求用户切换钱包账户。
40
+
33
41
  ### 2) SIWE + JWT
34
42
 
35
43
  - `signMessage`
@@ -0,0 +1,54 @@
1
+ /**
2
+ * 加密/解密 SDK API
3
+ *
4
+ * 调用钱包插件的 `yeying_encrypt` / `yeying_decrypt` / `yeying_getCipherSuites`
5
+ * EIP-1193 自定义方法。命名安全套件 + 静默执行 + 站点授权模型同 UCAN。
6
+ *
7
+ * 数据密码(password 参数)由 DApp 自行管理与钱包密码独立;
8
+ * plaintext 走 base64 字符串跨 message 边界传输。
9
+ */
10
+ import { isUserRejectedWalletAction } from './provider';
11
+ import type { Eip1193Provider } from './types';
12
+ export interface CipherSuiteInfo {
13
+ name: string;
14
+ description: string;
15
+ mode: 'hash' | 'symmetric';
16
+ }
17
+ export interface EncryptOptions {
18
+ data: string | Uint8Array;
19
+ password: string;
20
+ suite?: string;
21
+ provider?: Eip1193Provider;
22
+ }
23
+ export interface DecryptOptions {
24
+ ciphertext: string;
25
+ password: string;
26
+ provider?: Eip1193Provider;
27
+ }
28
+ export interface GetCipherSuitesOptions {
29
+ provider?: Eip1193Provider;
30
+ }
31
+ export declare class CipherError extends Error {
32
+ readonly type: 'userRejected' | 'disconnected' | 'timeout' | 'notFound' | 'unknown';
33
+ readonly code: number | null;
34
+ readonly originalError: unknown;
35
+ constructor(message: string, type: CipherError['type'], code: number | null, originalError: unknown);
36
+ }
37
+ declare function bytesToBase64(bytes: Uint8Array): string;
38
+ declare function base64ToBytes(b64: string): Uint8Array;
39
+ /**
40
+ * 用指定/默认套件加密数据
41
+ * @returns v1 格式密文 base64 字符串
42
+ */
43
+ export declare function encrypt(options: EncryptOptions): Promise<string>;
44
+ /**
45
+ * 解密 v1 格式密文
46
+ * @returns 明文 Uint8Array
47
+ */
48
+ export declare function decrypt(options: DecryptOptions): Promise<Uint8Array>;
49
+ /**
50
+ * 列出可用的命名安全套件
51
+ */
52
+ export declare function getSupportedCipherSuites(options?: GetCipherSuitesOptions): Promise<CipherSuiteInfo[]>;
53
+ export { bytesToBase64, base64ToBytes };
54
+ export { isUserRejectedWalletAction };
@@ -3,3 +3,4 @@ export * from './provider';
3
3
  export * from './siwe';
4
4
  export * from './ucan';
5
5
  export * from './central';
6
+ export * from './encrypt';
@@ -1,4 +1,4 @@
1
- import { Eip1193Provider, ProviderDiscoveryOptions, ProviderInfo, RequestAccountsOptions, AccountSelection, PreferredAccountOptions, WatchAccountsOptions, AccountsChangedHandler, WatchProviderOptions, ProviderChangedHandler, WalletErrorInfo, FocusPendingApprovalResult } from './types';
1
+ import { Eip1193Provider, ProviderDiscoveryOptions, ProviderInfo, RequestAccountsOptions, AccountSelection, PreferredAccountOptions, ResolveWalletAccountOptions, WalletAccountResolution, WatchAccountsOptions, AccountsChangedHandler, WatchProviderOptions, ProviderChangedHandler, WalletErrorInfo, FocusPendingApprovalResult } from './types';
2
2
  export declare function isYeYingProvider(provider?: Eip1193Provider | null, info?: ProviderInfo): boolean;
3
3
  export declare function getProvider(options?: ProviderDiscoveryOptions): Promise<Eip1193Provider | null>;
4
4
  export declare function watchProvider(handler: ProviderChangedHandler, options?: WatchProviderOptions): () => void;
@@ -13,6 +13,7 @@ export declare function focusPendingApproval(provider?: Eip1193Provider): Promis
13
13
  export declare function getAccounts(provider?: Eip1193Provider): Promise<string[]>;
14
14
  export declare function getChainId(provider?: Eip1193Provider): Promise<string | null>;
15
15
  export declare function getPreferredAccount(options?: PreferredAccountOptions): Promise<AccountSelection>;
16
+ export declare function resolveWalletAccount(options?: ResolveWalletAccountOptions): Promise<WalletAccountResolution>;
16
17
  export declare function watchAccounts(provider: Eip1193Provider, handler: AccountsChangedHandler, options?: WatchAccountsOptions): () => void;
17
18
  export declare function getBalance(provider?: Eip1193Provider, address?: string, blockTag?: string): Promise<string>;
18
19
  export declare function onAccountsChanged(provider: Eip1193Provider, handler: (accounts: string[]) => void): () => void;
@@ -67,6 +67,35 @@ export interface PreferredAccountOptions extends RequestAccountsOptions {
67
67
  autoConnect?: boolean;
68
68
  preferStored?: boolean;
69
69
  }
70
+ export interface ResolveWalletAccountOptions extends RequestAccountsOptions {
71
+ expectedAccount?: string | null;
72
+ autoConnect?: boolean;
73
+ }
74
+ export type WalletAccountResolution = {
75
+ status: 'wallet';
76
+ account: string;
77
+ walletAccount: string;
78
+ expectedAccount: null;
79
+ accounts: string[];
80
+ } | {
81
+ status: 'matched';
82
+ account: string;
83
+ walletAccount: string;
84
+ expectedAccount: string;
85
+ accounts: string[];
86
+ } | {
87
+ status: 'mismatch';
88
+ account: null;
89
+ walletAccount: string;
90
+ expectedAccount: string;
91
+ accounts: string[];
92
+ } | {
93
+ status: 'unavailable';
94
+ account: null;
95
+ walletAccount: null;
96
+ expectedAccount: string | null;
97
+ accounts: string[];
98
+ };
70
99
  export interface WatchAccountsOptions {
71
100
  storageKey?: string;
72
101
  preferStored?: boolean;
@@ -73,6 +73,17 @@ function selectPreferredAccount(accounts, stored, preferStored) {
73
73
  }
74
74
  return accounts[0] || null;
75
75
  }
76
+ function normalizeAccount(account) {
77
+ const normalized = (account || '').trim();
78
+ return normalized || null;
79
+ }
80
+ function isSameAccount(left, right) {
81
+ const normalizedLeft = normalizeAccount(left);
82
+ const normalizedRight = normalizeAccount(right);
83
+ return Boolean(normalizedLeft &&
84
+ normalizedRight &&
85
+ normalizedLeft.toLowerCase() === normalizedRight.toLowerCase());
86
+ }
76
87
  function isYeYingProvider(provider, info) {
77
88
  if (!provider)
78
89
  return false;
@@ -336,6 +347,49 @@ async function getPreferredAccount(options = {}) {
336
347
  writeStoredAccount(storageKey, account);
337
348
  return { account, accounts };
338
349
  }
350
+ async function resolveWalletAccount(options = {}) {
351
+ const provider = options.provider || (await requireProvider());
352
+ let accounts = await getAccounts(provider);
353
+ if (accounts.length === 0 && options.autoConnect) {
354
+ accounts = await requestAccounts({ provider });
355
+ }
356
+ const expectedAccount = normalizeAccount(options.expectedAccount);
357
+ const walletAccount = normalizeAccount(accounts[0]);
358
+ if (!walletAccount) {
359
+ return {
360
+ status: 'unavailable',
361
+ account: null,
362
+ walletAccount: null,
363
+ expectedAccount,
364
+ accounts,
365
+ };
366
+ }
367
+ if (!expectedAccount) {
368
+ return {
369
+ status: 'wallet',
370
+ account: walletAccount,
371
+ walletAccount,
372
+ expectedAccount: null,
373
+ accounts,
374
+ };
375
+ }
376
+ if (isSameAccount(expectedAccount, walletAccount)) {
377
+ return {
378
+ status: 'matched',
379
+ account: walletAccount,
380
+ walletAccount,
381
+ expectedAccount,
382
+ accounts,
383
+ };
384
+ }
385
+ return {
386
+ status: 'mismatch',
387
+ account: null,
388
+ walletAccount,
389
+ expectedAccount,
390
+ accounts,
391
+ };
392
+ }
339
393
  function watchAccounts(provider, handler, options = {}) {
340
394
  const storageKey = options.storageKey || DEFAULT_ACCOUNT_STORAGE_KEY;
341
395
  const preferStored = options.preferStored !== false;
@@ -1810,6 +1864,122 @@ async function authCentralUcanFetch(input, init = {}, options = {}) {
1810
1864
  });
1811
1865
  }
1812
1866
 
1867
+ /**
1868
+ * 加密/解密 SDK API
1869
+ *
1870
+ * 调用钱包插件的 `yeying_encrypt` / `yeying_decrypt` / `yeying_getCipherSuites`
1871
+ * EIP-1193 自定义方法。命名安全套件 + 静默执行 + 站点授权模型同 UCAN。
1872
+ *
1873
+ * 数据密码(password 参数)由 DApp 自行管理与钱包密码独立;
1874
+ * plaintext 走 base64 字符串跨 message 边界传输。
1875
+ */
1876
+ class CipherError extends Error {
1877
+ type;
1878
+ code;
1879
+ originalError;
1880
+ constructor(message, type, code, originalError) {
1881
+ super(message);
1882
+ this.name = 'CipherError';
1883
+ this.type = type;
1884
+ this.code = code;
1885
+ this.originalError = originalError;
1886
+ }
1887
+ }
1888
+ function wrapCipherError(err) {
1889
+ const info = classifyWalletError(err);
1890
+ throw new CipherError(info.message, info.type, info.code, err);
1891
+ }
1892
+ function bytesToBase64(bytes) {
1893
+ if (typeof Buffer !== 'undefined') {
1894
+ return Buffer.from(bytes).toString('base64');
1895
+ }
1896
+ let binary = '';
1897
+ for (let i = 0; i < bytes.length; i += 1) {
1898
+ binary += String.fromCharCode(bytes[i]);
1899
+ }
1900
+ return btoa(binary);
1901
+ }
1902
+ function base64ToBytes(b64) {
1903
+ if (typeof Buffer !== 'undefined') {
1904
+ return new Uint8Array(Buffer.from(b64, 'base64'));
1905
+ }
1906
+ const binary = atob(b64);
1907
+ const out = new Uint8Array(binary.length);
1908
+ for (let i = 0; i < binary.length; i += 1)
1909
+ out[i] = binary.charCodeAt(i);
1910
+ return out;
1911
+ }
1912
+ /**
1913
+ * 用指定/默认套件加密数据
1914
+ * @returns v1 格式密文 base64 字符串
1915
+ */
1916
+ async function encrypt(options) {
1917
+ const provider = options.provider || (await requireProvider());
1918
+ try {
1919
+ const result = await provider.request({
1920
+ method: 'yeying_encrypt',
1921
+ params: [{
1922
+ data: options.data,
1923
+ password: options.password,
1924
+ suite: options.suite
1925
+ }]
1926
+ });
1927
+ if (!result || typeof result !== 'object' || typeof result.ciphertext !== 'string') {
1928
+ throw new Error('Invalid encrypt response: missing ciphertext');
1929
+ }
1930
+ return result.ciphertext;
1931
+ }
1932
+ catch (err) {
1933
+ wrapCipherError(err);
1934
+ }
1935
+ }
1936
+ /**
1937
+ * 解密 v1 格式密文
1938
+ * @returns 明文 Uint8Array
1939
+ */
1940
+ async function decrypt(options) {
1941
+ const provider = options.provider || (await requireProvider());
1942
+ try {
1943
+ const result = await provider.request({
1944
+ method: 'yeying_decrypt',
1945
+ params: [{
1946
+ ciphertext: options.ciphertext,
1947
+ password: options.password
1948
+ }]
1949
+ });
1950
+ if (!result || typeof result !== 'object' || typeof result.plaintext !== 'string') {
1951
+ throw new Error('Invalid decrypt response: missing plaintext');
1952
+ }
1953
+ const { plaintext, encoding } = result;
1954
+ if (encoding && encoding !== 'base64') {
1955
+ throw new Error(`Unsupported plaintext encoding: ${encoding}`);
1956
+ }
1957
+ return base64ToBytes(plaintext);
1958
+ }
1959
+ catch (err) {
1960
+ wrapCipherError(err);
1961
+ }
1962
+ }
1963
+ /**
1964
+ * 列出可用的命名安全套件
1965
+ */
1966
+ async function getSupportedCipherSuites(options = {}) {
1967
+ const provider = options.provider || (await requireProvider());
1968
+ try {
1969
+ const result = await provider.request({
1970
+ method: 'yeying_getCipherSuites',
1971
+ params: []
1972
+ });
1973
+ if (!result || typeof result !== 'object' || !Array.isArray(result.suites)) {
1974
+ throw new Error('Invalid getCipherSuites response: missing suites array');
1975
+ }
1976
+ return result.suites;
1977
+ }
1978
+ catch (err) {
1979
+ wrapCipherError(err);
1980
+ }
1981
+ }
1982
+
1813
1983
  function normalizeBaseUrl(baseUrl) {
1814
1984
  return baseUrl.replace(/\/+$/, '');
1815
1985
  }
@@ -2355,5 +2525,5 @@ async function initDappSession(options) {
2355
2525
  return result;
2356
2526
  }
2357
2527
 
2358
- export { DEFAULT_UCAN_SESSION_TTL_MS, DEFAULT_UCAN_TOKEN_SKEW_MS, DEFAULT_UCAN_TOKEN_TTL_MS, WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, classifyUcanAuthError, classifyWalletError, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, decodeUcanPayload, deriveAppIdFromHost, deriveAppIdFromLocation, focusPendingApproval, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateInvocationUcan, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getUcanSession, getUcanTokenTiming, getWalletErrorCode, getWalletErrorMessage, initDappSession, initWebDavStorage, isUcanTokenFresh, isUserRejectedWalletAction, isWalletReconnectError, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeAppHostnameForAppId, normalizeUcanCapabilities, normalizeUcanCapability, normalizeUcanExpiry, onAccountsChanged, onChainChanged, refreshAccessToken, requestAccounts, requireProvider, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts, watchProvider };
2528
+ export { CipherError, DEFAULT_UCAN_SESSION_TTL_MS, DEFAULT_UCAN_TOKEN_SKEW_MS, DEFAULT_UCAN_TOKEN_TTL_MS, WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, base64ToBytes, bytesToBase64, classifyUcanAuthError, classifyWalletError, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, decodeUcanPayload, decrypt, deriveAppIdFromHost, deriveAppIdFromLocation, encrypt, focusPendingApproval, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateInvocationUcan, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getSupportedCipherSuites, getUcanSession, getUcanTokenTiming, getWalletErrorCode, getWalletErrorMessage, initDappSession, initWebDavStorage, isUcanTokenFresh, isUserRejectedWalletAction, isWalletReconnectError, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeAppHostnameForAppId, normalizeUcanCapabilities, normalizeUcanCapability, normalizeUcanExpiry, onAccountsChanged, onChainChanged, refreshAccessToken, requestAccounts, requireProvider, resolveWalletAccount, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts, watchProvider };
2359
2529
  //# sourceMappingURL=web3-bs.esm.js.map