@kevisual/api 0.0.40 → 0.0.42
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "mod.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"type": "module",
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@kevisual/cache": "^0.0.5",
|
|
25
|
-
"@kevisual/query": "^0.0.
|
|
26
|
-
"@kevisual/router": "^0.0.
|
|
25
|
+
"@kevisual/query": "^0.0.39",
|
|
26
|
+
"@kevisual/router": "^0.0.66",
|
|
27
27
|
"@kevisual/types": "^0.0.12",
|
|
28
|
-
"@kevisual/use-config": "^1.0.
|
|
28
|
+
"@kevisual/use-config": "^1.0.30",
|
|
29
29
|
"@types/bun": "^1.3.8",
|
|
30
30
|
"@types/crypto-js": "^4.2.2",
|
|
31
|
-
"@types/node": "^25.
|
|
31
|
+
"@types/node": "^25.2.0",
|
|
32
32
|
"crypto-js": "^4.2.0",
|
|
33
33
|
"dotenv": "^17.2.3",
|
|
34
34
|
"fast-glob": "^3.3.3"
|
|
@@ -54,4 +54,4 @@
|
|
|
54
54
|
"./resources": "./query/query-resources/index.ts",
|
|
55
55
|
"./query/*": "./query/*"
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
}
|
|
@@ -2,15 +2,18 @@ import { adapter, DataOpts, Result } from '@kevisual/query';
|
|
|
2
2
|
import path from 'path-browserify-esm';
|
|
3
3
|
import { hashContent } from './utils';
|
|
4
4
|
|
|
5
|
+
type Process = {}
|
|
5
6
|
type QueryResourcesOptions = {
|
|
6
7
|
prefix?: string;
|
|
7
8
|
storage?: Storage;
|
|
8
9
|
username?: string;
|
|
10
|
+
onProcess?: (opts?: Process) => void;
|
|
9
11
|
[key: string]: any;
|
|
10
12
|
};
|
|
11
13
|
export class QueryResources {
|
|
12
14
|
prefix: string; // root/resources
|
|
13
15
|
storage: Storage;
|
|
16
|
+
onProcess?: (opts?: Process) => void;
|
|
14
17
|
constructor(opts: QueryResourcesOptions) {
|
|
15
18
|
if (opts.username) {
|
|
16
19
|
this.prefix = `/${opts.username}/resources/`;
|
|
@@ -18,6 +21,7 @@ export class QueryResources {
|
|
|
18
21
|
this.prefix = opts.prefix || '';
|
|
19
22
|
}
|
|
20
23
|
this.storage = opts.storage || localStorage;
|
|
24
|
+
this.onProcess = opts.onProcess || (() => { });
|
|
21
25
|
}
|
|
22
26
|
setUsername(username: string) {
|
|
23
27
|
this.prefix = `/${username}/resources/`;
|
|
@@ -81,6 +85,7 @@ export class QueryResources {
|
|
|
81
85
|
// 使用分块上传
|
|
82
86
|
return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
|
|
83
87
|
}
|
|
88
|
+
this.onProcess?.({ type: 'uploadBegin', filename, size: fileSize, process: 0 });
|
|
84
89
|
|
|
85
90
|
const formData = new FormData();
|
|
86
91
|
if (isBlob) {
|
|
@@ -88,7 +93,7 @@ export class QueryResources {
|
|
|
88
93
|
} else {
|
|
89
94
|
formData.append('file', new Blob([content], { type }));
|
|
90
95
|
}
|
|
91
|
-
|
|
96
|
+
const res = await adapter({
|
|
92
97
|
url: url.toString(),
|
|
93
98
|
isPostFile: true,
|
|
94
99
|
method: 'POST',
|
|
@@ -101,6 +106,8 @@ export class QueryResources {
|
|
|
101
106
|
...restOpts?.params,
|
|
102
107
|
},
|
|
103
108
|
});
|
|
109
|
+
this.onProcess?.({ type: 'uploadFinish', filename, size: fileSize, process: 100 });
|
|
110
|
+
return res;
|
|
104
111
|
}
|
|
105
112
|
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
|
|
106
113
|
const pathname = `${this.prefix}${filepath}`;
|
|
@@ -114,8 +121,10 @@ export class QueryResources {
|
|
|
114
121
|
const { chunkSize: _chunkSize, ...restOpts } = opts || {};
|
|
115
122
|
const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
|
|
116
123
|
const totalChunks = Math.ceil(file.size / chunkSize);
|
|
124
|
+
this.onProcess?.({ type: 'uploadBegin', filename, size: file.size, process: 0 });
|
|
117
125
|
|
|
118
126
|
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
|
127
|
+
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: 0, totalChunks, currentChunk: currentChunk + 1 });
|
|
119
128
|
const start = currentChunk * chunkSize;
|
|
120
129
|
const end = Math.min(start + chunkSize, file.size);
|
|
121
130
|
const chunkBlob = file.slice(start, end);
|
|
@@ -145,19 +154,20 @@ export class QueryResources {
|
|
|
145
154
|
},
|
|
146
155
|
});
|
|
147
156
|
if (res.code !== 200) {
|
|
148
|
-
throw new Error(`Chunk
|
|
157
|
+
throw new Error(`Chunk 上传失败 code ${res!.code}, 错误信息是: ${res!.message}`);
|
|
149
158
|
}
|
|
150
159
|
console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
|
160
|
+
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: Math.round(((currentChunk + 1) / totalChunks) * 100), totalChunks, currentChunk: currentChunk + 1 });
|
|
151
161
|
} catch (error) {
|
|
152
162
|
console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
|
|
153
163
|
return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
|
|
154
164
|
}
|
|
155
165
|
}
|
|
156
|
-
|
|
166
|
+
this.onProcess?.({ type: 'uploadFinish', filename, size: file.size, process: 100 });
|
|
157
167
|
return { code: 200, message: '上传成功' };
|
|
158
168
|
}
|
|
159
169
|
|
|
160
|
-
async
|
|
170
|
+
async getStat(filepath: string, opts?: DataOpts): Promise<Result<Stat>> {
|
|
161
171
|
const url = `${this.prefix}${filepath}`;
|
|
162
172
|
return adapter({
|
|
163
173
|
url,
|
|
@@ -168,6 +178,15 @@ export class QueryResources {
|
|
|
168
178
|
headers: this.header(opts?.headers),
|
|
169
179
|
});
|
|
170
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* @deprecated use getStat instead
|
|
183
|
+
* @param filepath
|
|
184
|
+
* @param opts
|
|
185
|
+
* @returns
|
|
186
|
+
*/
|
|
187
|
+
async getState(filepath: string, opts?: DataOpts): Promise<Result<Stat>> {
|
|
188
|
+
return this.getStat(filepath, opts);
|
|
189
|
+
}
|
|
171
190
|
async createFolder(folderpath: string, opts?: DataOpts): Promise<Result<any>> {
|
|
172
191
|
const filepath = folderpath.endsWith('/') ? `${folderpath}keep.txt` : `${folderpath}/keep.txt`;
|
|
173
192
|
return this.uploadFile(filepath, '文件夹占位,其他文件不存在,文件夹不存在,如果有其他文件夹,删除当前文件夹占位文件即可', opts);
|