更新版本至 0.0.42,修改依赖项版本并在 QueryResources 类中新增 onProcess 回调以支持上传进度通知
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/api",
|
"name": "@kevisual/api",
|
||||||
"version": "0.0.41",
|
"version": "0.0.42",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "mod.ts",
|
"main": "mod.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
"@kevisual/query": "^0.0.39",
|
"@kevisual/query": "^0.0.39",
|
||||||
"@kevisual/router": "^0.0.66",
|
"@kevisual/router": "^0.0.66",
|
||||||
"@kevisual/types": "^0.0.12",
|
"@kevisual/types": "^0.0.12",
|
||||||
"@kevisual/use-config": "^1.0.28",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"@types/bun": "^1.3.8",
|
"@types/bun": "^1.3.8",
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.2.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"fast-glob": "^3.3.3"
|
"fast-glob": "^3.3.3"
|
||||||
|
|||||||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@@ -49,8 +49,8 @@ importers:
|
|||||||
specifier: ^0.0.12
|
specifier: ^0.0.12
|
||||||
version: 0.0.12
|
version: 0.0.12
|
||||||
'@kevisual/use-config':
|
'@kevisual/use-config':
|
||||||
specifier: ^1.0.28
|
specifier: ^1.0.30
|
||||||
version: 1.0.28(dotenv@17.2.3)
|
version: 1.0.30(dotenv@17.2.3)
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: ^1.3.8
|
specifier: ^1.3.8
|
||||||
version: 1.3.8
|
version: 1.3.8
|
||||||
@@ -58,8 +58,8 @@ importers:
|
|||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2
|
version: 4.2.2
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.1.0
|
specifier: ^25.2.0
|
||||||
version: 25.1.0
|
version: 25.2.0
|
||||||
crypto-js:
|
crypto-js:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
version: 4.2.0
|
version: 4.2.0
|
||||||
@@ -134,8 +134,8 @@ packages:
|
|||||||
'@kevisual/types@0.0.12':
|
'@kevisual/types@0.0.12':
|
||||||
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
|
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.28':
|
'@kevisual/use-config@1.0.30':
|
||||||
resolution: {integrity: sha512-ngF+LDbjxpXWrZNmnShIKF/jPpAa+ezV+DcgoZIIzHlRnIjE+rr9sLkN/B7WJbiH9C/j1tQXOILY8ujBqILrow==}
|
resolution: {integrity: sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
dotenv: ^17
|
dotenv: ^17
|
||||||
|
|
||||||
@@ -350,8 +350,8 @@ packages:
|
|||||||
'@types/node@22.15.27':
|
'@types/node@22.15.27':
|
||||||
resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==}
|
resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==}
|
||||||
|
|
||||||
'@types/node@25.1.0':
|
'@types/node@25.2.0':
|
||||||
resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==}
|
resolution: {integrity: sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==}
|
||||||
|
|
||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
@@ -765,7 +765,7 @@ snapshots:
|
|||||||
|
|
||||||
'@kevisual/types@0.0.12': {}
|
'@kevisual/types@0.0.12': {}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.28(dotenv@17.2.3)':
|
'@kevisual/use-config@1.0.30(dotenv@17.2.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/load': 0.0.6
|
'@kevisual/load': 0.0.6
|
||||||
dotenv: 17.2.3
|
dotenv: 17.2.3
|
||||||
@@ -921,7 +921,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
|
|
||||||
'@types/node@25.1.0':
|
'@types/node@25.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
|
|
||||||
@@ -945,7 +945,7 @@ snapshots:
|
|||||||
|
|
||||||
bun-types@1.3.8:
|
bun-types@1.3.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.1.0
|
'@types/node': 25.2.0
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import { adapter, DataOpts, Result } from '@kevisual/query';
|
|||||||
import path from 'path-browserify-esm';
|
import path from 'path-browserify-esm';
|
||||||
import { hashContent } from './utils';
|
import { hashContent } from './utils';
|
||||||
|
|
||||||
|
type Process = {}
|
||||||
type QueryResourcesOptions = {
|
type QueryResourcesOptions = {
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
storage?: Storage;
|
storage?: Storage;
|
||||||
username?: string;
|
username?: string;
|
||||||
|
onProcess?: (opts?: Process) => void;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
export class QueryResources {
|
export class QueryResources {
|
||||||
prefix: string; // root/resources
|
prefix: string; // root/resources
|
||||||
storage: Storage;
|
storage: Storage;
|
||||||
|
onProcess?: (opts?: Process) => void;
|
||||||
constructor(opts: QueryResourcesOptions) {
|
constructor(opts: QueryResourcesOptions) {
|
||||||
if (opts.username) {
|
if (opts.username) {
|
||||||
this.prefix = `/${opts.username}/resources/`;
|
this.prefix = `/${opts.username}/resources/`;
|
||||||
@@ -18,6 +21,7 @@ export class QueryResources {
|
|||||||
this.prefix = opts.prefix || '';
|
this.prefix = opts.prefix || '';
|
||||||
}
|
}
|
||||||
this.storage = opts.storage || localStorage;
|
this.storage = opts.storage || localStorage;
|
||||||
|
this.onProcess = opts.onProcess || (() => { });
|
||||||
}
|
}
|
||||||
setUsername(username: string) {
|
setUsername(username: string) {
|
||||||
this.prefix = `/${username}/resources/`;
|
this.prefix = `/${username}/resources/`;
|
||||||
@@ -81,6 +85,7 @@ export class QueryResources {
|
|||||||
// 使用分块上传
|
// 使用分块上传
|
||||||
return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
|
return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
|
||||||
}
|
}
|
||||||
|
this.onProcess?.({ type: 'uploadBegin', filename, size: fileSize, process: 0 });
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
if (isBlob) {
|
if (isBlob) {
|
||||||
@@ -88,7 +93,7 @@ export class QueryResources {
|
|||||||
} else {
|
} else {
|
||||||
formData.append('file', new Blob([content], { type }));
|
formData.append('file', new Blob([content], { type }));
|
||||||
}
|
}
|
||||||
return adapter({
|
const res = await adapter({
|
||||||
url: url.toString(),
|
url: url.toString(),
|
||||||
isPostFile: true,
|
isPostFile: true,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -101,6 +106,8 @@ export class QueryResources {
|
|||||||
...restOpts?.params,
|
...restOpts?.params,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.onProcess?.({ type: 'uploadFinish', filename, size: fileSize, process: 100 });
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
|
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
|
||||||
const pathname = `${this.prefix}${filepath}`;
|
const pathname = `${this.prefix}${filepath}`;
|
||||||
@@ -114,8 +121,10 @@ export class QueryResources {
|
|||||||
const { chunkSize: _chunkSize, ...restOpts } = opts || {};
|
const { chunkSize: _chunkSize, ...restOpts } = opts || {};
|
||||||
const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
|
const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
|
||||||
const totalChunks = Math.ceil(file.size / chunkSize);
|
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||||
|
this.onProcess?.({ type: 'uploadBegin', filename, size: file.size, process: 0 });
|
||||||
|
|
||||||
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
||||||
|
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: 0, totalChunks, currentChunk: currentChunk + 1 });
|
||||||
const start = currentChunk * chunkSize;
|
const start = currentChunk * chunkSize;
|
||||||
const end = Math.min(start + chunkSize, file.size);
|
const end = Math.min(start + chunkSize, file.size);
|
||||||
const chunkBlob = file.slice(start, end);
|
const chunkBlob = file.slice(start, end);
|
||||||
@@ -145,15 +154,16 @@ export class QueryResources {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
throw new Error(`Chunk upload failed with code ${res!.code}, message: ${res!.message}`);
|
throw new Error(`Chunk 上传失败 code ${res!.code}, 错误信息是: ${res!.message}`);
|
||||||
}
|
}
|
||||||
console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
||||||
|
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: Math.round(((currentChunk + 1) / totalChunks) * 100), totalChunks, currentChunk: currentChunk + 1 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
|
console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
|
||||||
return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
|
return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.onProcess?.({ type: 'uploadFinish', filename, size: file.size, process: 100 });
|
||||||
return { code: 200, message: '上传成功' };
|
return { code: 200, message: '上传成功' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user