@yeying-community/web3-bs 1.0.5 → 1.0.7

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
@@ -1,13 +1,14 @@
1
- # YeYing Inject Wallet SDK
1
+ # YeYing Browser DApp Access SDK
2
2
 
3
- 轻量级注入钱包 SDK,专注浏览器端 EIP-1193 Provider。默认优先选择 YeYing Wallet(支持 EIP-6963 多钱包发现)。
4
- 仅支持浏览器环境(依赖 `window` / `localStorage` / `fetch`)。
3
+ `web3-bs` 是浏览器端 DApp 接入 SDK,用于统一封装:
4
+
5
+ - 钱包连接(EIP-1193 / EIP-6963)
6
+ - SIWE challenge 登录与 JWT 鉴权请求
7
+ - UCAN 多后端授权(钱包 UCAN RPC 优先,失败可回退本地 Ed25519 session)
8
+ - 中心化 UCAN 发行服务接入
9
+ - WebDAV 文件访问与应用目录初始化
5
10
 
6
- 功能要点:
7
- - 浏览器端 EIP-1193 Provider 辅助库
8
- - 默认优先 YeYing Wallet
9
- - 内置 `signMessage` / `loginWithChallenge` / `refresh` / `logout` 等方法
10
- - 支持 UCAN Session + SIWE Bridge,用于多后端授权
11
+ 仅支持浏览器环境(依赖 `window` / `localStorage` / `fetch`)。
11
12
 
12
13
  ## 安装
13
14
 
@@ -15,68 +16,112 @@
15
16
  npm install @yeying-community/web3-bs
16
17
  ```
17
18
 
18
- 更多集成与流程说明见 `docs/sdk-design.md`。
19
+ ## 能力概览
19
20
 
20
- ## 示例
21
+ ### 1) Provider 与账户
21
22
 
22
- - Frontend Dapp (HTML): `examples/frontend/dapp.html`
23
- - Frontend Dapp (TS module): `examples/frontend/main.ts`
24
- - Backend server (Node): `examples/backend/node/server.js`
25
- - Backend server (Go): `examples/backend/go/main.go`
26
- - Backend server (Python): `examples/backend/python/app.py`
27
- - Backend server (Java): `examples/backend/java/src/main/java/com/yeying/demo/AuthServer.java`
23
+ - `getProvider` / `requireProvider`
24
+ - `requestAccounts` / `getAccounts` / `getPreferredAccount` / `watchAccounts`
25
+ - `getChainId` / `getBalance`
26
+ - `onAccountsChanged` / `onChainChanged`
28
27
 
29
- ## 本地验证
28
+ ### 2) SIWE + JWT
30
29
 
31
- 1. 构建 SDK:`npm run build`
32
- 2. 启动后端:`scripts/backend.sh start node`(将 `node` 替换为 `go` / `python` / `java`)
33
- 3. 启动前端:`python3 -m http.server 8001 --bind 127.0.0.1`
34
- 4. 访问:`http://127.0.0.1:8001/examples/frontend/dapp.html`
35
- 5. 确保安装 YeYing 钱包扩展插件
36
- 6. 点击:`Detect Provider` `Connect Wallet` `Login`
30
+ - `signMessage`
31
+ - `loginWithChallenge`
32
+ - `authFetch`
33
+ - `refreshAccessToken`
34
+ - `logout`
35
+ - `getAccessToken` / `setAccessToken` / `clearAccessToken`
37
36
 
38
- 提示:如果前端来自其他域名,请设置
39
- `COOKIE_SAMESITE=none` 且 `COOKIE_SECURE=true` 并使用 HTTPS,
40
- 以便 `refresh_token` Cookie 能随 `credentials: 'include'` 发送。
37
+ ### 3) UCAN(钱包优先 + 本地回退)
41
38
 
42
- ## 后端脚本用法
39
+ - `createUcanSession` / `getUcanSession`
40
+ - `getOrCreateUcanRoot` / `createRootUcan`
41
+ - `createDelegationUcan` / `createInvocationUcan`
42
+ - `authUcanFetch`
43
+ - `normalizeUcanCapabilities`
43
44
 
