@yeying-community/web3-bs 1.0.6 → 1.0.8
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 +132 -106
- package/dist/auth/central.d.ts +1 -0
- package/dist/dapp.d.ts +8 -0
- package/dist/storage/webdav.d.ts +39 -0
- package/dist/web3-bs.esm.js +176 -14
- package/dist/web3-bs.esm.js.map +1 -1
- package/dist/web3-bs.umd.js +178 -13
- package/dist/web3-bs.umd.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
# YeYing Browser DApp Access SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
它优先面向 EIP-1193 / EIP-6963 钱包生态,可对接 YeYing、MetaMask 等浏览器钱包;也可对接能暴露 EIP-1193 能力的 App 钱包或中心化认证服务。仅支持浏览器环境(依赖 `window` / `localStorage` / `fetch`)。
|
|
3
|
+
`web3-bs` 是浏览器端 DApp 接入 SDK,用于统一封装:
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
- 钱包连接(EIP-1193 / EIP-6963)
|
|
6
|
+
- SIWE challenge 登录与 JWT 鉴权请求
|
|
7
|
+
- UCAN 多后端授权(钱包 UCAN RPC 优先,失败可回退本地 Ed25519 session)
|
|
8
|
+
- 中心化 UCAN 发行服务接入
|
|
9
|
+
- WebDAV 文件访问与应用目录初始化
|
|
10
|
+
|
|
11
|
+
仅支持浏览器环境(依赖 `window` / `localStorage` / `fetch`)。
|
|
13
12
|
|
|
14
13
|
## 安装
|
|
15
14
|
|
|
@@ -17,140 +16,167 @@
|
|
|
17
16
|
npm install @yeying-community/web3-bs
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
推荐先读:
|
|
22
|
-
- `docs/README.md`
|
|
23
|
-
- `docs/positioning.md`
|
|
24
|
-
- `docs/quickstart.md`
|
|
25
|
-
- `docs/capability-matrix.md`
|
|
19
|
+
## 能力概览
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
### 1) Provider 与账户
|
|
28
22
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
23
|
+
- `getProvider` / `requireProvider`
|
|
24
|
+
- `requestAccounts` / `getAccounts` / `getPreferredAccount` / `watchAccounts`
|
|
25
|
+
- `getChainId` / `getBalance`
|
|
26
|
+
- `onAccountsChanged` / `onChainChanged`
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
### 2) SIWE + JWT
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
- `signMessage`
|
|
31
|
+
- `loginWithChallenge`
|
|
32
|
+
- `authFetch`
|
|
33
|
+
- `refreshAccessToken`
|
|
34
|
+
- `logout`
|
|
35
|
+
- `getAccessToken` / `setAccessToken` / `clearAccessToken`
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
- Frontend Mobile Central UCAN Demo: `examples/frontend/mobile-central-ucan.html`
|
|
39
|
-
- Frontend Dapp (TS module): `examples/frontend/main.ts`
|
|
40
|
-
- Backend server (Node): `examples/backend/node/server.js`
|
|
41
|
-
- Backend server (Go): `examples/backend/go/main.go`
|
|
42
|
-
- Backend server (Python): `examples/backend/python/app.py`
|
|
43
|
-
- Backend server (Java): `examples/backend/java/src/main/java/com/yeying/demo/AuthServer.java`
|
|
37
|
+
### 3) UCAN(钱包优先 + 本地回退)
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
- `createUcanSession` / `getUcanSession`
|
|
40
|
+
- `getOrCreateUcanRoot` / `createRootUcan`
|
|
41
|
+
- `createDelegationUcan` / `createInvocationUcan`
|
|
42
|
+
- `authUcanFetch`
|
|
43
|
+
- `normalizeUcanCapabilities`
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
4. 访问:`http://127.0.0.1:8001/examples/frontend/dapp.html`
|
|
51
|
-
5. 确保安装 YeYing 钱包扩展插件
|
|
52
|
-
6. 点击:`Detect Provider` → `Connect Wallet` → `Login`
|
|
45
|
+
说明:
|
|
46
|
+
- 能调用 `yeying_ucan_session` / `yeying_ucan_sign` 时,优先用钱包侧 UCAN session 签名。
|
|
47
|
+
- 不支持上述钱包 RPC 时,SDK 会回退到浏览器本地 Ed25519 session(IndexedDB 持久化)。
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
`COOKIE_SAMESITE=none` 且 `COOKIE_SECURE=true` 并使用 HTTPS,
|
|
56
|
-
以便 `refresh_token` Cookie 能随 `credentials: 'include'` 发送。
|
|
49
|
+
### 4) 中心化 UCAN
|
|
57
50
|
|
|
58
|
-
|
|
51
|
+
- `getCentralIssuerInfo`
|
|
52
|
+
- `createCentralSession`
|
|
53
|
+
- `issueCentralUcan`
|
|
54
|
+
- `createAndIssueCentralUcan`
|
|
55
|
+
- `authCentralUcanFetch`
|
|
56
|
+
- `getCentralSessionToken` / `setCentralSessionToken` / `clearCentralSessionToken`
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
`./scripts/backend.sh <start|stop|restart|status> <node|go|python|java|all> [--setup] [--no-stop]`
|
|
58
|
+
### 5) WebDAV 与 DApp 会话编排
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
- `createWebDavClient`
|
|
61
|
+
- `initWebDavStorage`(自动生成/复用 WebDAV Invocation UCAN,可自动创建应用目录)
|
|
62
|
+
- `createShareLink` / `listShareLinks` / `revokeShareLink`(公开分享链接管理)
|
|
63
|
+
- `initDappSession`(SIWE 登录 + WebDAV UCAN 初始化)
|
|
64
|
+
- `deriveAppIdFromLocation` / `deriveAppIdFromHost`
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
./scripts/backend.sh start go --setup
|
|
66
|
+
## 常见接入方式
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
./scripts/backend.sh status all
|
|
68
|
+
### 单后端登录(SIWE + JWT)
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
```ts
|
|
71
|
+
import { loginWithChallenge, authFetch } from '@yeying-community/web3-bs';
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
await loginWithChallenge({
|
|
74
|
+
baseUrl: 'http://localhost:3203/api/v1/public/auth',
|
|
75
|
+
storeToken: false,
|
|
76
|
+
});
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const res = await authFetch(
|
|
79
|
+
'http://localhost:3203/api/v1/public/profile',
|
|
80
|
+
{ method: 'GET' },
|
|
81
|
+
{ baseUrl: 'http://localhost:3203/api/v1/public/auth', storeToken: false }
|
|
82
|
+
);
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
- 日志位于 `.tmp/backend-logs`
|
|
86
|
-
- 进程 PID 位于 `.tmp/backend-pids`
|
|
87
|
-
- 可通过环境变量传递端口/秘钥/TTL 等配置(如 `PORT`、`JWT_SECRET` 等)
|
|
85
|
+
### 多后端 UCAN + WebDAV
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
```ts
|
|
88
|
+
import { initWebDavStorage, deriveAppIdFromLocation } from '@yeying-community/web3-bs';
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
const appId = deriveAppIdFromLocation(window.location) || 'localhost-8001';
|
|
91
|
+
const webdav = await initWebDavStorage({
|
|
92
|
+
baseUrl: 'http://localhost:6065',
|
|
93
|
+
audience: 'did:web:localhost:6065',
|
|
94
|
+
appId,
|
|
95
|
+
capabilities: [{ with: `app:all:${appId}`, can: 'write' }],
|
|
96
|
+
});
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
./scripts/backend.sh start all
|
|
95
|
-
./scripts/backend.sh start all --setup
|
|
98
|
+
await webdav.client.upload(`${webdav.appDir}/hello.txt`, 'Hello WebDAV');
|
|
96
99
|
```
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
- Go `3201`
|
|
100
|
-
- Java `3202`
|
|
101
|
-
- Node `3203`
|
|
102
|
-
- Python `3204`
|
|
101
|
+
### WebDAV 分享链接(warehouse)
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- UCAN 调用的 `audience` 与后端 `UCAN_AUD` 一致(如 `did:web:127.0.0.1:3202`)
|
|
103
|
+
```ts
|
|
104
|
+
import { createWebDavClient } from '@yeying-community/web3-bs';
|
|
107
105
|
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const client = createWebDavClient({
|
|
107
|
+
baseUrl: 'http://localhost:6065',
|
|
108
|
+
token: '<JWT_OR_UCAN>',
|
|
109
|
+
});
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
// expiresValue = 0 表示长期(不过期)分享链接
|
|
112
|
+
const share = await client.createShareLink({
|
|
113
|
+
path: '/apps/demo/hello.txt',
|
|
114
|
+
expiresValue: 0,
|
|
115
|
+
expiresUnit: 'day',
|
|
116
|
+
});
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
console.log(share.url);
|
|
119
|
+
```
|
|
114
120
|
|
|
115
|
-
|
|
121
|
+
分享链接权限边界(warehouse 当前实现):
|
|
122
|
+
- 使用 UCAN 且 capability 带 `app` scope(如 `app:all:<appId>`)时,`createShareLink` / `listShareLinks` 仅允许授权目录内的文件路径。
|
|
123
|
+
- 使用 JWT(或未携带 UCAN `app` scope)时,不会自动套用上述目录过滤,最终范围由后端鉴权策略决定。
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
npm run check:capabilities
|
|
119
|
-
```
|
|
125
|
+
## Demo
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
- `
|
|
126
|
-
-
|
|
127
|
+
- 前端 Demo(双 Tab:单后端 SIWE / 多后端 UCAN+WebDAV):
|
|
128
|
+
`examples/frontend/dapp.html`
|
|
129
|
+
- 前端 TS 示例:`examples/frontend/main.ts`
|
|
130
|
+
- 多语言后端示例:
|
|
131
|
+
- Node: `examples/backend/node/server.js`
|
|
132
|
+
- Go: `examples/backend/go/main.go`
|
|
133
|
+
- Java: `examples/backend/java/src/main/java/com/yeying/demo/AuthServer.java`
|
|
134
|
+
- Python: `examples/backend/python/app.py`
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
## 本地联调
|
|
129
137
|
|
|
130
|
-
|
|
138
|
+
1. 构建 SDK:`npm run build`
|
|
139
|
+
2. 启动后端(示例):
|
|
140
|
+
`./scripts/backend.sh start nodejs`
|
|
141
|
+
3. 启动前端:
|
|
142
|
+
`python3 -m http.server 8001 --bind 127.0.0.1`
|
|
143
|
+
4. 打开:
|
|
144
|
+
`http://127.0.0.1:8001/examples/frontend/dapp.html`
|
|
131
145
|
|
|
132
|
-
|
|
146
|
+
多后端联调:
|
|
133
147
|
|
|
134
|
-
|
|
148
|
+
```bash
|
|
149
|
+
./scripts/backend.sh start all
|
|
150
|
+
```
|
|
135
151
|
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
- SDK 推荐使用 `with/can`(兼容 `resource/action`),例如:`{ with: "app:all:<appId>", can: "read,write" }`。
|
|
142
|
-
- 推荐资源统一使用 `app:<scope>:<appId>`,常用为 `with=app:all:<appId>`;请确保路径在 `/apps/<appId>/`(或 `app_scope.path_prefix`)下。
|
|
143
|
-
- Token 过期或缓存异常时,清理 UCAN 会话并重新登录/生成 Root + Invocation。
|
|
152
|
+
默认端口:
|
|
153
|
+
- Go `3201`
|
|
154
|
+
- Java `3202`
|
|
155
|
+
- Node `3203`
|
|
156
|
+
- Python `3204`
|
|
144
157
|
|
|
145
|
-
|
|
158
|
+
## CORS 注意事项
|
|
146
159
|
|
|
147
|
-
|
|
160
|
+
若你用 `http://[::]:8001` 打开页面,请确保后端 CORS 白名单包含该 Origin。
|
|
161
|
+
建议统一加入:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
CORS_ORIGINS=http://localhost:8001,http://127.0.0.1:8001,http://[::]:8001
|
|
148
165
|
```
|
|
149
|
-
|
|
166
|
+
|
|
167
|
+
## 本地软链接(开发)
|
|
168
|
+
|
|
169
|
+
将本仓库作为本地依赖链接到你的 DApp:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
mkdir -p /path/to/your-dapp/node_modules/@yeying-community
|
|
173
|
+
ln -s /path/to/web3-bs /path/to/your-dapp/node_modules/@yeying-community/web3-bs
|
|
150
174
|
```
|
|
151
175
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
-
|
|
176
|
+
## 文档导航
|
|
177
|
+
|
|
178
|
+
- [文档导航](./docs/文档导航.md)
|
|
179
|
+
- [快速上手](./docs/快速上手.md)
|
|
180
|
+
- [SDK能力](./docs/SDK能力.md)
|
|
181
|
+
- [移动端认证与授权选型指南](./docs/移动端认证与授权选型指南.md)
|
|
182
|
+
- [接口规范(OpenAPI)](./docs/开放接口规范.yaml)
|
package/dist/auth/central.d.ts
CHANGED
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>;
|
package/dist/storage/webdav.d.ts
CHANGED
|
@@ -23,6 +23,40 @@ export type WebDavRequestOptions = {
|
|
|
23
23
|
contentType?: string;
|
|
24
24
|
signal?: AbortSignal;
|
|
25
25
|
};
|
|
26
|
+
export type WebDavShareExpiresUnit = 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
|
|
27
|
+
export type WebDavShareItem = {
|
|
28
|
+
token: string;
|
|
29
|
+
name: string;
|
|
30
|
+
path: string;
|
|
31
|
+
url: string;
|
|
32
|
+
viewCount: number;
|
|
33
|
+
downloadCount: number;
|
|
34
|
+
expiresAt?: string;
|
|
35
|
+
createdAt?: string;
|
|
36
|
+
};
|
|
37
|
+
export type CreateWebDavShareLinkOptions = {
|
|
38
|
+
path: string;
|
|
39
|
+
expiresIn?: number;
|
|
40
|
+
expiresValue?: number;
|
|
41
|
+
expiresUnit?: WebDavShareExpiresUnit;
|
|
42
|
+
auth?: WebDavAuth;
|
|
43
|
+
token?: string;
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
};
|
|
46
|
+
export type WebDavShareListOptions = {
|
|
47
|
+
auth?: WebDavAuth;
|
|
48
|
+
token?: string;
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
};
|
|
51
|
+
export type WebDavShareRevokeOptions = {
|
|
52
|
+
auth?: WebDavAuth;
|
|
53
|
+
token?: string;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
};
|
|
56
|
+
export type WebDavShareRevokeResult = {
|
|
57
|
+
message?: string;
|
|
58
|
+
revoked?: boolean;
|
|
59
|
+
};
|
|
26
60
|
export declare class WebDavClient {
|
|
27
61
|
private baseUrl;
|
|
28
62
|
private prefix;
|
|
@@ -51,5 +85,10 @@ export declare class WebDavClient {
|
|
|
51
85
|
recoverRecycle(hash: string): Promise<unknown>;
|
|
52
86
|
deleteRecycle(hash: string): Promise<unknown>;
|
|
53
87
|
clearRecycle(): Promise<unknown>;
|
|
88
|
+
private requestApiJson;
|
|
89
|
+
getShareAccessUrl(token: string, fileName?: string): string;
|
|
90
|
+
createShareLink(options: CreateWebDavShareLinkOptions): Promise<WebDavShareItem>;
|
|
91
|
+
listShareLinks(options?: WebDavShareListOptions): Promise<WebDavShareItem[]>;
|
|
92
|
+
revokeShareLink(token: string, options?: WebDavShareRevokeOptions): Promise<WebDavShareRevokeResult>;
|
|
54
93
|
}
|
|
55
94
|
export declare function createWebDavClient(options: WebDavClientOptions): WebDavClient;
|
package/dist/web3-bs.esm.js
CHANGED
|
@@ -1131,6 +1131,16 @@ function resolveCredentials(options) {
|
|
|
1131
1131
|
function resolveSessionTokenKey(options) {
|
|
1132
1132
|
return options?.sessionTokenStorageKey || DEFAULT_SESSION_TOKEN_KEY;
|
|
1133
1133
|
}
|
|
1134
|
+
function resolveAccessToken(options) {
|
|
1135
|
+
if (typeof options?.accessToken === 'string') {
|
|
1136
|
+
const token = options.accessToken.trim();
|
|
1137
|
+
return token || null;
|
|
1138
|
+
}
|
|
1139
|
+
if (options?.accessToken === null) {
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
return getAccessToken(options);
|
|
1143
|
+
}
|
|
1134
1144
|
function shouldStoreSessionToken(options) {
|
|
1135
1145
|
return options?.storeSessionToken !== false;
|
|
1136
1146
|
}
|
|
@@ -1178,6 +1188,9 @@ function parseCapabilitiesField(obj, keys) {
|
|
|
1178
1188
|
}
|
|
1179
1189
|
return undefined;
|
|
1180
1190
|
}
|
|
1191
|
+
function parseIssuerDidField(obj) {
|
|
1192
|
+
return parseStringField(obj, ['issuerDid', 'issuer', 'did']);
|
|
1193
|
+
}
|
|
1181
1194
|
function readStoredSessionToken(options) {
|
|
1182
1195
|
if (!shouldStoreSessionToken(options))
|
|
1183
1196
|
return null;
|
|
@@ -1234,11 +1247,16 @@ async function getCentralIssuerInfo(options = {}) {
|
|
|
1234
1247
|
const fetcher = resolveFetcher(options);
|
|
1235
1248
|
const credentials = resolveCredentials(options);
|
|
1236
1249
|
const url = joinUrl$1(resolveBaseUrl(options), options.issuerPath || DEFAULT_ISSUER_PATH);
|
|
1250
|
+
const token = resolveAccessToken(options);
|
|
1251
|
+
const headers = new Headers({
|
|
1252
|
+
accept: 'application/json',
|
|
1253
|
+
});
|
|
1254
|
+
if (token) {
|
|
1255
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
1256
|
+
}
|
|
1237
1257
|
const response = await fetcher(url, {
|
|
1238
1258
|
method: 'GET',
|
|
1239
|
-
headers
|
|
1240
|
-
accept: 'application/json',
|
|
1241
|
-
},
|
|
1259
|
+
headers,
|
|
1242
1260
|
credentials,
|
|
1243
1261
|
});
|
|
1244
1262
|
const payload = await parseJsonBody(response);
|
|
@@ -1248,7 +1266,7 @@ async function getCentralIssuerInfo(options = {}) {
|
|
|
1248
1266
|
const data = parseEnvelopeData(payload);
|
|
1249
1267
|
return {
|
|
1250
1268
|
enabled: typeof data.enabled === 'boolean' ? data.enabled : undefined,
|
|
1251
|
-
issuerDid:
|
|
1269
|
+
issuerDid: parseIssuerDidField(data),
|
|
1252
1270
|
defaultAudience: parseStringField(data, ['defaultAudience']),
|
|
1253
1271
|
defaultCapabilities: parseCapabilitiesField(data, ['defaultCapabilities']),
|
|
1254
1272
|
response: payload,
|
|
@@ -1261,13 +1279,18 @@ async function createCentralSession(options) {
|
|
|
1261
1279
|
}
|
|
1262
1280
|
const fetcher = resolveFetcher(options);
|
|
1263
1281
|
const credentials = resolveCredentials(options);
|
|
1282
|
+
const accessToken = resolveAccessToken(options);
|
|
1264
1283
|
const url = joinUrl$1(resolveBaseUrl(options), options.sessionPath || DEFAULT_SESSION_PATH);
|
|
1284
|
+
const headers = new Headers({
|
|
1285
|
+
'Content-Type': 'application/json',
|
|
1286
|
+
accept: 'application/json',
|
|
1287
|
+
});
|
|
1288
|
+
if (accessToken) {
|
|
1289
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
1290
|
+
}
|
|
1265
1291
|
const response = await fetcher(url, {
|
|
1266
1292
|
method: 'POST',
|
|
1267
|
-
headers
|
|
1268
|
-
'Content-Type': 'application/json',
|
|
1269
|
-
accept: 'application/json',
|
|
1270
|
-
},
|
|
1293
|
+
headers,
|
|
1271
1294
|
credentials,
|
|
1272
1295
|
body: JSON.stringify({
|
|
1273
1296
|
subject,
|
|
@@ -1288,7 +1311,7 @@ async function createCentralSession(options) {
|
|
|
1288
1311
|
subject: parseStringField(data, ['subject']) || subject,
|
|
1289
1312
|
sessionToken,
|
|
1290
1313
|
expiresAt: parseNumberField(data, ['expiresAt']),
|
|
1291
|
-
issuerDid:
|
|
1314
|
+
issuerDid: parseIssuerDidField(data),
|
|
1292
1315
|
response: payload,
|
|
1293
1316
|
};
|
|
1294
1317
|
}
|
|
@@ -1329,13 +1352,13 @@ async function issueCentralUcan(options = {}) {
|
|
|
1329
1352
|
}
|
|
1330
1353
|
return {
|
|
1331
1354
|
ucan,
|
|
1332
|
-
issuerDid:
|
|
1355
|
+
issuerDid: parseIssuerDidField(data),
|
|
1333
1356
|
subject: parseStringField(data, ['subject']),
|
|
1334
1357
|
audience: parseStringField(data, ['audience']),
|
|
1335
1358
|
capabilities: parseCapabilitiesField(data, ['capabilities']),
|
|
1336
|
-
exp: parseNumberField(data, ['exp']),
|
|
1337
|
-
nbf: parseNumberField(data, ['nbf']),
|
|
1338
|
-
iat: parseNumberField(data, ['iat']),
|
|
1359
|
+
exp: parseNumberField(data, ['exp', 'expiresAt']),
|
|
1360
|
+
nbf: parseNumberField(data, ['nbf', 'notBefore']),
|
|
1361
|
+
iat: parseNumberField(data, ['iat', 'issuedAt']),
|
|
1339
1362
|
response: payload,
|
|
1340
1363
|
};
|
|
1341
1364
|
}
|
|
@@ -1412,6 +1435,9 @@ function joinUrl(baseUrl, path) {
|
|
|
1412
1435
|
const suffix = path.startsWith('/') ? path : `/${path}`;
|
|
1413
1436
|
return `${base}${suffix}`;
|
|
1414
1437
|
}
|
|
1438
|
+
function isRecord(value) {
|
|
1439
|
+
return typeof value === 'object' && value !== null;
|
|
1440
|
+
}
|
|
1415
1441
|
function resolveAuthHeader(auth, token) {
|
|
1416
1442
|
if (auth?.type === 'bearer') {
|
|
1417
1443
|
return `Bearer ${auth.token}`;
|
|
@@ -1600,6 +1626,72 @@ class WebDavClient {
|
|
|
1600
1626
|
}
|
|
1601
1627
|
return await res.json();
|
|
1602
1628
|
}
|
|
1629
|
+
async requestApiJson(method, apiPath, body, options) {
|
|
1630
|
+
const headers = this.buildHeaders({
|
|
1631
|
+
auth: options?.auth,
|
|
1632
|
+
token: options?.token,
|
|
1633
|
+
contentType: body === undefined ? undefined : 'application/json',
|
|
1634
|
+
});
|
|
1635
|
+
const response = await this.fetcher(joinUrl(this.baseUrl, apiPath), {
|
|
1636
|
+
method,
|
|
1637
|
+
headers,
|
|
1638
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
1639
|
+
credentials: this.credentials,
|
|
1640
|
+
signal: options?.signal,
|
|
1641
|
+
});
|
|
1642
|
+
if (!response.ok) {
|
|
1643
|
+
throw new Error(`WebDAV ${method} ${apiPath} failed: ${response.status} ${response.statusText}`);
|
|
1644
|
+
}
|
|
1645
|
+
return await response.json();
|
|
1646
|
+
}
|
|
1647
|
+
getShareAccessUrl(token, fileName) {
|
|
1648
|
+
const normalizedToken = encodeURIComponent(String(token || '').trim());
|
|
1649
|
+
if (!normalizedToken) {
|
|
1650
|
+
throw new Error('Share token is required');
|
|
1651
|
+
}
|
|
1652
|
+
const encodedFileName = String(fileName || '').trim()
|
|
1653
|
+
? `/${encodeURIComponent(String(fileName || '').trim())}`
|
|
1654
|
+
: '';
|
|
1655
|
+
return joinUrl(this.baseUrl, `/api/v1/public/share/${normalizedToken}${encodedFileName}`);
|
|
1656
|
+
}
|
|
1657
|
+
async createShareLink(options) {
|
|
1658
|
+
const normalizedPath = String(options.path || '').trim();
|
|
1659
|
+
if (!normalizedPath) {
|
|
1660
|
+
throw new Error('Share path is required');
|
|
1661
|
+
}
|
|
1662
|
+
const payload = await this.requestApiJson('POST', '/api/v1/public/share/create', {
|
|
1663
|
+
path: normalizedPath,
|
|
1664
|
+
expiresIn: options.expiresIn,
|
|
1665
|
+
expiresValue: options.expiresValue,
|
|
1666
|
+
expiresUnit: options.expiresUnit,
|
|
1667
|
+
}, options);
|
|
1668
|
+
if (!isRecord(payload)) {
|
|
1669
|
+
throw new Error('WebDAV share create response is invalid');
|
|
1670
|
+
}
|
|
1671
|
+
return payload;
|
|
1672
|
+
}
|
|
1673
|
+
async listShareLinks(options = {}) {
|
|
1674
|
+
const payload = await this.requestApiJson('GET', '/api/v1/public/share/list', undefined, options);
|
|
1675
|
+
if (!isRecord(payload)) {
|
|
1676
|
+
return [];
|
|
1677
|
+
}
|
|
1678
|
+
const items = payload.items;
|
|
1679
|
+
if (!Array.isArray(items)) {
|
|
1680
|
+
return [];
|
|
1681
|
+
}
|
|
1682
|
+
return items.filter(isRecord);
|
|
1683
|
+
}
|
|
1684
|
+
async revokeShareLink(token, options = {}) {
|
|
1685
|
+
const normalizedToken = String(token || '').trim();
|
|
1686
|
+
if (!normalizedToken) {
|
|
1687
|
+
throw new Error('Share token is required');
|
|
1688
|
+
}
|
|
1689
|
+
const payload = await this.requestApiJson('POST', '/api/v1/public/share/revoke', { token: normalizedToken }, options);
|
|
1690
|
+
if (!isRecord(payload)) {
|
|
1691
|
+
return {};
|
|
1692
|
+
}
|
|
1693
|
+
return payload;
|
|
1694
|
+
}
|
|
1603
1695
|
}
|
|
1604
1696
|
function createWebDavClient(options) {
|
|
1605
1697
|
return new WebDavClient(options);
|
|
@@ -1608,6 +1700,13 @@ function createWebDavClient(options) {
|
|
|
1608
1700
|
const tokenCache = new Map();
|
|
1609
1701
|
const TOKEN_SKEW_MS = 5000;
|
|
1610
1702
|
const DEFAULT_APP_ACTION = 'write';
|
|
1703
|
+
const LOOPBACK_HOST_ALIASES = new Set([
|
|
1704
|
+
'localhost',
|
|
1705
|
+
'127.0.0.1',
|
|
1706
|
+
'::1',
|
|
1707
|
+
'0:0:0:0:0:0:0:1',
|
|
1708
|
+
'0.0.0.0',
|
|
1709
|
+
]);
|
|
1611
1710
|
function normalizeAppDir(path) {
|
|
1612
1711
|
const trimmed = path.trim();
|
|
1613
1712
|
if (!trimmed)
|
|
@@ -1619,6 +1718,69 @@ function normalizeAppDir(path) {
|
|
|
1619
1718
|
function sanitizeAppId(appId) {
|
|
1620
1719
|
return appId.trim().replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
1621
1720
|
}
|
|
1721
|
+
function parseHostPort(rawHost) {
|
|
1722
|
+
const host = rawHost.trim();
|
|
1723
|
+
if (!host)
|
|
1724
|
+
return { hostname: '', port: '' };
|
|
1725
|
+
const bracketMatch = host.match(/^\[([^\]]+)\](?::([0-9]+))?$/);
|
|
1726
|
+
if (bracketMatch) {
|
|
1727
|
+
return {
|
|
1728
|
+
hostname: bracketMatch[1] || '',
|
|
1729
|
+
port: bracketMatch[2] || '',
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
const firstColon = host.indexOf(':');
|
|
1733
|
+
const lastColon = host.lastIndexOf(':');
|
|
1734
|
+
if (firstColon > -1 && firstColon === lastColon) {
|
|
1735
|
+
const hostname = host.slice(0, firstColon).trim();
|
|
1736
|
+
const port = host.slice(firstColon + 1).trim();
|
|
1737
|
+
if (/^[0-9]+$/.test(port)) {
|
|
1738
|
+
return { hostname, port };
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
return { hostname: host, port: '' };
|
|
1742
|
+
}
|
|
1743
|
+
function normalizeAppHostnameForAppId(hostname) {
|
|
1744
|
+
const normalized = (hostname || '').trim().toLowerCase();
|
|
1745
|
+
if (!normalized)
|
|
1746
|
+
return '';
|
|
1747
|
+
const bare = normalized.replace(/^\[(.*)\]$/, '$1');
|
|
1748
|
+
if (LOOPBACK_HOST_ALIASES.has(normalized) || LOOPBACK_HOST_ALIASES.has(bare)) {
|
|
1749
|
+
return 'localhost';
|
|
1750
|
+
}
|
|
1751
|
+
return bare;
|
|
1752
|
+
}
|
|
1753
|
+
function buildSanitizedAppId(hostname, port) {
|
|
1754
|
+
const normalizedHostname = normalizeAppHostnameForAppId(hostname);
|
|
1755
|
+
if (!normalizedHostname)
|
|
1756
|
+
return '';
|
|
1757
|
+
const normalizedPort = port === undefined || port === null ? '' : String(port).trim();
|
|
1758
|
+
const host = normalizedPort
|
|
1759
|
+
? `${normalizedHostname}:${normalizedPort}`
|
|
1760
|
+
: normalizedHostname;
|
|
1761
|
+
return sanitizeAppId(host);
|
|
1762
|
+
}
|
|
1763
|
+
function deriveAppIdFromHost(host) {
|
|
1764
|
+
const parsed = parseHostPort(host || '');
|
|
1765
|
+
return buildSanitizedAppId(parsed.hostname, parsed.port);
|
|
1766
|
+
}
|
|
1767
|
+
function deriveAppIdFromLocation(locationLike) {
|
|
1768
|
+
const source = locationLike ||
|
|
1769
|
+
(typeof window !== 'undefined' ? window.location : undefined);
|
|
1770
|
+
if (!source)
|
|
1771
|
+
return '';
|
|
1772
|
+
const hostname = typeof source.hostname === 'string' ? source.hostname : '';
|
|
1773
|
+
const port = source.port;
|
|
1774
|
+
if (hostname) {
|
|
1775
|
+
const appId = buildSanitizedAppId(hostname, port);
|
|
1776
|
+
if (appId)
|
|
1777
|
+
return appId;
|
|
1778
|
+
}
|
|
1779
|
+
if (typeof source.host === 'string') {
|
|
1780
|
+
return deriveAppIdFromHost(source.host);
|
|
1781
|
+
}
|
|
1782
|
+
return '';
|
|
1783
|
+
}
|
|
1622
1784
|
function normalizeAction(action) {
|
|
1623
1785
|
const trimmed = (action || '').trim();
|
|
1624
1786
|
return trimmed ? trimmed : null;
|
|
@@ -1842,5 +2004,5 @@ async function initDappSession(options) {
|
|
|
1842
2004
|
return result;
|
|
1843
2005
|
}
|
|
1844
2006
|
|
|
1845
|
-
export { WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getUcanSession, initDappSession, initWebDavStorage, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeUcanCapabilities, normalizeUcanCapability, onAccountsChanged, onChainChanged, refreshAccessToken, requestAccounts, requireProvider, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts };
|
|
2007
|
+
export { WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, deriveAppIdFromHost, deriveAppIdFromLocation, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getUcanSession, initDappSession, initWebDavStorage, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeAppHostnameForAppId, normalizeUcanCapabilities, normalizeUcanCapability, onAccountsChanged, onChainChanged, refreshAccessToken, requestAccounts, requireProvider, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts };
|
|
1846
2008
|
//# sourceMappingURL=web3-bs.esm.js.map
|