@yeying-community/web3-bs 1.0.3 → 1.0.5

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.
@@ -6,11 +6,43 @@
6
6
 
7
7
  const YEYING_RDNS = 'io.github.yeying';
8
8
  const DEFAULT_TIMEOUT = 1000;
9
+ const DEFAULT_ACCOUNT_STORAGE_KEY = 'yeying:last_account';
9
10
  function getWindowEthereum() {
10
11
  if (typeof window === 'undefined')
11
12
  return null;
12
13
  return window.ethereum || null;
13
14
  }
15
+ function readStoredAccount(storageKey) {
16
+ if (typeof localStorage === 'undefined')
17
+ return null;
18
+ try {
19
+ return localStorage.getItem(storageKey);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ function writeStoredAccount(storageKey, account) {
26
+ if (typeof localStorage === 'undefined')
27
+ return;
28
+ try {
29
+ if (account) {
30
+ localStorage.setItem(storageKey, account);
31
+ }
32
+ else {
33
+ localStorage.removeItem(storageKey);
34
+ }
35
+ }
36
+ catch {
37
+ // ignore storage errors
38
+ }
39
+ }
40
+ function selectPreferredAccount(accounts, stored, preferStored) {
41
+ if (preferStored && stored && accounts.includes(stored)) {
42
+ return stored;
43
+ }
44
+ return accounts[0] || null;
45
+ }
14
46
  function isYeYingProvider(provider, info) {
15
47
  if (!provider)
16
48
  return false;
@@ -116,6 +148,29 @@
116
148
  const chainId = (await p.request({ method: 'eth_chainId' }));
117
149
  return typeof chainId === 'string' ? chainId : null;
118
150
  }
151
+ async function getPreferredAccount(options = {}) {
152
+ const provider = options.provider || (await requireProvider());
153
+ const storageKey = options.storageKey || DEFAULT_ACCOUNT_STORAGE_KEY;
154
+ const preferStored = options.preferStored !== false;
155
+ let accounts = await getAccounts(provider);
156
+ if (accounts.length === 0 && options.autoConnect) {
157
+ accounts = await requestAccounts({ provider });
158
+ }
159
+ const stored = readStoredAccount(storageKey);
160
+ const account = selectPreferredAccount(accounts, stored, preferStored);
161
+ writeStoredAccount(storageKey, account);
162
+ return { account, accounts };
163
+ }
164
+ function watchAccounts(provider, handler, options = {}) {
165
+ const storageKey = options.storageKey || DEFAULT_ACCOUNT_STORAGE_KEY;
166
+ const preferStored = options.preferStored !== false;
167
+ return onAccountsChanged(provider, (accounts) => {
168
+ const stored = readStoredAccount(storageKey);
169
+ const account = selectPreferredAccount(accounts, stored, preferStored);
170
+ writeStoredAccount(storageKey, account);
171
+ handler({ account, accounts });
172
+ });
173
+ }
119
174
  async function getBalance(provider, address, blockTag = 'latest') {
120
175
  const p = provider || (await requireProvider());
121
176
  let target = address;
@@ -714,8 +769,8 @@
714
769
  const session = options.session || (await createUcanSession({ id: options.sessionId, provider }));
715
770
  const address = await resolveAddress(provider, options.address);
716
771
  const chainId = options.chainId || (await getChainId(provider)) || '1';
717
- const domain = options.domain || (typeof window !== 'undefined' ? window.location.host : 'localhost');
718
- const uri = options.uri || (typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
772
+ const domain = options.domain || (typeof window !== 'undefined' ? window.location.host : '127.0.0.1');
773
+ const uri = options.uri || (typeof window !== 'undefined' ? window.location.origin : 'http://127.0.0.1');
719
774
  const nonce = options.nonce || randomNonce(8);
720
775
  const exp = normalizeExpiry(undefined, options.expiresInMs ?? DEFAULT_SESSION_TTL);
721
776
  const nbf = options.notBeforeMs;
@@ -1064,6 +1119,7 @@
1064
1119
 
1065
1120
  const tokenCache = new Map();
1066
1121
  const TOKEN_SKEW_MS = 5000;
1122
+ const DEFAULT_APP_ACTION = 'write';
1067
1123
  function normalizeAppDir(path) {
1068
1124
  const trimmed = path.trim();
1069
1125
  if (!trimmed)
@@ -1075,6 +1131,42 @@
1075
1131
  function sanitizeAppId(appId) {
1076
1132
  return appId.trim().replace(/[^a-zA-Z0-9._-]/g, '-');
1077
1133
  }
1134
+ function normalizeAction(action) {
1135
+ const trimmed = (action || '').trim();
1136
+ return trimmed ? trimmed : null;
1137
+ }
1138
+ function buildAppCapability(options) {
1139
+ if (!options.appId)
1140
+ return null;
1141
+ const action = normalizeAction(options.appAction) || DEFAULT_APP_ACTION;
1142
+ return {
1143
+ resource: `app:${sanitizeAppId(options.appId)}`,
1144
+ action,
1145
+ };
1146
+ }
1147
+ function hasAppCapability(caps) {
1148
+ return (caps || []).some(cap => typeof cap?.resource === 'string' && cap.resource.startsWith('app:'));
1149
+ }
1150
+ function dedupeCapabilities(caps) {
1151
+ const seen = new Set();
1152
+ return (caps || []).filter(cap => {
1153
+ if (!cap || !cap.resource || !cap.action)
1154
+ return false;
1155
+ const key = `${cap.resource}|${cap.action}`;
1156
+ if (seen.has(key))
1157
+ return false;
1158
+ seen.add(key);
1159
+ return true;
1160
+ });
1161
+ }
1162
+ function ensureAppCapability(caps, options) {
1163
+ const appCap = buildAppCapability(options);
1164
+ if (!appCap)
1165
+ return caps || [];
1166
+ if (hasAppCapability(caps || []))
1167
+ return caps || [];
1168
+ return dedupeCapabilities([...(caps || []), appCap]);
1169
+ }
1078
1170
  function resolveAppDir(options) {
1079
1171
  if (options.appDir) {
1080
1172
  return normalizeAppDir(options.appDir);
@@ -1090,6 +1182,14 @@
1090
1182
  function buildTokenCacheKey(issuer, audience, caps) {
1091
1183
  return `${issuer.did}|${audience}|${buildCapsKey(caps)}`;
1092
1184
  }
1185
+ function resolveWebdavCaps(options) {
1186
+ const baseCaps = options.capabilities || options.root?.cap || [];
1187
+ return ensureAppCapability(baseCaps, options);
1188
+ }
1189
+ function resolveInvocationCaps(options, fallbackCaps) {
1190
+ const caps = options.invocationCapabilities || fallbackCaps;
1191
+ return ensureAppCapability(caps, options);
1192
+ }
1093
1193
  function isTokenValid(entry, nowMs) {
1094
1194
  if (!entry.exp)
1095
1195
  return false;
@@ -1161,7 +1261,7 @@
1161
1261
  return token;
1162
1262
  }
1163
1263
  async function initWebDavStorage(options) {
1164
- const caps = options.capabilities || options.root?.cap;
1264
+ const caps = resolveWebdavCaps(options);
1165
1265
  if (!caps || caps.length === 0) {
1166
1266
  throw new Error('Missing UCAN capabilities for WebDAV');
1167
1267
  }
@@ -1191,7 +1291,7 @@
1191
1291
  expiresInMs: options.rootExpiresInMs,
1192
1292
  });
1193
1293
  }
1194
- const invocationCaps = options.invocationCapabilities || caps;
1294
+ const invocationCaps = resolveInvocationCaps(options, caps);
1195
1295
  const token = await getCachedInvocationToken({
1196
1296
  issuer: session,
1197
1297
  audience: options.audience,
@@ -1269,6 +1369,7 @@
1269
1369
  exports.getBalance = getBalance;
1270
1370
  exports.getChainId = getChainId;
1271
1371
  exports.getOrCreateUcanRoot = getOrCreateUcanRoot;
1372
+ exports.getPreferredAccount = getPreferredAccount;
1272
1373
  exports.getProvider = getProvider;
1273
1374
  exports.getStoredUcanRoot = getStoredUcanRoot;
1274
1375
  exports.getUcanSession = getUcanSession;
@@ -1285,6 +1386,7 @@
1285
1386
  exports.setAccessToken = setAccessToken;
1286
1387
  exports.signMessage = signMessage;
1287
1388
  exports.storeUcanRoot = storeUcanRoot;
1389
+ exports.watchAccounts = watchAccounts;
1288
1390
 
1289
1391
  }));
1290
1392
  //# sourceMappingURL=web3-bs.umd.js.map