44
- 通用格式:
45
- `./scripts/backend.sh <start|stop|restart|status> <node|go|python|java|all> [--setup] [--no-stop]`
45
+ 说明:
46
+ - 能调用 `yeying_ucan_session` / `yeying_ucan_sign` 时,优先用钱包侧 UCAN session 签名。
47
+ - 不支持上述钱包 RPC 时,SDK 会回退到浏览器本地 Ed25519 session(IndexedDB 持久化)。
46
48
 
47
- 示例:
48
- ```bash
49
- # 启动 Node 后端
50
- ./scripts/backend.sh start node
49
+ ### 4) 中心化 UCAN
50
+
51
+ - `getCentralIssuerInfo`
52
+ - `createCentralSession`
53
+ - `issueCentralUcan`
54
+ - `createAndIssueCentralUcan`
55
+ - `authCentralUcanFetch`
56
+ - `getCentralSessionToken` / `setCentralSessionToken` / `clearCentralSessionToken`
51
57
 
52
- # 启动 Go 后端并安装依赖/构建
53
- ./scripts/backend.sh start go --setup
58
+ ### 5) WebDAV 与 DApp 会话编排
54
59
 
55
- # 查看全部后端状态
56
- ./scripts/backend.sh status all
60
+ - `createWebDavClient`
61
+ - `initWebDavStorage`(自动生成/复用 WebDAV Invocation UCAN,可自动创建应用目录)
62
+ - `initDappSession`(SIWE 登录 + WebDAV UCAN 初始化)
63
+ - `deriveAppIdFromLocation` / `deriveAppIdFromHost`
57
64
 
58
- # 重启 Python 后端
59
- ./scripts/backend.sh restart python
65
+ ## 常见接入方式
60
66
 
61
- # 停止所有后端
62
- ./scripts/backend.sh stop all
67
+ ### 单后端登录(SIWE + JWT)
63
68
 
64
- # 同时启动多个后端(不停止已运行的服务)
65
- ./scripts/backend.sh start all --no-stop
69
+ ```ts
70
+ import { loginWithChallenge, authFetch } from '@yeying-community/web3-bs';
71
+
72
+ await loginWithChallenge({
73
+ baseUrl: 'http://localhost:3203/api/v1/public/auth',
74
+ storeToken: false,
75
+ });
76
+
77
+ const res = await authFetch(
78
+ 'http://localhost:3203/api/v1/public/profile',
79
+ { method: 'GET' },
80
+ { baseUrl: 'http://localhost:3203/api/v1/public/auth', storeToken: false }
81
+ );
66
82
  ```
67
83
 
68
- 说明:
69
- - 日志位于 `.tmp/backend-logs`
70
- - 进程 PID 位于 `.tmp/backend-pids`
71
- - 可通过环境变量传递端口/秘钥/TTL 等配置(如 `PORT`、`JWT_SECRET` 等)
84
+ ### 多后端 UCAN + WebDAV
85
+
86
+ ```ts
87
+ import { initWebDavStorage, deriveAppIdFromLocation } from '@yeying-community/web3-bs';
88
+
89
+ const appId = deriveAppIdFromLocation(window.location) || 'localhost-8001';
90
+ const webdav = await initWebDavStorage({
91
+ baseUrl: 'http://localhost:6065',
92
+ audience: 'did:web:localhost:6065',
93
+ appId,
94
+ capabilities: [{ with: `app:all:${appId}`, can: 'write' }],
95
+ });
96
+
97
+ await webdav.client.upload(`${webdav.appDir}/hello.txt`, 'Hello WebDAV');
98
+ ```
72
99
 
73
- ## 多后端联调(不同端口)
100
+ ## Demo
74
101
 
75
- 可同时启动多语言后端(不同端口),验证 UCAN 多后端授权:
102
+ - 前端 Demo(双 Tab:单后端 SIWE / 多后端 UCAN+WebDAV):
103
+ `examples/frontend/dapp.html`
104
+ - 前端 TS 示例:`examples/frontend/main.ts`
105
+ - 多语言后端示例:
106
+ - Node: `examples/backend/node/server.js`
107
+ - Go: `examples/backend/go/main.go`
108
+ - Java: `examples/backend/java/src/main/java/com/yeying/demo/AuthServer.java`
109
+ - Python: `examples/backend/python/app.py`
110
+
111
+ ## 本地联调
112
+
113
+ 1. 构建 SDK:`npm run build`
114
+ 2. 启动后端(示例):
115
+ `./scripts/backend.sh start nodejs`
116
+ 3. 启动前端:
117
+ `python3 -m http.server 8001 --bind 127.0.0.1`
118
+ 4. 打开:
119
+ `http://127.0.0.1:8001/examples/frontend/dapp.html`
120
+
121
+ 多后端联调:
76
122
 
