@lhy-meta-server/meta-oss 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +378 -3
- package/dist/ali-oss/client.d.ts +185 -0
- package/dist/ali-oss/client.d.ts.map +1 -0
- package/dist/ali-oss/driver.d.ts +156 -0
- package/dist/ali-oss/driver.d.ts.map +1 -0
- package/dist/ali-oss/index.d.ts +11 -0
- package/dist/ali-oss/index.d.ts.map +1 -0
- package/dist/ali-oss/index.js +3 -0
- package/dist/ali-oss/index.js.map +11 -0
- package/dist/ali-oss/mapping.d.ts +25 -0
- package/dist/ali-oss/mapping.d.ts.map +1 -0
- package/dist/core/driver.d.ts +194 -0
- package/dist/core/driver.d.ts.map +1 -0
- package/dist/core/errors.d.ts +106 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/execution.d.ts +130 -0
- package/dist/core/execution.d.ts.map +1 -0
- package/dist/core/keys.d.ts +34 -0
- package/dist/core/keys.d.ts.map +1 -0
- package/dist/core/mime.d.ts +35 -0
- package/dist/core/mime.d.ts.map +1 -0
- package/dist/core/observability.d.ts +224 -0
- package/dist/core/observability.d.ts.map +1 -0
- package/dist/core/payload.d.ts +81 -0
- package/dist/core/payload.d.ts.map +1 -0
- package/dist/core/policy.d.ts +31 -0
- package/dist/core/policy.d.ts.map +1 -0
- package/dist/core/storage.d.ts +344 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/types.d.ts +301 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/validation.d.ts +73 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/elysia/index.d.ts +81 -0
- package/dist/elysia/index.d.ts.map +1 -0
- package/dist/elysia/index.js +3 -0
- package/dist/elysia/index.js.map +10 -0
- package/dist/filesystem/driver.d.ts +242 -0
- package/dist/filesystem/driver.d.ts.map +1 -0
- package/dist/filesystem/durability.d.ts +28 -0
- package/dist/filesystem/durability.d.ts.map +1 -0
- package/dist/filesystem/index.d.ts +11 -0
- package/dist/filesystem/index.d.ts.map +1 -0
- package/dist/filesystem/index.js +4 -0
- package/dist/filesystem/index.js.map +14 -0
- package/dist/filesystem/metadata.d.ts +56 -0
- package/dist/filesystem/metadata.d.ts.map +1 -0
- package/dist/filesystem/paths.d.ts +48 -0
- package/dist/filesystem/paths.d.ts.map +1 -0
- package/dist/filesystem/signer.d.ts +58 -0
- package/dist/filesystem/signer.d.ts.map +1 -0
- package/dist/index-5w45sfp6.js +4 -0
- package/dist/index-5w45sfp6.js.map +10 -0
- package/dist/index-7dpmhwry.js +4 -0
- package/dist/index-7dpmhwry.js.map +11 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +16 -0
- package/package.json +81 -6
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import type { DriverCopyOptions, DriverGetOptions, DriverListOptions, DriverPutOptions, DriverSignOptions, MultipartDriver, StorageDriver } from '../core/driver';
|
|
3
|
+
import { StorageError } from '../core/errors';
|
|
4
|
+
import { type StoragePayload } from '../core/payload';
|
|
5
|
+
import type { DeleteManyResult, ListResult, ObjectInfo, ObjectStream } from '../core/types';
|
|
6
|
+
import type { AliOssClient } from './client';
|
|
7
|
+
/**
|
|
8
|
+
* ali-oss 适配器配置。
|
|
9
|
+
*/
|
|
10
|
+
export interface AliOssDriverOptions {
|
|
11
|
+
/**
|
|
12
|
+
* 业务创建的 ali-oss 客户端实例,例如 `new OSS({ region, bucket, accessKeyId, ... })`。
|
|
13
|
+
*/
|
|
14
|
+
client: AliOssClient;
|
|
15
|
+
/**
|
|
16
|
+
* 可选的服务器端加密算法,例如 `AES256` 或 `KMS`。
|
|
17
|
+
*/
|
|
18
|
+
serverSideEncryption?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 可选的存储类型,例如 `Standard`、`IA`、`Archive`。
|
|
21
|
+
*/
|
|
22
|
+
storageClass?: string;
|
|
23
|
+
/**
|
|
24
|
+
* 不超过该字节数的内容读入内存后整体上传,更大的内容流式上传,默认为 8 MiB。
|
|
25
|
+
*
|
|
26
|
+
* 整体上传可由 SDK 与服务层安全重试;流式上传内存占用恒定但只尝试一次。
|
|
27
|
+
* 大于服务层 `multipartThreshold` 的内容会先被自动转为分片上传。
|
|
28
|
+
*/
|
|
29
|
+
bufferThreshold?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 零配置的阿里云 OSS 适配器。
|
|
33
|
+
*
|
|
34
|
+
* 只需把 ali-oss 客户端实例传入即可使用全部能力:流式上传下载、批量删除、
|
|
35
|
+
* 服务端复制、分页列举、原生签名 URL 与分片上传。本包不依赖 `ali-oss`,
|
|
36
|
+
* 凭据只存在于业务创建的客户端中,适配器不会读取或记录。
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import OSS from 'ali-oss'
|
|
41
|
+
* import { AliOssDriver } from '@lhy-meta-server/meta-oss/ali-oss'
|
|
42
|
+
*
|
|
43
|
+
* const driver = new AliOssDriver({ client: new OSS({ region, bucket, accessKeyId, accessKeySecret }) })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class AliOssDriver implements StorageDriver {
|
|
47
|
+
/**
|
|
48
|
+
* 适配器名称。
|
|
49
|
+
*/
|
|
50
|
+
readonly name = "ali-oss";
|
|
51
|
+
/**
|
|
52
|
+
* 分片上传能力。
|
|
53
|
+
*/
|
|
54
|
+
readonly multipart: MultipartDriver;
|
|
55
|
+
private readonly client;
|
|
56
|
+
private readonly baseHeaders;
|
|
57
|
+
private readonly bufferThreshold;
|
|
58
|
+
/**
|
|
59
|
+
* 创建 ali-oss 适配器。
|
|
60
|
+
*
|
|
61
|
+
* @param options 客户端实例与可选的加密、存储类型配置。
|
|
62
|
+
* @throws {@link StorageError} 未提供客户端时抛出 `INVALID_OPTION`。
|
|
63
|
+
*/
|
|
64
|
+
constructor(options: AliOssDriverOptions);
|
|
65
|
+
/**
|
|
66
|
+
* 上传对象。
|
|
67
|
+
*
|
|
68
|
+
* 不超过 `bufferThreshold` 的已知大小内容读入内存后用 `put` 上传(SDK 可安全重试);
|
|
69
|
+
* 更大的内容(包括 `Blob` / `Bun.file()`)与未知大小的流一律用 `putStream` 流式上传,
|
|
70
|
+
* 内存占用与文件大小无关。取消时会销毁上传流以中断请求。
|
|
71
|
+
*
|
|
72
|
+
* @param key 完整对象键。
|
|
73
|
+
* @param payload 上传内容。
|
|
74
|
+
* @param options 已归一化的写入选项。
|
|
75
|
+
* @returns 对象描述信息。
|
|
76
|
+
*/
|
|
77
|
+
put(key: string, payload: StoragePayload, options: DriverPutOptions): Promise<ObjectInfo>;
|
|
78
|
+
/**
|
|
79
|
+
* 以流方式下载对象,支持范围读取。
|
|
80
|
+
*
|
|
81
|
+
* @param key 完整对象键。
|
|
82
|
+
* @param options 读取范围与取消信号。
|
|
83
|
+
* @returns 对象描述信息与可读流。
|
|
84
|
+
*/
|
|
85
|
+
get(key: string, options: DriverGetOptions): Promise<ObjectStream>;
|
|
86
|
+
/**
|
|
87
|
+
* 读取对象头部信息。
|
|
88
|
+
*
|
|
89
|
+
* @param key 完整对象键。
|
|
90
|
+
* @returns 对象描述信息。
|
|
91
|
+
*/
|
|
92
|
+
head(key: string): Promise<ObjectInfo>;
|
|
93
|
+
/**
|
|
94
|
+
* 删除对象;OSS 对不存在的对象同样返回成功。
|
|
95
|
+
*
|
|
96
|
+
* @param key 完整对象键。
|
|
97
|
+
*/
|
|
98
|
+
delete(key: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* 使用 `DeleteMultipleObjects` 批量删除。
|
|
101
|
+
*
|
|
102
|
+
* @param keys 完整对象键,最多 1000 个。
|
|
103
|
+
* @returns 删除结果。
|
|
104
|
+
*/
|
|
105
|
+
deleteMany(keys: string[]): Promise<DeleteManyResult>;
|
|
106
|
+
/**
|
|
107
|
+
* 分页列举对象。
|
|
108
|
+
*
|
|
109
|
+
* @param options 前缀、分隔符、游标与页大小。
|
|
110
|
+
* @returns 当前页结果。
|
|
111
|
+
*/
|
|
112
|
+
list(options: DriverListOptions): Promise<ListResult>;
|
|
113
|
+
/**
|
|
114
|
+
* 服务端复制对象,并保留源对象的 HTTP 属性与元数据。
|
|
115
|
+
*
|
|
116
|
+
* 禁止覆盖时使用 `x-oss-forbid-overwrite` 由 OSS 原子拒绝。
|
|
117
|
+
*
|
|
118
|
+
* @param source 完整源对象键。
|
|
119
|
+
* @param destination 完整目标对象键。
|
|
120
|
+
* @param options 覆盖策略。
|
|
121
|
+
* @returns 目标对象描述信息。
|
|
122
|
+
*/
|
|
123
|
+
copy(source: string, destination: string, options: DriverCopyOptions): Promise<ObjectInfo>;
|
|
124
|
+
/**
|
|
125
|
+
* 使用 SDK 原生签名生成限时 URL,优先使用支持 STS 刷新的异步接口。
|
|
126
|
+
*
|
|
127
|
+
* @param key 完整对象键。
|
|
128
|
+
* @param options 方法、有效期与头部约束。
|
|
129
|
+
* @returns 签名 URL。
|
|
130
|
+
*/
|
|
131
|
+
signUrl(key: string, options: DriverSignOptions): Promise<string>;
|
|
132
|
+
private createMultipart;
|
|
133
|
+
private uploadPart;
|
|
134
|
+
private completeMultipart;
|
|
135
|
+
private abortMultipart;
|
|
136
|
+
private writeOptions;
|
|
137
|
+
private call;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 将 ali-oss 错误归一化,额外识别 `FileAlreadyExists`、`NoSuchUpload` 与
|
|
141
|
+
* `RequestError`(SDK 的网络错误状态码为 `-1` / `-2`)。
|
|
142
|
+
*
|
|
143
|
+
* @param error ali-oss 抛出的错误。
|
|
144
|
+
* @param key 关联对象键。
|
|
145
|
+
* @returns 归一化后的存储错误。
|
|
146
|
+
*/
|
|
147
|
+
export declare function normalizeAliError(error: unknown, key?: string): StorageError;
|
|
148
|
+
/**
|
|
149
|
+
* 信号中止时销毁 Node.js 流,使正在进行的 SDK 请求随之失败并释放连接。
|
|
150
|
+
*
|
|
151
|
+
* @param signal 取消信号。
|
|
152
|
+
* @param stream 需要随取消销毁的流。
|
|
153
|
+
* @returns 解除监听的函数。
|
|
154
|
+
*/
|
|
155
|
+
export declare function bindAbort(signal: AbortSignal, stream: Readable): () => void;
|
|
156
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/ali-oss/driver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,YAAY,EAAkB,MAAM,gBAAgB,CAAA;AAC7D,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,iBAAiB,CAAA;AACrE,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EAEV,UAAU,EACV,YAAY,EAEb,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,UAAU,CAAA;AAGlE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,YAAW,aAAa;IAChD;;OAEG;IACH,SAAgB,IAAI,aAAY;IAChC;;OAEG;IACH,SAAgB,SAAS,EAAE,eAAe,CAAA;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IAExC;;;;;OAKG;IACH,YAAmB,OAAO,EAAE,mBAAmB,EAc9C;IAED;;;;;;;;;;;OAWG;IACU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiBrG;IAED;;;;;;OAMG;IACU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAmB9E;IAED;;;;;OAKG;IACU,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBlD;IAED;;;;OAIG;IACU,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9C;IAED;;;;;OAKG;IACU,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASjE;IAED;;;;;OAKG;IACU,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAYjE;IAED;;;;;;;;;OASG;IACU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAItG;IAED;;;;;;OAMG;IACU,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAY7E;YAEa,eAAe;YAKf,UAAU;YAaV,iBAAiB;YAWjB,cAAc;IAS5B,OAAO,CAAC,YAAY;YAcN,IAAI;CAOnB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CAS5E;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAG,MAAM,IAAI,CAO3E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 阿里云 OSS 适配器入口。
|
|
3
|
+
*
|
|
4
|
+
* 通过 `@lhy-meta-server/meta-oss/ali-oss` 引入。本包不依赖 `ali-oss`,
|
|
5
|
+
* 业务自行安装 SDK 并把客户端实例传给 {@link AliOssDriver}。
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export type { AliOssClient, AliOssListObject, AliOssListResult, AliOssRequestOptions, AliOssResponseInfo, } from './client';
|
|
10
|
+
export { AliOssDriver, type AliOssDriverOptions, normalizeAliError } from './driver';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ali-oss/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{g as C}from"../index-5w45sfp6.js";import{h as J,j as X,o as $}from"../index-7dpmhwry.js";import{Buffer as _}from"node:buffer";import{Readable as B}from"node:stream";function V(O){return typeof O==="string"&&O.length>0?O.replace(/^"|"$/g,""):void 0}function W(O,A={}){let D={};for(let[P,Y]of Object.entries(A))if(P.startsWith("x-oss-meta-")&&typeof Y==="string")D[P.slice(11)]=Y;let K=(P)=>typeof A[P]==="string"?A[P]:void 0,L=K("last-modified"),w=K("content-type"),G=K("cache-control"),z=K("content-disposition"),Q=V(A.etag);return{key:O,size:Number(A["content-length"]??0),metadata:D,...Q?{etag:Q}:{},...L?{lastModified:new Date(L)}:{},...w?{contentType:w}:{},...G?{cacheControl:G}:{},...z?{contentDisposition:z}:{}}}function Z(O){let A=V(O.etag);return{key:O.name,size:O.size,metadata:{},...A?{etag:A}:{},...O.lastModified?{lastModified:new Date(O.lastModified)}:{}}}class I{name="ali-oss";multipart;client;baseHeaders;bufferThreshold;constructor(O){if(!O?.client)throw new J("INVALID_OPTION","client is required");this.client=O.client,this.bufferThreshold=C("bufferThreshold",O.bufferThreshold??8388608,0),this.baseHeaders={...O.serverSideEncryption?{"x-oss-server-side-encryption":O.serverSideEncryption}:{},...O.storageClass?{"x-oss-storage-class":O.storageClass}:{}},this.multipart={createMultipart:(A,D)=>this.createMultipart(A,D),uploadPart:(A,D,K)=>this.uploadPart(A,D,K),completeMultipart:(A,D)=>this.completeMultipart(A,D),abortMultipart:(A)=>this.abortMultipart(A)}}async put(O,A,D){let K=this.writeOptions(D);if(A.size!==void 0&&A.size<=this.bufferThreshold){let L=await A.bytes(),w=_.from(L.buffer,L.byteOffset,L.byteLength);await this.call(O,()=>this.client.put(O,w,K))}else{let L=$(A.stream()),w=M(D.signal,L);try{let G=A.size===void 0?K:{...K,contentLength:A.size};await this.call(O,()=>this.client.putStream(O,L,G))}finally{w()}}return this.head(O)}async get(O,A){let D=A.range,K=D?{Range:`bytes=${D.start}-${D.end??""}`}:{},L=await this.call(O,()=>this.client.getStream(O,{headers:K}));if(A.signal.aborted)throw L.stream.destroy(),A.signal.reason;let w=L.res.headers??{},G=W(O,w),z=/bytes (\d+)-(\d+)\/(\d+)/.exec(String(w["content-range"]??""));if(z)G.size=Number(z[3]);let Q=B.toWeb(L.stream);return{info:G,body:Q,...z?{range:{start:Number(z[1]),end:Number(z[2])}}:{}}}async head(O){let A=await this.call(O,()=>this.client.head(O));if(this.client.getObjectMeta){let K=(await this.call(O,()=>this.client.getObjectMeta(O))).res.headers??{};return W(O,{...A.res.headers,...K["content-length"]===void 0?{}:{"content-length":K["content-length"]},...K.etag===void 0?{}:{etag:K.etag}})}return W(O,A.res.headers)}async delete(O){try{await this.client.delete(O)}catch(A){let D=X(A,"delete",O);if(D.code!=="NOT_FOUND")throw D}}async deleteMany(O){let A=await this.client.deleteMulti(O,{quiet:!1}),D=new Set((A.deleted??[]).map((K)=>typeof K==="string"?K:K.Key));return{deleted:O.filter((K)=>D.has(K)),failed:O.filter((K)=>!D.has(K)).map((K)=>({key:K,error:new J("BACKEND","Object was not deleted",{key:K})}))}}async list(O){let A=await this.client.list({...O.prefix?{prefix:O.prefix}:{},...O.delimiter?{delimiter:O.delimiter}:{},...O.cursor?{marker:O.cursor}:{},"max-keys":O.limit});return{objects:(A.objects??[]).map(Z),prefixes:A.prefixes??[],...A.isTruncated&&A.nextMarker?{cursor:A.nextMarker}:{}}}async copy(O,A,D){let K=D.overwrite?{}:{"x-oss-forbid-overwrite":"true"};return await this.call(O,()=>this.client.copy(A,O,{headers:K})),this.head(A)}async signUrl(O,A){let D={method:A.method,expires:A.expiresIn,...A.contentType?{"Content-Type":A.contentType}:{},...A.responseContentDisposition?{response:{"content-disposition":A.responseContentDisposition}}:{}};if(this.client.asyncSignatureUrl)return this.client.asyncSignatureUrl(O,D);if(this.client.signatureUrl)return this.client.signatureUrl(O,D);throw new J("UNSUPPORTED","ali-oss client does not provide signatureUrl")}async createMultipart(O,A){let D=await this.call(O,()=>this.client.initMultipartUpload(O,this.writeOptions(A)));return{key:O,uploadId:D.uploadId}}async uploadPart(O,A,D){let K=await D.bytes(),L=_.from(K.buffer,K.byteOffset,K.byteLength),w=await this.call(O.key,()=>this.client.uploadPart(O.key,O.uploadId,A,L,0,L.byteLength));return{partNumber:A,etag:V(w.etag)}}async completeMultipart(O,A){return await this.call(O.key,()=>this.client.completeMultipartUpload(O.key,O.uploadId,A.map((D)=>({number:D.partNumber,etag:`"${D.etag}"`})))),this.head(O.key)}async abortMultipart(O){try{await this.client.abortMultipartUpload(O.key,O.uploadId)}catch(A){let D=X(A,"abortMultipart",O.key);if(D.code!=="NOT_FOUND")throw D}}writeOptions(O){return{mime:O.contentType,meta:O.metadata,headers:{...this.baseHeaders,"Content-Type":O.contentType,...O.cacheControl?{"Cache-Control":O.cacheControl}:{},...O.contentDisposition?{"Content-Disposition":O.contentDisposition}:{},...O.overwrite?{}:{"x-oss-forbid-overwrite":"true"}}}}async call(O,A){try{return await A()}catch(D){throw U(D,O)}}}function U(O,A){let D=O;if(D?.code==="NoSuchUpload")return new J("NOT_FOUND","Multipart upload not found",{key:A,cause:O});if(D?.status===-1||D?.status===-2||D?.name==="RequestError")return new J("BACKEND","ali-oss request failed",{key:A,cause:O,retryable:!0});return X(O,void 0,A)}function M(O,A){let D=()=>A.destroy();if(O.aborted)D();else O.addEventListener("abort",D,{once:!0});return()=>O.removeEventListener("abort",D)}export{U as normalizeAliError,I as AliOssDriver};
|
|
2
|
+
|
|
3
|
+
//# debugId=54BB889CD849C70864756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["..\\src\\ali-oss\\driver.ts", "..\\src\\ali-oss\\mapping.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { Buffer } from 'node:buffer'\nimport { Readable } from 'node:stream'\nimport type {\n DriverCopyOptions,\n DriverGetOptions,\n DriverListOptions,\n DriverPutOptions,\n DriverSignOptions,\n MultipartDriver,\n StorageDriver,\n} from '../core/driver'\nimport { StorageError, toStorageError } from '../core/errors'\nimport { type StoragePayload, toNodeReadable } from '../core/payload'\nimport type {\n DeleteManyResult,\n ListResult,\n MultipartUpload,\n ObjectInfo,\n ObjectStream,\n UploadedPart,\n} from '../core/types'\nimport { assertInteger } from '../core/validation'\nimport type { AliOssClient, AliOssRequestOptions } from './client'\nimport { cleanEtag, infoFromHeaders, infoFromListObject } from './mapping'\n\n/**\n * ali-oss 适配器配置。\n */\nexport interface AliOssDriverOptions {\n /**\n * 业务创建的 ali-oss 客户端实例,例如 `new OSS({ region, bucket, accessKeyId, ... })`。\n */\n client: AliOssClient\n /**\n * 可选的服务器端加密算法,例如 `AES256` 或 `KMS`。\n */\n serverSideEncryption?: string\n /**\n * 可选的存储类型,例如 `Standard`、`IA`、`Archive`。\n */\n storageClass?: string\n /**\n * 不超过该字节数的内容读入内存后整体上传,更大的内容流式上传,默认为 8 MiB。\n *\n * 整体上传可由 SDK 与服务层安全重试;流式上传内存占用恒定但只尝试一次。\n * 大于服务层 `multipartThreshold` 的内容会先被自动转为分片上传。\n */\n bufferThreshold?: number\n}\n\n/**\n * 零配置的阿里云 OSS 适配器。\n *\n * 只需把 ali-oss 客户端实例传入即可使用全部能力:流式上传下载、批量删除、\n * 服务端复制、分页列举、原生签名 URL 与分片上传。本包不依赖 `ali-oss`,\n * 凭据只存在于业务创建的客户端中,适配器不会读取或记录。\n *\n * @example\n * ```ts\n * import OSS from 'ali-oss'\n * import { AliOssDriver } from '@lhy-meta-server/meta-oss/ali-oss'\n *\n * const driver = new AliOssDriver({ client: new OSS({ region, bucket, accessKeyId, accessKeySecret }) })\n * ```\n */\nexport class AliOssDriver implements StorageDriver {\n /**\n * 适配器名称。\n */\n public readonly name = 'ali-oss'\n /**\n * 分片上传能力。\n */\n public readonly multipart: MultipartDriver\n private readonly client: AliOssClient\n private readonly baseHeaders: Record<string, string>\n private readonly bufferThreshold: number\n\n /**\n * 创建 ali-oss 适配器。\n *\n * @param options 客户端实例与可选的加密、存储类型配置。\n * @throws {@link StorageError} 未提供客户端时抛出 `INVALID_OPTION`。\n */\n public constructor(options: AliOssDriverOptions) {\n if (!options?.client) throw new StorageError('INVALID_OPTION', 'client is required')\n this.client = options.client\n this.bufferThreshold = assertInteger('bufferThreshold', options.bufferThreshold ?? 8 * 1024 * 1024, 0)\n this.baseHeaders = {\n ...(options.serverSideEncryption ? { 'x-oss-server-side-encryption': options.serverSideEncryption } : {}),\n ...(options.storageClass ? { 'x-oss-storage-class': options.storageClass } : {}),\n }\n this.multipart = {\n createMultipart: (key, putOptions) => this.createMultipart(key, putOptions),\n uploadPart: (upload, partNumber, payload) => this.uploadPart(upload, partNumber, payload),\n completeMultipart: (upload, parts) => this.completeMultipart(upload, parts),\n abortMultipart: (upload) => this.abortMultipart(upload),\n }\n }\n\n /**\n * 上传对象。\n *\n * 不超过 `bufferThreshold` 的已知大小内容读入内存后用 `put` 上传(SDK 可安全重试);\n * 更大的内容(包括 `Blob` / `Bun.file()`)与未知大小的流一律用 `putStream` 流式上传,\n * 内存占用与文件大小无关。取消时会销毁上传流以中断请求。\n *\n * @param key 完整对象键。\n * @param payload 上传内容。\n * @param options 已归一化的写入选项。\n * @returns 对象描述信息。\n */\n public async put(key: string, payload: StoragePayload, options: DriverPutOptions): Promise<ObjectInfo> {\n const request = this.writeOptions(options)\n if (payload.size !== undefined && payload.size <= this.bufferThreshold) {\n const bytes = await payload.bytes()\n const buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n await this.call(key, () => this.client.put(key, buffer, request))\n } else {\n const stream = toNodeReadable(payload.stream())\n const release = bindAbort(options.signal, stream)\n try {\n const streamRequest = payload.size === undefined ? request : { ...request, contentLength: payload.size }\n await this.call(key, () => this.client.putStream(key, stream, streamRequest))\n } finally {\n release()\n }\n }\n return this.head(key)\n }\n\n /**\n * 以流方式下载对象,支持范围读取。\n *\n * @param key 完整对象键。\n * @param options 读取范围与取消信号。\n * @returns 对象描述信息与可读流。\n */\n public async get(key: string, options: DriverGetOptions): Promise<ObjectStream> {\n const range = options.range\n const headers: Record<string, string> = range ? { Range: `bytes=${range.start}-${range.end ?? ''}` } : {}\n const result = await this.call(key, () => this.client.getStream(key, { headers }))\n // 打开阶段被取消(或超时)时立即销毁响应流,释放连接;之后的消费由调用方通过 body.cancel() 控制。\n if (options.signal.aborted) {\n result.stream.destroy()\n throw options.signal.reason\n }\n const responseHeaders = result.res.headers ?? {}\n const info = infoFromHeaders(key, responseHeaders)\n const contentRange = /bytes (\\d+)-(\\d+)\\/(\\d+)/.exec(String(responseHeaders['content-range'] ?? ''))\n if (contentRange) info.size = Number(contentRange[3])\n const body = Readable.toWeb(result.stream) as unknown as ReadableStream<Uint8Array>\n return {\n info,\n body,\n ...(contentRange ? { range: { start: Number(contentRange[1]), end: Number(contentRange[2]) } } : {}),\n }\n }\n\n /**\n * 读取对象头部信息。\n *\n * @param key 完整对象键。\n * @returns 对象描述信息。\n */\n public async head(key: string): Promise<ObjectInfo> {\n // HeadObject 在开启 gzip 时无法返回准确大小,因此先用 getObjectMeta 获取大小与 ETag,\n // 再用 head 获取 Content-Type 与自定义元数据;旧版 SDK 没有 getObjectMeta 时退化为仅用 head。\n const result = await this.call(key, () => this.client.head(key))\n if (this.client.getObjectMeta) {\n const meta = await this.call(key, () =>\n (this.client.getObjectMeta as NonNullable<AliOssClient['getObjectMeta']>)(key),\n )\n const exact = meta.res.headers ?? {}\n return infoFromHeaders(key, {\n ...result.res.headers,\n ...(exact['content-length'] === undefined ? {} : { 'content-length': exact['content-length'] }),\n ...(exact.etag === undefined ? {} : { etag: exact.etag }),\n })\n }\n return infoFromHeaders(key, result.res.headers)\n }\n\n /**\n * 删除对象;OSS 对不存在的对象同样返回成功。\n *\n * @param key 完整对象键。\n */\n public async delete(key: string): Promise<void> {\n try {\n await this.client.delete(key)\n } catch (error) {\n const storageError = toStorageError(error, 'delete', key)\n if (storageError.code !== 'NOT_FOUND') throw storageError\n }\n }\n\n /**\n * 使用 `DeleteMultipleObjects` 批量删除。\n *\n * @param keys 完整对象键,最多 1000 个。\n * @returns 删除结果。\n */\n public async deleteMany(keys: string[]): Promise<DeleteManyResult> {\n const result = await this.client.deleteMulti(keys, { quiet: false })\n const deleted = new Set((result.deleted ?? []).map((item) => (typeof item === 'string' ? item : item.Key)))\n return {\n deleted: keys.filter((key) => deleted.has(key)),\n failed: keys\n .filter((key) => !deleted.has(key))\n .map((key) => ({ key, error: new StorageError('BACKEND', 'Object was not deleted', { key }) })),\n }\n }\n\n /**\n * 分页列举对象。\n *\n * @param options 前缀、分隔符、游标与页大小。\n * @returns 当前页结果。\n */\n public async list(options: DriverListOptions): Promise<ListResult> {\n const result = await this.client.list({\n ...(options.prefix ? { prefix: options.prefix } : {}),\n ...(options.delimiter ? { delimiter: options.delimiter } : {}),\n ...(options.cursor ? { marker: options.cursor } : {}),\n 'max-keys': options.limit,\n })\n return {\n objects: (result.objects ?? []).map(infoFromListObject),\n prefixes: result.prefixes ?? [],\n ...(result.isTruncated && result.nextMarker ? { cursor: result.nextMarker } : {}),\n }\n }\n\n /**\n * 服务端复制对象,并保留源对象的 HTTP 属性与元数据。\n *\n * 禁止覆盖时使用 `x-oss-forbid-overwrite` 由 OSS 原子拒绝。\n *\n * @param source 完整源对象键。\n * @param destination 完整目标对象键。\n * @param options 覆盖策略。\n * @returns 目标对象描述信息。\n */\n public async copy(source: string, destination: string, options: DriverCopyOptions): Promise<ObjectInfo> {\n const headers: Record<string, string> = options.overwrite ? {} : { 'x-oss-forbid-overwrite': 'true' }\n await this.call(source, () => this.client.copy(destination, source, { headers }))\n return this.head(destination)\n }\n\n /**\n * 使用 SDK 原生签名生成限时 URL,优先使用支持 STS 刷新的异步接口。\n *\n * @param key 完整对象键。\n * @param options 方法、有效期与头部约束。\n * @returns 签名 URL。\n */\n public async signUrl(key: string, options: DriverSignOptions): Promise<string> {\n const request: Record<string, unknown> = {\n method: options.method,\n expires: options.expiresIn,\n ...(options.contentType ? { 'Content-Type': options.contentType } : {}),\n ...(options.responseContentDisposition\n ? { response: { 'content-disposition': options.responseContentDisposition } }\n : {}),\n }\n if (this.client.asyncSignatureUrl) return this.client.asyncSignatureUrl(key, request)\n if (this.client.signatureUrl) return this.client.signatureUrl(key, request)\n throw new StorageError('UNSUPPORTED', 'ali-oss client does not provide signatureUrl')\n }\n\n private async createMultipart(key: string, options: DriverPutOptions): Promise<MultipartUpload> {\n const result = await this.call(key, () => this.client.initMultipartUpload(key, this.writeOptions(options)))\n return { key, uploadId: result.uploadId }\n }\n\n private async uploadPart(\n upload: MultipartUpload,\n partNumber: number,\n payload: StoragePayload,\n ): Promise<UploadedPart> {\n const bytes = await payload.bytes()\n const buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const result = await this.call(upload.key, () =>\n this.client.uploadPart(upload.key, upload.uploadId, partNumber, buffer, 0, buffer.byteLength),\n )\n return { partNumber, etag: cleanEtag(result.etag) as string }\n }\n\n private async completeMultipart(upload: MultipartUpload, parts: UploadedPart[]): Promise<ObjectInfo> {\n await this.call(upload.key, () =>\n this.client.completeMultipartUpload(\n upload.key,\n upload.uploadId,\n parts.map((part) => ({ number: part.partNumber, etag: `\"${part.etag}\"` })),\n ),\n )\n return this.head(upload.key)\n }\n\n private async abortMultipart(upload: MultipartUpload): Promise<void> {\n try {\n await this.client.abortMultipartUpload(upload.key, upload.uploadId)\n } catch (error) {\n const storageError = toStorageError(error, 'abortMultipart', upload.key)\n if (storageError.code !== 'NOT_FOUND') throw storageError\n }\n }\n\n private writeOptions(options: DriverPutOptions): AliOssRequestOptions {\n return {\n mime: options.contentType,\n meta: options.metadata,\n headers: {\n ...this.baseHeaders,\n 'Content-Type': options.contentType,\n ...(options.cacheControl ? { 'Cache-Control': options.cacheControl } : {}),\n ...(options.contentDisposition ? { 'Content-Disposition': options.contentDisposition } : {}),\n ...(options.overwrite ? {} : { 'x-oss-forbid-overwrite': 'true' }),\n },\n }\n }\n\n private async call<T>(key: string, task: () => Promise<T>): Promise<T> {\n try {\n return await task()\n } catch (error) {\n throw normalizeAliError(error, key)\n }\n }\n}\n\n/**\n * 将 ali-oss 错误归一化,额外识别 `FileAlreadyExists`、`NoSuchUpload` 与\n * `RequestError`(SDK 的网络错误状态码为 `-1` / `-2`)。\n *\n * @param error ali-oss 抛出的错误。\n * @param key 关联对象键。\n * @returns 归一化后的存储错误。\n */\nexport function normalizeAliError(error: unknown, key?: string): StorageError {\n const value = error as { name?: unknown; code?: unknown; status?: unknown } | null\n if (value?.code === 'NoSuchUpload') {\n return new StorageError('NOT_FOUND', 'Multipart upload not found', { key, cause: error })\n }\n if (value?.status === -1 || value?.status === -2 || value?.name === 'RequestError') {\n return new StorageError('BACKEND', 'ali-oss request failed', { key, cause: error, retryable: true })\n }\n return toStorageError(error, undefined, key)\n}\n\n/**\n * 信号中止时销毁 Node.js 流,使正在进行的 SDK 请求随之失败并释放连接。\n *\n * @param signal 取消信号。\n * @param stream 需要随取消销毁的流。\n * @returns 解除监听的函数。\n */\nexport function bindAbort(signal: AbortSignal, stream: Readable): () => void {\n // 不携带错误销毁:只触发 close,避免无人监听 error 时成为未处理异常;\n // 取消原因由服务层根据信号统一转换为 TIMEOUT / ABORTED。\n const onAbort = () => stream.destroy()\n if (signal.aborted) onAbort()\n else signal.addEventListener('abort', onAbort, { once: true })\n return () => signal.removeEventListener('abort', onAbort)\n}\n",
|
|
6
|
+
"import type { ObjectInfo } from '../core/types'\nimport type { AliOssListObject } from './client'\n\n/**\n * 去除 ETag 两侧引号。\n *\n * @param value 原始 ETag。\n * @returns 去除引号后的 ETag;输入不是字符串时返回 `undefined`。\n */\nexport function cleanEtag(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value.replace(/^\"|\"$/g, '') : undefined\n}\n\n/**\n * 从 ali-oss 响应头构建对象描述信息。\n *\n * @param key 完整对象键。\n * @param headers 小写响应头。\n * @returns 对象描述信息。\n */\nexport function infoFromHeaders(key: string, headers: Record<string, unknown> = {}): ObjectInfo {\n const metadata: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (name.startsWith('x-oss-meta-') && typeof value === 'string') metadata[name.slice(11)] = value\n }\n const text = (name: string) => (typeof headers[name] === 'string' ? (headers[name] as string) : undefined)\n const lastModified = text('last-modified')\n const contentType = text('content-type')\n const cacheControl = text('cache-control')\n const contentDisposition = text('content-disposition')\n const etag = cleanEtag(headers.etag)\n return {\n key,\n size: Number(headers['content-length'] ?? 0),\n metadata,\n ...(etag ? { etag } : {}),\n ...(lastModified ? { lastModified: new Date(lastModified) } : {}),\n ...(contentType ? { contentType } : {}),\n ...(cacheControl ? { cacheControl } : {}),\n ...(contentDisposition ? { contentDisposition } : {}),\n }\n}\n\n/**\n * 将 ali-oss 列举结果中的对象转换为对象描述信息;列举结果不包含元数据。\n *\n * @param object 列举结果中的对象。\n * @returns 对象描述信息。\n */\nexport function infoFromListObject(object: AliOssListObject): ObjectInfo {\n const etag = cleanEtag(object.etag)\n return {\n key: object.name,\n size: object.size,\n metadata: {},\n ...(etag ? { etag } : {}),\n ...(object.lastModified ? { lastModified: new Date(object.lastModified) } : {}),\n }\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "54BB889CD849C70864756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ObjectInfo } from '../core/types';
|
|
2
|
+
import type { AliOssListObject } from './client';
|
|
3
|
+
/**
|
|
4
|
+
* 去除 ETag 两侧引号。
|
|
5
|
+
*
|
|
6
|
+
* @param value 原始 ETag。
|
|
7
|
+
* @returns 去除引号后的 ETag;输入不是字符串时返回 `undefined`。
|
|
8
|
+
*/
|
|
9
|
+
export declare function cleanEtag(value: unknown): string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* 从 ali-oss 响应头构建对象描述信息。
|
|
12
|
+
*
|
|
13
|
+
* @param key 完整对象键。
|
|
14
|
+
* @param headers 小写响应头。
|
|
15
|
+
* @returns 对象描述信息。
|
|
16
|
+
*/
|
|
17
|
+
export declare function infoFromHeaders(key: string, headers?: Record<string, unknown>): ObjectInfo;
|
|
18
|
+
/**
|
|
19
|
+
* 将 ali-oss 列举结果中的对象转换为对象描述信息;列举结果不包含元数据。
|
|
20
|
+
*
|
|
21
|
+
* @param object 列举结果中的对象。
|
|
22
|
+
* @returns 对象描述信息。
|
|
23
|
+
*/
|
|
24
|
+
export declare function infoFromListObject(object: AliOssListObject): ObjectInfo;
|
|
25
|
+
//# sourceMappingURL=mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../src/ali-oss/mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,UAAU,CAqB9F;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CASvE"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { StoragePayload } from './payload';
|
|
2
|
+
import type { DeleteManyResult, ListResult, MultipartUpload, ObjectHttpOptions, ObjectInfo, ObjectRange, ObjectStream, SignedUrlMethod, UploadedPart, VerifiedUrl, VerifyUrlRequest } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* 服务层传给适配器的单次执行上下文。
|
|
5
|
+
*/
|
|
6
|
+
export interface DriverContext {
|
|
7
|
+
/**
|
|
8
|
+
* 合并了调用方取消与超时的信号;适配器应尽可能将其传给底层 I/O。
|
|
9
|
+
*/
|
|
10
|
+
signal: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 适配器写入对象时收到的已归一化参数。
|
|
14
|
+
*/
|
|
15
|
+
export interface DriverPutOptions extends ObjectHttpOptions, DriverContext {
|
|
16
|
+
/**
|
|
17
|
+
* 已推断或校验后的 MIME 类型。
|
|
18
|
+
*/
|
|
19
|
+
contentType: string;
|
|
20
|
+
/**
|
|
21
|
+
* 已校验的自定义元数据。
|
|
22
|
+
*/
|
|
23
|
+
metadata: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* 同名对象存在时是否覆盖;为 `false` 时适配器必须原子地拒绝并抛出 `ALREADY_EXISTS`。
|
|
26
|
+
*/
|
|
27
|
+
overwrite: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 适配器读取对象时收到的参数。
|
|
31
|
+
*/
|
|
32
|
+
export interface DriverGetOptions extends DriverContext {
|
|
33
|
+
/**
|
|
34
|
+
* 已校验的读取范围。
|
|
35
|
+
*/
|
|
36
|
+
range?: ObjectRange;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 适配器列举对象时收到的已归一化参数。
|
|
40
|
+
*/
|
|
41
|
+
export interface DriverListOptions extends DriverContext {
|
|
42
|
+
/**
|
|
43
|
+
* 对象键前缀,未设置时为空字符串。
|
|
44
|
+
*/
|
|
45
|
+
prefix: string;
|
|
46
|
+
/**
|
|
47
|
+
* 目录分隔符。
|
|
48
|
+
*/
|
|
49
|
+
delimiter?: string;
|
|
50
|
+
/**
|
|
51
|
+
* 上一页游标。
|
|
52
|
+
*/
|
|
53
|
+
cursor?: string;
|
|
54
|
+
/**
|
|
55
|
+
* 单页最大条目数。
|
|
56
|
+
*/
|
|
57
|
+
limit: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 适配器生成签名 URL 时收到的已归一化参数。
|
|
61
|
+
*/
|
|
62
|
+
export interface DriverSignOptions extends DriverContext {
|
|
63
|
+
/**
|
|
64
|
+
* HTTP 方法。
|
|
65
|
+
*/
|
|
66
|
+
method: SignedUrlMethod;
|
|
67
|
+
/**
|
|
68
|
+
* 有效期秒数。
|
|
69
|
+
*/
|
|
70
|
+
expiresIn: number;
|
|
71
|
+
/**
|
|
72
|
+
* `PUT` 签名要求的 MIME 类型。
|
|
73
|
+
*/
|
|
74
|
+
contentType?: string;
|
|
75
|
+
/**
|
|
76
|
+
* `GET` 下载时覆盖的 `Content-Disposition`。
|
|
77
|
+
*/
|
|
78
|
+
responseContentDisposition?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 适配器复制对象时收到的参数。
|
|
82
|
+
*/
|
|
83
|
+
export interface DriverCopyOptions extends DriverContext {
|
|
84
|
+
/**
|
|
85
|
+
* 目标对象存在时是否覆盖。
|
|
86
|
+
*/
|
|
87
|
+
overwrite: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 可选的分片上传能力。
|
|
91
|
+
*/
|
|
92
|
+
export interface MultipartDriver {
|
|
93
|
+
/**
|
|
94
|
+
* 创建分片上传会话。
|
|
95
|
+
*/
|
|
96
|
+
createMultipart(key: string, options: DriverPutOptions): Promise<MultipartUpload>;
|
|
97
|
+
/**
|
|
98
|
+
* 上传单个分片,分片内容总是可重复读取且大小已知。
|
|
99
|
+
*/
|
|
100
|
+
uploadPart(upload: MultipartUpload, partNumber: number, payload: StoragePayload, context: DriverContext): Promise<UploadedPart>;
|
|
101
|
+
/**
|
|
102
|
+
* 按分片序号升序合并全部分片。
|
|
103
|
+
*/
|
|
104
|
+
completeMultipart(upload: MultipartUpload, parts: UploadedPart[], context: DriverContext): Promise<ObjectInfo>;
|
|
105
|
+
/**
|
|
106
|
+
* 放弃会话并清理已上传的分片,会话不存在时应静默成功。
|
|
107
|
+
*/
|
|
108
|
+
abortMultipart(upload: MultipartUpload, context: DriverContext): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 存储适配器契约。
|
|
112
|
+
*
|
|
113
|
+
* 适配器只负责与具体后端交互;键校验、前缀、超时、重试、上传限制、
|
|
114
|
+
* 并发控制与可观测性都由 `ObjectStorage` 统一处理。适配器收到的对象键
|
|
115
|
+
* 已经包含服务级前缀并通过安全校验。
|
|
116
|
+
*
|
|
117
|
+
* 所有方法都必须把“对象不存在”归一化为 `NOT_FOUND` 的 `StorageError`。
|
|
118
|
+
* 可选能力缺失时,服务层会抛出 `UNSUPPORTED`。
|
|
119
|
+
*/
|
|
120
|
+
export interface StorageDriver {
|
|
121
|
+
/**
|
|
122
|
+
* 适配器名称,用于可观测事件,例如 `filesystem`、`ali-oss`。
|
|
123
|
+
*/
|
|
124
|
+
readonly name: string;
|
|
125
|
+
/**
|
|
126
|
+
* 写入对象并返回其描述信息。
|
|
127
|
+
*/
|
|
128
|
+
put(key: string, payload: StoragePayload, options: DriverPutOptions): Promise<ObjectInfo>;
|
|
129
|
+
/**
|
|
130
|
+
* 以流方式读取对象。
|
|
131
|
+
*/
|
|
132
|
+
get(key: string, options: DriverGetOptions): Promise<ObjectStream>;
|
|
133
|
+
/**
|
|
134
|
+
* 读取对象描述信息。
|
|
135
|
+
*/
|
|
136
|
+
head(key: string, context: DriverContext): Promise<ObjectInfo>;
|
|
137
|
+
/**
|
|
138
|
+
* 删除对象;对象不存在时应静默成功。
|
|
139
|
+
*/
|
|
140
|
+
delete(key: string, context: DriverContext): Promise<void>;
|
|
141
|
+
/**
|
|
142
|
+
* 批量删除对象;未实现时服务层会以受控并发逐个删除。
|
|
143
|
+
*/
|
|
144
|
+
deleteMany?(keys: string[], context: DriverContext): Promise<DeleteManyResult>;
|
|
145
|
+
/**
|
|
146
|
+
* 分页列举对象。
|
|
147
|
+
*/
|
|
148
|
+
list?(options: DriverListOptions): Promise<ListResult>;
|
|
149
|
+
/**
|
|
150
|
+
* 在后端内部复制对象;未实现时服务层会读取后重新写入。
|
|
151
|
+
*/
|
|
152
|
+
copy?(source: string, destination: string, options: DriverCopyOptions): Promise<ObjectInfo>;
|
|
153
|
+
/**
|
|
154
|
+
* 生成签名访问 URL。
|
|
155
|
+
*/
|
|
156
|
+
signUrl?(key: string, options: DriverSignOptions): Promise<string>;
|
|
157
|
+
/**
|
|
158
|
+
* 校验由本适配器签发的签名 URL;仅自签名的后端(如本地文件系统)需要实现。
|
|
159
|
+
*/
|
|
160
|
+
verifyUrl?(request: VerifyUrlRequest): VerifiedUrl;
|
|
161
|
+
/**
|
|
162
|
+
* 分片上传能力。
|
|
163
|
+
*/
|
|
164
|
+
multipart?: MultipartDriver;
|
|
165
|
+
/**
|
|
166
|
+
* 释放连接、句柄等资源。
|
|
167
|
+
*/
|
|
168
|
+
close?(): Promise<void>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 以最少代码接入任意第三方对象存储。
|
|
172
|
+
*
|
|
173
|
+
* 只需实现 `put`、`get`、`head`、`delete` 四个方法即可获得服务层的全部能力
|
|
174
|
+
* (校验、重试、超时、并发、可观测性、批量删除与复制降级);其余能力按需补充。
|
|
175
|
+
* 底层 SDK 抛出的 404/403/409/5xx 等错误会被服务层自动归一化。
|
|
176
|
+
*
|
|
177
|
+
* @typeParam Driver 适配器的具体类型。
|
|
178
|
+
* @param driver 适配器实现。
|
|
179
|
+
* @returns 原样返回的适配器,用于获得类型检查与推断。
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* const driver = defineDriver({
|
|
184
|
+
* name: 'my-oss',
|
|
185
|
+
* async put(key, payload, options) { ... },
|
|
186
|
+
* async get(key, options) { ... },
|
|
187
|
+
* async head(key) { ... },
|
|
188
|
+
* async delete(key) { ... },
|
|
189
|
+
* })
|
|
190
|
+
* const storage = new ObjectStorage({ driver })
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare function defineDriver<const Driver extends StorageDriver>(driver: Driver): Driver;
|
|
194
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/core/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 稳定的对象存储错误码。
|
|
3
|
+
*
|
|
4
|
+
* 业务代码应依据错误码而不是错误消息进行分支判断,错误消息可能随版本调整。
|
|
5
|
+
*/
|
|
6
|
+
export type StorageErrorCode = 'INVALID_KEY' | 'INVALID_OPTION' | 'NOT_FOUND' | 'ALREADY_EXISTS' | 'UPLOAD_REJECTED' | 'UNSUPPORTED' | 'TIMEOUT' | 'ABORTED' | 'ACCESS_DENIED' | 'CLOSED' | 'BACKEND';
|
|
7
|
+
/**
|
|
8
|
+
* 创建对象存储错误时可附加的上下文。
|
|
9
|
+
*/
|
|
10
|
+
export interface StorageErrorOptions {
|
|
11
|
+
/**
|
|
12
|
+
* 原始错误,便于排障时追溯底层 SDK 或系统调用。
|
|
13
|
+
*/
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
/**
|
|
16
|
+
* 发生错误的对象存储操作名称。
|
|
17
|
+
*/
|
|
18
|
+
operation?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 与错误关联的对象键。
|
|
21
|
+
*/
|
|
22
|
+
key?: string;
|
|
23
|
+
/**
|
|
24
|
+
* 重试同一请求是否可能成功,默认为 `false`。
|
|
25
|
+
*/
|
|
26
|
+
retryable?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 对象存储模块唯一的错误类型。
|
|
30
|
+
*
|
|
31
|
+
* 所有适配器都应把底层异常归一化为该类型,使业务层可以通过 `code`
|
|
32
|
+
* 获得一致的判断依据,并通过 `cause` 保留原始异常。
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* try {
|
|
37
|
+
* await storage.head('avatars/1.png')
|
|
38
|
+
* } catch (error) {
|
|
39
|
+
* if (isStorageError(error, 'NOT_FOUND')) return null
|
|
40
|
+
* throw error
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class StorageError extends Error {
|
|
45
|
+
/**
|
|
46
|
+
* 机器可读的稳定错误码。
|
|
47
|
+
*/
|
|
48
|
+
readonly code: StorageErrorCode;
|
|
49
|
+
/**
|
|
50
|
+
* 发生错误的操作名称。
|
|
51
|
+
*/
|
|
52
|
+
readonly operation?: string;
|
|
53
|
+
/**
|
|
54
|
+
* 与错误关联的对象键。
|
|
55
|
+
*/
|
|
56
|
+
readonly key?: string;
|
|
57
|
+
/**
|
|
58
|
+
* 重试同一请求是否可能成功。
|
|
59
|
+
*/
|
|
60
|
+
readonly retryable: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* 创建对象存储错误。
|
|
63
|
+
*
|
|
64
|
+
* @param code 稳定错误码。
|
|
65
|
+
* @param message 可读错误描述,不应包含密钥或签名等敏感信息。
|
|
66
|
+
* @param options 原始错误、操作、对象键及可重试标记。
|
|
67
|
+
*/
|
|
68
|
+
constructor(code: StorageErrorCode, message: string, options?: StorageErrorOptions);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 判断任意值是否为对象存储错误,并可选地匹配错误码。
|
|
72
|
+
*
|
|
73
|
+
* @param error 待判断的值。
|
|
74
|
+
* @param code 期望的错误码;省略时只判断类型。
|
|
75
|
+
* @returns 是否为匹配的 {@link StorageError}。
|
|
76
|
+
*/
|
|
77
|
+
export declare function isStorageError(error: unknown, code?: StorageErrorCode): error is StorageError;
|
|
78
|
+
/**
|
|
79
|
+
* 读取错误对象上的 HTTP 状态码,兼容 `status`、`statusCode` 与 `response.status`。
|
|
80
|
+
*
|
|
81
|
+
* @param error 任意错误值。
|
|
82
|
+
* @returns 状态码;不存在时返回 `undefined`。
|
|
83
|
+
*/
|
|
84
|
+
export declare function statusOf(error: unknown): number | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* 读取错误对象上的字符串错误码。
|
|
87
|
+
*
|
|
88
|
+
* @param error 任意错误值。
|
|
89
|
+
* @returns 错误码;不存在时返回 `undefined`。
|
|
90
|
+
*/
|
|
91
|
+
export declare function codeOf(error: unknown): string | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* 将任意底层异常归一化为 {@link StorageError}。
|
|
94
|
+
*
|
|
95
|
+
* 规则:已是存储错误则补充上下文后原样返回;HTTP 404 / `NoSuchKey` / `ENOENT`
|
|
96
|
+
* 映射为 `NOT_FOUND`;401、403 / `AccessDenied` / `EACCES` 映射为 `ACCESS_DENIED`;
|
|
97
|
+
* 409、412 / `EEXIST` 映射为 `ALREADY_EXISTS`;408、429、5xx 与常见瞬时网络错误
|
|
98
|
+
* 映射为可重试的 `BACKEND`;其余映射为不可重试的 `BACKEND`。
|
|
99
|
+
*
|
|
100
|
+
* @param error 底层异常。
|
|
101
|
+
* @param operation 操作名称。
|
|
102
|
+
* @param key 关联对象键。
|
|
103
|
+
* @returns 归一化后的存储错误。
|
|
104
|
+
*/
|
|
105
|
+
export declare function toStorageError(error: unknown, operation?: string, key?: string): StorageError;
|
|
106
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,gBAAgB,GAChB,WAAW,GACX,gBAAgB,GAChB,iBAAiB,GACjB,aAAa,GACb,SAAS,GACT,SAAS,GACT,eAAe,GACf,QAAQ,GACR,SAAS,CAAA;AAEb;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC;;OAEG;IACH,SAAgB,IAAI,EAAE,gBAAgB,CAAA;IACtC;;OAEG;IACH,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClC;;OAEG;IACH,SAAgB,GAAG,CAAC,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,SAAgB,SAAS,EAAE,OAAO,CAAA;IAElC;;;;;;OAMG;IACH,YAAmB,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,EAO5F;CACF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,IAAI,YAAY,CAE7F;AAeD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAI3D;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CA6B7F"}
|