77
123
  ```bash
78
124
  ./scripts/backend.sh start all
79
- ./scripts/backend.sh start all --setup
80
125
  ```
81
126
 
82
127
  默认端口:
@@ -85,37 +130,28 @@ npm install @yeying-community/web3-bs
85
130
  - Node `3203`
86
131
  - Python `3204`
87
132
 
88
- 前端调用不同端口的后端时:
89
- - 将前端 Origin 加入 `CORS_ORIGINS`(例如 `http://127.0.0.1:3203`)
90
- - UCAN 调用的 `audience` 与后端 `UCAN_AUD` 一致(如 `did:web:127.0.0.1:3202`)
91
-
92
- 提示:`examples/frontend/dapp.html` 已内置多后端列表,可在一次 UCAN 授权后依次调用多个服务。
93
-
94
- ## 常见问题
95
-
96
- ### 刷新token失败
133
+ ## CORS 注意事项
97
134
 
98
- 清理旧 Cookie 后重新登录:在浏览器 DevTools → Application → Cookies → http://127.0.0.1:8001 删除 refresh_token,再点 Login 后再点 Refresh Token
135
+ 若你用 `http://[::]:8001` 打开页面,请确保后端 CORS 白名单包含该 Origin
136
+ 建议统一加入:
99
137
 
100
- ### WebDAV 提示 invalid token
101
-
102
- 报错示例:`authentication failed` / `invalid token`(通常来自 WebDAV 服务端鉴权中间件)。
138
+ ```bash
139
+ CORS_ORIGINS=http://localhost:8001,http://127.0.0.1:8001,http://[::]:8001
140
+ ```
103
141
 
104
- 排查与解决:
105
- - 确认 `baseUrl` 指向 WebDAV 服务(默认 `http://127.0.0.1:6065`),不要误用 320x 认证后端。
106
- - `audience` 必须与 WebDAV 服务端 `UCAN_AUD` 一致(例如 `did:web:127.0.0.1:6065`)。
107
- - `capabilities` 与服务端要求一致(`UCAN_RESOURCE` / `UCAN_ACTION`)。
108
- - Token 过期或缓存异常时,清理 UCAN 会话并重新登录/生成 Root + Invocation。
142
+ ## 本地软链接(开发)
109
143
 
110
- ### UCAN audience mismatch
144
+ 将本仓库作为本地依赖链接到你的 DApp:
111
145
 
112
- 日志示例:
113
- ```
114
- [2026-01-31T05:19:44.478Z] UCAN profile failed { error: 'UCAN audience mismatch' }
146
+ ```bash
147
+ mkdir -p /path/to/your-dapp/node_modules/@yeying-community
148
+ ln -s /path/to/web3-bs /path/to/your-dapp/node_modules/@yeying-community/web3-bs
115
149
  ```
116
150
 
117
- 解决思路:
118
- - 生成 UCAN 时的 `audience` 必须与目标后端的 `UCAN_AUD` 完全一致。
119
- - 例如 Node 后端:`did:web:127.0.0.1:3203`
120
- - 例如 WebDAV 服务:`did:web:127.0.0.1:6065`
121
- - 多后端联调时,确保每个后端使用对应的 `audience` 生成 Invocation UCAN。
151
+ ## 文档导航
152
+
153
+ - [文档导航](./docs/文档导航.md)
154
+ - [快速上手](./docs/快速上手.md)
155
+ - [SDK能力](./docs/SDK能力.md)
156
+ - [移动端认证与授权选型指南](./docs/移动端认证与授权选型指南.md)
157
+ - [接口规范(OpenAPI)](./docs/开放接口规范.yaml)
@@ -0,0 +1,77 @@
1
+ import type { AuthBaseOptions } from './types';
2
+ import { type UcanCapability } from './ucan';
3
+ export type CentralAuthBaseOptions = AuthBaseOptions & {
4
+ baseUrl?: string;
5
+ issuerPath?: string;
6
+ sessionPath?: string;
7
+ issuePath?: string;
8
+ accessToken?: string | null;
9
+ storeSessionToken?: boolean;
10
+ sessionTokenStorageKey?: string;
11
+ };
12
+ export type CentralIssuerInfo = {
13
+ enabled?: boolean;
14
+ issuerDid?: string;
15
+ defaultAudience?: string;
16
+ defaultCapabilities?: UcanCapability[];
17
+ response: unknown;
18
+ };
19
+ export type CreateCentralSessionOptions = CentralAuthBaseOptions & {
20
+ subject: string;
21
+ sessionTtlMs?: number;
22
+ };
23
+ export type CentralSessionResult = {
24
+ subject: string;
25
+ sessionToken: string;
26
+ expiresAt?: number;
27
+ issuerDid?: string;
28
+ response: unknown;
29
+ };
30
+ export type IssueCentralUcanOptions = CentralAuthBaseOptions & {
31
+ sessionToken?: string | null;
32
+ audience?: string;
33
+ capabilities?: UcanCapability[];
34
+ expiresInMs?: number;
35
+ ttlMs?: number;
36
+ };
37
+ export type CentralUcanIssueResult = {
38
+ ucan: string;
39
+ issuerDid?: string;
40
+ subject?: string;
41
+ audience?: string;
42
+ capabilities?: UcanCapability[];
43
+ exp?: number;
44
+ nbf?: number;
45
+ iat?: number;
46
+ response: unknown;
47
+ };
48
+ export type CreateAndIssueCentralUcanOptions = CentralAuthBaseOptions & {
49
+ subject: string;
50
+ sessionTtlMs?: number;
51
+ audience?: string;
52
+ capabilities?: UcanCapability[];
53
+ expiresInMs?: number;
54
+ ttlMs?: number;
55
+ };
56
+ export type CreateAndIssueCentralUcanResult = {
57
+ session: CentralSessionResult;
58
+ issue: CentralUcanIssueResult;
59
+ };
60
+ export type AuthCentralUcanFetchOptions = CentralAuthBaseOptions & {
61
+ ucan?: string | null;
62
+ sessionToken?: string | null;
63
+ subject?: string;
64
+ sessionTtlMs?: number;
65
+ audience?: string;
66
+ capabilities?: UcanCapability[];
67
+ expiresInMs?: number;
68
+ ttlMs?: number;
69
+ };
70
+ export declare function getCentralSessionToken(options?: CentralAuthBaseOptions): string | null;
71
+ export declare function setCentralSessionToken(token: string | null, options?: CentralAuthBaseOptions): void;
72
+ export declare function clearCentralSessionToken(options?: CentralAuthBaseOptions): void;
73
+ export declare function getCentralIssuerInfo(options?: CentralAuthBaseOptions): Promise<CentralIssuerInfo>;
74
+ export declare function createCentralSession(options: CreateCentralSessionOptions): Promise<CentralSessionResult>;
75
+ export declare function issueCentralUcan(options?: IssueCentralUcanOptions): Promise<CentralUcanIssueResult>;
76
+ export declare function createAndIssueCentralUcan(options: CreateAndIssueCentralUcanOptions): Promise<CreateAndIssueCentralUcanResult>;
77
+ export declare function authCentralUcanFetch(input: RequestInfo | URL, init?: RequestInit, options?: AuthCentralUcanFetchOptions): Promise<Response>;
@@ -2,3 +2,4 @@ export * from './types';
2
2
  export * from './provider';
3
3
  export * from './siwe';
4
4
  export * from './ucan';
5
+ export * from './central';
@@ -1,7 +1,10 @@
1
1
  import { Eip1193Provider } from './types';
2
2
  export type UcanCapability = {
3
- resource: string;
4
- action: string;
3
+ with?: string;
4
+ can?: string;
5
+ resource?: string;
6
+ action?: string;
7
+ nb?: unknown;
5
8
  };
6
9
  export type UcanRootProof = {
7
10
  type: 'siwe';
@@ -24,11 +27,15 @@ export type UcanTokenPayload = {
24
27
  nbf?: number;
25
28
  prf: UcanProof[];
26
29
  };
30
+ export type UcanSessionSource = 'wallet' | 'local';
27
31
  export type UcanSessionRecord = {
28
32
  id: string;
29
33
  did: string;
30
34
  createdAt: number;
31
35
  expiresAt: number | null;
36
+ source?: UcanSessionSource;
37
+ privateKeyJwk?: JsonWebKey;
38
+ publicKeyJwk?: JsonWebKey;
32
39
  root?: UcanRootProof;
33
40
  };
34
41
  export type UcanSessionKey = {
@@ -36,6 +43,7 @@ export type UcanSessionKey = {
36
43
  did: string;
37
44
  createdAt: number;
38
45
  expiresAt: number | null;
46
+ source?: UcanSessionSource;
39
47
  signer?: (signingInput: string, payload: UcanTokenPayload) => Promise<string>;
40
48
  privateKey?: CryptoKey;
41
49
  };
@@ -81,6 +89,14 @@ export type UcanFetchOptions = {
81
89
  notBeforeMs?: number;
82
90
  fetcher?: typeof fetch;
83
91
  };
92
+ export declare function getCapabilityResource(cap: UcanCapability | null | undefined): string;
93
+ export declare function getCapabilityAction(cap: UcanCapability | null | undefined): string;
94
+ export declare function normalizeUcanCapability(cap: UcanCapability | null | undefined, options?: {
95
+ includeLegacyAliases?: boolean;
96
+ }): UcanCapability | null;
97
+ export declare function normalizeUcanCapabilities(caps: UcanCapability[] | undefined, options?: {
98
+ includeLegacyAliases?: boolean;
99
+ }): UcanCapability[];
84
100
  export declare function getUcanSession(id?: string, provider?: Eip1193Provider): Promise<UcanSessionKey | null>;
85
101
  export declare function createUcanSession(options?: CreateUcanSessionOptions): Promise<UcanSessionKey>;
86
102
  export declare function clearUcanSession(id?: string): Promise<void>;
package/dist/dapp.d.ts CHANGED
@@ -45,5 +45,13 @@ export type InitDappSessionResult = {
45
45
  webdavToken?: string;
46
46
  webdavAppDir?: string;
47
47
  };
48
+ export type AppIdLocationLike = {
49
+ host?: string | null;
50
+ hostname?: string | null;
51
+ port?: string | number | null;
52
+ };
53
+ export declare function normalizeAppHostnameForAppId(hostname: string): string;
54
+ export declare function deriveAppIdFromHost(host: string): string;
55
+ export declare function deriveAppIdFromLocation(locationLike?: AppIdLocationLike): string;
48
56
  export declare function initWebDavStorage(options: InitWebDavStorageOptions): Promise<InitWebDavStorageResult>;
49
57
  export declare function initDappSession(options: InitDappSessionOptions): Promise<InitDappSessionResult>;