@kevisual/oss 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/dist/index-BNtwSChY.d.ts +133 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +134 -0
- package/dist/services/config.d.ts +32 -0
- package/dist/services/config.js +198 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.js +199 -0
- package/package.json +30 -0
- package/readme.md +9 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as minio from 'minio';
|
|
2
|
+
import { ItemBucketMetadata, Client } from 'minio';
|
|
3
|
+
import * as minio_dist_esm_internal_type_mjs from 'minio/dist/esm/internal/type.mjs';
|
|
4
|
+
import * as stream from 'stream';
|
|
5
|
+
|
|
6
|
+
type UploadedObjectInfo = {
|
|
7
|
+
etag: string;
|
|
8
|
+
lastModified?: Date;
|
|
9
|
+
size?: number;
|
|
10
|
+
versionId: string;
|
|
11
|
+
metadata?: ItemBucketMetadata;
|
|
12
|
+
};
|
|
13
|
+
type StatObjectResult = {
|
|
14
|
+
size: number;
|
|
15
|
+
etag: string;
|
|
16
|
+
lastModified: Date;
|
|
17
|
+
metaData: ItemBucketMetadata;
|
|
18
|
+
versionId?: string | null;
|
|
19
|
+
};
|
|
20
|
+
type ListFileObject = {
|
|
21
|
+
name: string;
|
|
22
|
+
size: number;
|
|
23
|
+
lastModified: Date;
|
|
24
|
+
etag: string;
|
|
25
|
+
};
|
|
26
|
+
type ListDirectoryObject = {
|
|
27
|
+
prefix: string;
|
|
28
|
+
size: number;
|
|
29
|
+
};
|
|
30
|
+
type ListObjectResult = ListFileObject | ListDirectoryObject;
|
|
31
|
+
interface OssBaseOperation {
|
|
32
|
+
prefix: string;
|
|
33
|
+
setPrefix(prefix: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* 获取对象
|
|
36
|
+
* @param objectName 对象名
|
|
37
|
+
*/
|
|
38
|
+
getObject(objectName: string): Promise<any>;
|
|
39
|
+
/**
|
|
40
|
+
* 上传对象
|
|
41
|
+
* @param objectName 对象名
|
|
42
|
+
* @param data 数据
|
|
43
|
+
*/
|
|
44
|
+
putObject(objectName: string, data: Buffer | string, metaData?: ItemBucketMetadata): Promise<UploadedObjectInfo>;
|
|
45
|
+
/**
|
|
46
|
+
* 上传文件
|
|
47
|
+
* @param objectName 对象名
|
|
48
|
+
* @param filePath 文件路径
|
|
49
|
+
*/
|
|
50
|
+
fPutObject(objectName: string, filePath: string, metaData?: ItemBucketMetadata): Promise<UploadedObjectInfo>;
|
|
51
|
+
/**
|
|
52
|
+
* 获取对象信息
|
|
53
|
+
* @param objectName 对象名
|
|
54
|
+
*/
|
|
55
|
+
statObject(objectName: string): Promise<StatObjectResult>;
|
|
56
|
+
/**
|
|
57
|
+
* 删除对象
|
|
58
|
+
* @param objectName 对象名
|
|
59
|
+
*/
|
|
60
|
+
deleteObject(objectName: string): Promise<any>;
|
|
61
|
+
/**
|
|
62
|
+
* 列出对象
|
|
63
|
+
* @param objectName 对象名
|
|
64
|
+
* @param opts 选项
|
|
65
|
+
* @param opts.recursive 是否递归
|
|
66
|
+
* @param opts.startAfter 开始位置
|
|
67
|
+
*/
|
|
68
|
+
listObjects(objectName: string, opts?: {
|
|
69
|
+
/**
|
|
70
|
+
* 是否递归
|
|
71
|
+
*/
|
|
72
|
+
recursive?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* 开始位置
|
|
75
|
+
*/
|
|
76
|
+
startAfter?: string;
|
|
77
|
+
}): Promise<ListObjectResult[]>;
|
|
78
|
+
/**
|
|
79
|
+
* 复制对象
|
|
80
|
+
* @param sourceObject 源对象
|
|
81
|
+
* @param targetObject 目标对象
|
|
82
|
+
*/
|
|
83
|
+
copyObject: Client['copyObject'];
|
|
84
|
+
}
|
|
85
|
+
interface OssService extends OssBaseOperation {
|
|
86
|
+
owner: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type OssBaseOptions<T = {
|
|
90
|
+
[key: string]: any;
|
|
91
|
+
}> = {
|
|
92
|
+
/**
|
|
93
|
+
* 已经初始化好的minio client
|
|
94
|
+
*/
|
|
95
|
+
client?: Client;
|
|
96
|
+
/**
|
|
97
|
+
* 桶名
|
|
98
|
+
*/
|
|
99
|
+
bucketName: string;
|
|
100
|
+
/**
|
|
101
|
+
* 前缀
|
|
102
|
+
*/
|
|
103
|
+
prefix?: string;
|
|
104
|
+
} & T;
|
|
105
|
+
declare class OssBase implements OssBaseOperation {
|
|
106
|
+
client?: Client;
|
|
107
|
+
bucketName: string;
|
|
108
|
+
prefix: string;
|
|
109
|
+
/**
|
|
110
|
+
* 计算字符串或者对象的的md5值
|
|
111
|
+
*/
|
|
112
|
+
hash: (str: string | Buffer | Object) => string;
|
|
113
|
+
constructor(opts: OssBaseOptions);
|
|
114
|
+
setPrefix(prefix: string): void;
|
|
115
|
+
getObject(objectName: string): Promise<stream.Readable>;
|
|
116
|
+
getJson(objectName: string): Promise<Record<string, any>>;
|
|
117
|
+
putObject(objectName: string, data: Buffer | string | Object, metaData?: ItemBucketMetadata): Promise<minio_dist_esm_internal_type_mjs.UploadedObjectInfo>;
|
|
118
|
+
deleteObject(objectName: string): Promise<void>;
|
|
119
|
+
listObjects<IS_FILE = false>(objectName: string, opts?: {
|
|
120
|
+
recursive?: boolean;
|
|
121
|
+
startAfter?: string;
|
|
122
|
+
}): Promise<IS_FILE extends true ? ListFileObject[] : ListObjectResult[]>;
|
|
123
|
+
fPutObject(objectName: string, filePath: string, metaData?: ItemBucketMetadata): Promise<any>;
|
|
124
|
+
statObject(objectName: string): Promise<minio.BucketItemStat>;
|
|
125
|
+
copyObject(sourceObject: any, targetObject: any): Promise<minio_dist_esm_internal_type_mjs.CopyObjectResult>;
|
|
126
|
+
static create<T extends OssBase, U>(this: new (opts: OssBaseOptions<U>) => T, opts: OssBaseOptions<U>): T;
|
|
127
|
+
static fromBase<T extends OssBase, U>(this: new (opts: OssBaseOptions<U>) => T, createOpts: {
|
|
128
|
+
oss: OssBase;
|
|
129
|
+
opts: Partial<OssBaseOptions<U>>;
|
|
130
|
+
}): T;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { type ListFileObject as L, OssBase as O, type OssService as a, type OssBaseOptions as b, type ListObjectResult as c };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/util/hash.ts
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
var hash = (str) => {
|
|
4
|
+
let hashStr;
|
|
5
|
+
if (typeof str === "object") {
|
|
6
|
+
hashStr = JSON.stringify(str, null, 2);
|
|
7
|
+
} else {
|
|
8
|
+
hashStr = str;
|
|
9
|
+
}
|
|
10
|
+
return crypto.createHash("md5").update(hashStr).digest("hex");
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/index.ts
|
|
14
|
+
var OssBase = class {
|
|
15
|
+
client;
|
|
16
|
+
bucketName;
|
|
17
|
+
prefix = "";
|
|
18
|
+
/**
|
|
19
|
+
* 计算字符串或者对象的的md5值
|
|
20
|
+
*/
|
|
21
|
+
hash = hash;
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
if (!opts.client) {
|
|
24
|
+
throw new Error("client is required");
|
|
25
|
+
}
|
|
26
|
+
this.bucketName = opts.bucketName;
|
|
27
|
+
this.client = opts.client;
|
|
28
|
+
this.prefix = opts.prefix;
|
|
29
|
+
}
|
|
30
|
+
setPrefix(prefix) {
|
|
31
|
+
this.prefix = prefix;
|
|
32
|
+
}
|
|
33
|
+
async getObject(objectName) {
|
|
34
|
+
const bucketName = this.bucketName;
|
|
35
|
+
const obj = await this.client.getObject(bucketName, `${this.prefix}${objectName}`);
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
async getJson(objectName) {
|
|
39
|
+
const obj = await this.getObject(objectName);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
let data = "";
|
|
42
|
+
obj.on("data", (chunk) => {
|
|
43
|
+
data += chunk;
|
|
44
|
+
});
|
|
45
|
+
obj.on("end", () => {
|
|
46
|
+
try {
|
|
47
|
+
const jsonData = JSON.parse(data);
|
|
48
|
+
resolve(jsonData);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
reject(new Error("Failed to parse JSON"));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
obj.on("error", (err) => {
|
|
54
|
+
reject(err);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async putObject(objectName, data, metaData) {
|
|
59
|
+
let putData;
|
|
60
|
+
if (typeof data === "object") {
|
|
61
|
+
putData = JSON.stringify(data);
|
|
62
|
+
} else {
|
|
63
|
+
putData = data;
|
|
64
|
+
}
|
|
65
|
+
const size = putData.length;
|
|
66
|
+
const bucketName = this.bucketName;
|
|
67
|
+
const obj = await this.client.putObject(bucketName, `${this.prefix}${objectName}`, putData, size, metaData);
|
|
68
|
+
return obj;
|
|
69
|
+
}
|
|
70
|
+
async deleteObject(objectName) {
|
|
71
|
+
const bucketName = this.bucketName;
|
|
72
|
+
const obj = await this.client.removeObject(bucketName, `${this.prefix}${objectName}`);
|
|
73
|
+
return obj;
|
|
74
|
+
}
|
|
75
|
+
async listObjects(objectName, opts) {
|
|
76
|
+
const bucketName = this.bucketName;
|
|
77
|
+
const prefix = `${this.prefix}${objectName}`;
|
|
78
|
+
const res = await new Promise((resolve, reject) => {
|
|
79
|
+
let res2 = [];
|
|
80
|
+
let hasError = false;
|
|
81
|
+
this.client.listObjectsV2(bucketName, prefix, opts?.recursive ?? false, opts?.startAfter).on("data", (data) => {
|
|
82
|
+
res2.push(data);
|
|
83
|
+
}).on("error", (err) => {
|
|
84
|
+
console.error("minio error", prefix, err);
|
|
85
|
+
hasError = true;
|
|
86
|
+
}).on("end", () => {
|
|
87
|
+
if (hasError) {
|
|
88
|
+
reject();
|
|
89
|
+
return;
|
|
90
|
+
} else {
|
|
91
|
+
resolve(res2);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
return res;
|
|
96
|
+
}
|
|
97
|
+
async fPutObject(objectName, filePath, metaData) {
|
|
98
|
+
const bucketName = this.bucketName;
|
|
99
|
+
const obj = await this.client.fPutObject(bucketName, `${this.prefix}${objectName}`, filePath, metaData);
|
|
100
|
+
return obj;
|
|
101
|
+
}
|
|
102
|
+
async statObject(objectName) {
|
|
103
|
+
const bucketName = this.bucketName;
|
|
104
|
+
try {
|
|
105
|
+
const obj = await this.client.statObject(bucketName, `${this.prefix}${objectName}`);
|
|
106
|
+
return obj;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
if (e.code === "NotFound") {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
throw e;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async copyObject(sourceObject, targetObject) {
|
|
115
|
+
const bucketName = this.bucketName;
|
|
116
|
+
const obj = await this.client.copyObject(bucketName, sourceObject, targetObject);
|
|
117
|
+
return obj;
|
|
118
|
+
}
|
|
119
|
+
static create(opts) {
|
|
120
|
+
return new this(opts);
|
|
121
|
+
}
|
|
122
|
+
static fromBase(createOpts) {
|
|
123
|
+
const base = createOpts.oss;
|
|
124
|
+
const opts = createOpts.opts;
|
|
125
|
+
return new this({
|
|
126
|
+
client: base.client,
|
|
127
|
+
bucketName: base.bucketName,
|
|
128
|
+
...opts
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
export {
|
|
133
|
+
OssBase
|
|
134
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { O as OssBase, a as OssService, b as OssBaseOptions, L as ListFileObject, c as ListObjectResult } from '../index-BNtwSChY.js';
|
|
2
|
+
import * as minio_dist_esm_internal_type_mjs from 'minio/dist/esm/internal/type.mjs';
|
|
3
|
+
import 'minio';
|
|
4
|
+
import 'stream';
|
|
5
|
+
|
|
6
|
+
declare class ConfigOssService extends OssBase implements OssService {
|
|
7
|
+
owner: string;
|
|
8
|
+
constructor(opts: OssBaseOptions<{
|
|
9
|
+
owner: string;
|
|
10
|
+
}>);
|
|
11
|
+
listAllFile(): Promise<ListFileObject[]>;
|
|
12
|
+
listAll(): Promise<ListObjectResult[]>;
|
|
13
|
+
configMap: Map<string, any>;
|
|
14
|
+
keys: string[];
|
|
15
|
+
getAllConfigJson(): Promise<ListFileObject[]>;
|
|
16
|
+
isEndWithJson(string: string): boolean;
|
|
17
|
+
putJsonObject(key: string, data: any): Promise<minio_dist_esm_internal_type_mjs.UploadedObjectInfo>;
|
|
18
|
+
getObjectList(objectNameList: string[]): Promise<Map<string, Record<string, any>>>;
|
|
19
|
+
getList(): Promise<{
|
|
20
|
+
list: {
|
|
21
|
+
key: string;
|
|
22
|
+
name: string;
|
|
23
|
+
size: number;
|
|
24
|
+
lastModified: Date;
|
|
25
|
+
etag: string;
|
|
26
|
+
}[];
|
|
27
|
+
keys: string[];
|
|
28
|
+
keyEtagMap: Map<string, string>;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { ConfigOssService };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// src/util/hash.ts
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
var hash = (str) => {
|
|
4
|
+
let hashStr;
|
|
5
|
+
if (typeof str === "object") {
|
|
6
|
+
hashStr = JSON.stringify(str, null, 2);
|
|
7
|
+
} else {
|
|
8
|
+
hashStr = str;
|
|
9
|
+
}
|
|
10
|
+
return crypto.createHash("md5").update(hashStr).digest("hex");
|
|
11
|
+
};
|
|
12
|
+
var hashSringify = (str) => {
|
|
13
|
+
return JSON.stringify(str, null, 2);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/index.ts
|
|
17
|
+
var OssBase = class {
|
|
18
|
+
client;
|
|
19
|
+
bucketName;
|
|
20
|
+
prefix = "";
|
|
21
|
+
/**
|
|
22
|
+
* 计算字符串或者对象的的md5值
|
|
23
|
+
*/
|
|
24
|
+
hash = hash;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
if (!opts.client) {
|
|
27
|
+
throw new Error("client is required");
|
|
28
|
+
}
|
|
29
|
+
this.bucketName = opts.bucketName;
|
|
30
|
+
this.client = opts.client;
|
|
31
|
+
this.prefix = opts.prefix;
|
|
32
|
+
}
|
|
33
|
+
setPrefix(prefix) {
|
|
34
|
+
this.prefix = prefix;
|
|
35
|
+
}
|
|
36
|
+
async getObject(objectName) {
|
|
37
|
+
const bucketName = this.bucketName;
|
|
38
|
+
const obj = await this.client.getObject(bucketName, `${this.prefix}${objectName}`);
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
async getJson(objectName) {
|
|
42
|
+
const obj = await this.getObject(objectName);
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
let data = "";
|
|
45
|
+
obj.on("data", (chunk) => {
|
|
46
|
+
data += chunk;
|
|
47
|
+
});
|
|
48
|
+
obj.on("end", () => {
|
|
49
|
+
try {
|
|
50
|
+
const jsonData = JSON.parse(data);
|
|
51
|
+
resolve(jsonData);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
reject(new Error("Failed to parse JSON"));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
obj.on("error", (err) => {
|
|
57
|
+
reject(err);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async putObject(objectName, data, metaData) {
|
|
62
|
+
let putData;
|
|
63
|
+
if (typeof data === "object") {
|
|
64
|
+
putData = JSON.stringify(data);
|
|
65
|
+
} else {
|
|
66
|
+
putData = data;
|
|
67
|
+
}
|
|
68
|
+
const size = putData.length;
|
|
69
|
+
const bucketName = this.bucketName;
|
|
70
|
+
const obj = await this.client.putObject(bucketName, `${this.prefix}${objectName}`, putData, size, metaData);
|
|
71
|
+
return obj;
|
|
72
|
+
}
|
|
73
|
+
async deleteObject(objectName) {
|
|
74
|
+
const bucketName = this.bucketName;
|
|
75
|
+
const obj = await this.client.removeObject(bucketName, `${this.prefix}${objectName}`);
|
|
76
|
+
return obj;
|
|
77
|
+
}
|
|
78
|
+
async listObjects(objectName, opts) {
|
|
79
|
+
const bucketName = this.bucketName;
|
|
80
|
+
const prefix = `${this.prefix}${objectName}`;
|
|
81
|
+
const res = await new Promise((resolve, reject) => {
|
|
82
|
+
let res2 = [];
|
|
83
|
+
let hasError = false;
|
|
84
|
+
this.client.listObjectsV2(bucketName, prefix, opts?.recursive ?? false, opts?.startAfter).on("data", (data) => {
|
|
85
|
+
res2.push(data);
|
|
86
|
+
}).on("error", (err) => {
|
|
87
|
+
console.error("minio error", prefix, err);
|
|
88
|
+
hasError = true;
|
|
89
|
+
}).on("end", () => {
|
|
90
|
+
if (hasError) {
|
|
91
|
+
reject();
|
|
92
|
+
return;
|
|
93
|
+
} else {
|
|
94
|
+
resolve(res2);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return res;
|
|
99
|
+
}
|
|
100
|
+
async fPutObject(objectName, filePath, metaData) {
|
|
101
|
+
const bucketName = this.bucketName;
|
|
102
|
+
const obj = await this.client.fPutObject(bucketName, `${this.prefix}${objectName}`, filePath, metaData);
|
|
103
|
+
return obj;
|
|
104
|
+
}
|
|
105
|
+
async statObject(objectName) {
|
|
106
|
+
const bucketName = this.bucketName;
|
|
107
|
+
try {
|
|
108
|
+
const obj = await this.client.statObject(bucketName, `${this.prefix}${objectName}`);
|
|
109
|
+
return obj;
|
|
110
|
+
} catch (e) {
|
|
111
|
+
if (e.code === "NotFound") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async copyObject(sourceObject, targetObject) {
|
|
118
|
+
const bucketName = this.bucketName;
|
|
119
|
+
const obj = await this.client.copyObject(bucketName, sourceObject, targetObject);
|
|
120
|
+
return obj;
|
|
121
|
+
}
|
|
122
|
+
static create(opts) {
|
|
123
|
+
return new this(opts);
|
|
124
|
+
}
|
|
125
|
+
static fromBase(createOpts) {
|
|
126
|
+
const base = createOpts.oss;
|
|
127
|
+
const opts = createOpts.opts;
|
|
128
|
+
return new this({
|
|
129
|
+
client: base.client,
|
|
130
|
+
bucketName: base.bucketName,
|
|
131
|
+
...opts
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// src/services/config.ts
|
|
137
|
+
var ConfigOssService = class extends OssBase {
|
|
138
|
+
owner;
|
|
139
|
+
constructor(opts) {
|
|
140
|
+
super(opts);
|
|
141
|
+
this.owner = opts.owner;
|
|
142
|
+
this.setPrefix(`${this.owner}/config/1.0.0/`);
|
|
143
|
+
}
|
|
144
|
+
async listAllFile() {
|
|
145
|
+
const list = await this.listObjects("");
|
|
146
|
+
return list.filter((item) => item.size > 0 && this.isEndWithJson(item.name));
|
|
147
|
+
}
|
|
148
|
+
async listAll() {
|
|
149
|
+
return await this.listObjects("");
|
|
150
|
+
}
|
|
151
|
+
configMap = /* @__PURE__ */ new Map();
|
|
152
|
+
keys = [];
|
|
153
|
+
async getAllConfigJson() {
|
|
154
|
+
const list = await this.listAllFile();
|
|
155
|
+
return list;
|
|
156
|
+
}
|
|
157
|
+
isEndWithJson(string) {
|
|
158
|
+
return string?.endsWith?.(`.json`);
|
|
159
|
+
}
|
|
160
|
+
putJsonObject(key, data) {
|
|
161
|
+
const json = hashSringify(data);
|
|
162
|
+
return this.putObject(key, json, {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
"app-source": "user-config-app",
|
|
165
|
+
"Cache-Control": "max-age=31536000, immutable"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async getObjectList(objectNameList) {
|
|
169
|
+
const jsonMap = /* @__PURE__ */ new Map();
|
|
170
|
+
for (const objectName of objectNameList) {
|
|
171
|
+
try {
|
|
172
|
+
const json = await this.getJson(objectName);
|
|
173
|
+
jsonMap.set(objectName, json);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error(error);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return jsonMap;
|
|
180
|
+
}
|
|
181
|
+
async getList() {
|
|
182
|
+
const list = await this.listAllFile();
|
|
183
|
+
const keyEtagMap = /* @__PURE__ */ new Map();
|
|
184
|
+
const listKeys = list.map((item) => {
|
|
185
|
+
const key = item.name.replace(this.prefix, "");
|
|
186
|
+
keyEtagMap.set(key, item.etag);
|
|
187
|
+
return {
|
|
188
|
+
...item,
|
|
189
|
+
key
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
const keys = Array.from(keyEtagMap.keys());
|
|
193
|
+
return { list: listKeys, keys, keyEtagMap };
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
export {
|
|
197
|
+
ConfigOssService
|
|
198
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// src/util/hash.ts
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
var hash = (str) => {
|
|
4
|
+
let hashStr;
|
|
5
|
+
if (typeof str === "object") {
|
|
6
|
+
hashStr = JSON.stringify(str, null, 2);
|
|
7
|
+
} else {
|
|
8
|
+
hashStr = str;
|
|
9
|
+
}
|
|
10
|
+
return crypto.createHash("md5").update(hashStr).digest("hex");
|
|
11
|
+
};
|
|
12
|
+
var hashSringify = (str) => {
|
|
13
|
+
return JSON.stringify(str, null, 2);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/index.ts
|
|
17
|
+
var OssBase = class {
|
|
18
|
+
client;
|
|
19
|
+
bucketName;
|
|
20
|
+
prefix = "";
|
|
21
|
+
/**
|
|
22
|
+
* 计算字符串或者对象的的md5值
|
|
23
|
+
*/
|
|
24
|
+
hash = hash;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
if (!opts.client) {
|
|
27
|
+
throw new Error("client is required");
|
|
28
|
+
}
|
|
29
|
+
this.bucketName = opts.bucketName;
|
|
30
|
+
this.client = opts.client;
|
|
31
|
+
this.prefix = opts.prefix;
|
|
32
|
+
}
|
|
33
|
+
setPrefix(prefix) {
|
|
34
|
+
this.prefix = prefix;
|
|
35
|
+
}
|
|
36
|
+
async getObject(objectName) {
|
|
37
|
+
const bucketName = this.bucketName;
|
|
38
|
+
const obj = await this.client.getObject(bucketName, `${this.prefix}${objectName}`);
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
async getJson(objectName) {
|
|
42
|
+
const obj = await this.getObject(objectName);
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
let data = "";
|
|
45
|
+
obj.on("data", (chunk) => {
|
|
46
|
+
data += chunk;
|
|
47
|
+
});
|
|
48
|
+
obj.on("end", () => {
|
|
49
|
+
try {
|
|
50
|
+
const jsonData = JSON.parse(data);
|
|
51
|
+
resolve(jsonData);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
reject(new Error("Failed to parse JSON"));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
obj.on("error", (err) => {
|
|
57
|
+
reject(err);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async putObject(objectName, data, metaData) {
|
|
62
|
+
let putData;
|
|
63
|
+
if (typeof data === "object") {
|
|
64
|
+
putData = JSON.stringify(data);
|
|
65
|
+
} else {
|
|
66
|
+
putData = data;
|
|
67
|
+
}
|
|
68
|
+
const size = putData.length;
|
|
69
|
+
const bucketName = this.bucketName;
|
|
70
|
+
const obj = await this.client.putObject(bucketName, `${this.prefix}${objectName}`, putData, size, metaData);
|
|
71
|
+
return obj;
|
|
72
|
+
}
|
|
73
|
+
async deleteObject(objectName) {
|
|
74
|
+
const bucketName = this.bucketName;
|
|
75
|
+
const obj = await this.client.removeObject(bucketName, `${this.prefix}${objectName}`);
|
|
76
|
+
return obj;
|
|
77
|
+
}
|
|
78
|
+
async listObjects(objectName, opts) {
|
|
79
|
+
const bucketName = this.bucketName;
|
|
80
|
+
const prefix = `${this.prefix}${objectName}`;
|
|
81
|
+
const res = await new Promise((resolve, reject) => {
|
|
82
|
+
let res2 = [];
|
|
83
|
+
let hasError = false;
|
|
84
|
+
this.client.listObjectsV2(bucketName, prefix, opts?.recursive ?? false, opts?.startAfter).on("data", (data) => {
|
|
85
|
+
res2.push(data);
|
|
86
|
+
}).on("error", (err) => {
|
|
87
|
+
console.error("minio error", prefix, err);
|
|
88
|
+
hasError = true;
|
|
89
|
+
}).on("end", () => {
|
|
90
|
+
if (hasError) {
|
|
91
|
+
reject();
|
|
92
|
+
return;
|
|
93
|
+
} else {
|
|
94
|
+
resolve(res2);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return res;
|
|
99
|
+
}
|
|
100
|
+
async fPutObject(objectName, filePath, metaData) {
|
|
101
|
+
const bucketName = this.bucketName;
|
|
102
|
+
const obj = await this.client.fPutObject(bucketName, `${this.prefix}${objectName}`, filePath, metaData);
|
|
103
|
+
return obj;
|
|
104
|
+
}
|
|
105
|
+
async statObject(objectName) {
|
|
106
|
+
const bucketName = this.bucketName;
|
|
107
|
+
try {
|
|
108
|
+
const obj = await this.client.statObject(bucketName, `${this.prefix}${objectName}`);
|
|
109
|
+
return obj;
|
|
110
|
+
} catch (e) {
|
|
111
|
+
if (e.code === "NotFound") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async copyObject(sourceObject, targetObject) {
|
|
118
|
+
const bucketName = this.bucketName;
|
|
119
|
+
const obj = await this.client.copyObject(bucketName, sourceObject, targetObject);
|
|
120
|
+
return obj;
|
|
121
|
+
}
|
|
122
|
+
static create(opts) {
|
|
123
|
+
return new this(opts);
|
|
124
|
+
}
|
|
125
|
+
static fromBase(createOpts) {
|
|
126
|
+
const base = createOpts.oss;
|
|
127
|
+
const opts = createOpts.opts;
|
|
128
|
+
return new this({
|
|
129
|
+
client: base.client,
|
|
130
|
+
bucketName: base.bucketName,
|
|
131
|
+
...opts
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// src/services/config.ts
|
|
137
|
+
var ConfigOssService = class extends OssBase {
|
|
138
|
+
owner;
|
|
139
|
+
constructor(opts) {
|
|
140
|
+
super(opts);
|
|
141
|
+
this.owner = opts.owner;
|
|
142
|
+
this.setPrefix(`${this.owner}/config/1.0.0/`);
|
|
143
|
+
}
|
|
144
|
+
async listAllFile() {
|
|
145
|
+
const list = await this.listObjects("");
|
|
146
|
+
return list.filter((item) => item.size > 0 && this.isEndWithJson(item.name));
|
|
147
|
+
}
|
|
148
|
+
async listAll() {
|
|
149
|
+
return await this.listObjects("");
|
|
150
|
+
}
|
|
151
|
+
configMap = /* @__PURE__ */ new Map();
|
|
152
|
+
keys = [];
|
|
153
|
+
async getAllConfigJson() {
|
|
154
|
+
const list = await this.listAllFile();
|
|
155
|
+
return list;
|
|
156
|
+
}
|
|
157
|
+
isEndWithJson(string) {
|
|
158
|
+
return string?.endsWith?.(`.json`);
|
|
159
|
+
}
|
|
160
|
+
putJsonObject(key, data) {
|
|
161
|
+
const json = hashSringify(data);
|
|
162
|
+
return this.putObject(key, json, {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
"app-source": "user-config-app",
|
|
165
|
+
"Cache-Control": "max-age=31536000, immutable"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async getObjectList(objectNameList) {
|
|
169
|
+
const jsonMap = /* @__PURE__ */ new Map();
|
|
170
|
+
for (const objectName of objectNameList) {
|
|
171
|
+
try {
|
|
172
|
+
const json = await this.getJson(objectName);
|
|
173
|
+
jsonMap.set(objectName, json);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error(error);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return jsonMap;
|
|
180
|
+
}
|
|
181
|
+
async getList() {
|
|
182
|
+
const list = await this.listAllFile();
|
|
183
|
+
const keyEtagMap = /* @__PURE__ */ new Map();
|
|
184
|
+
const listKeys = list.map((item) => {
|
|
185
|
+
const key = item.name.replace(this.prefix, "");
|
|
186
|
+
keyEtagMap.set(key, item.etag);
|
|
187
|
+
return {
|
|
188
|
+
...item,
|
|
189
|
+
key
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
const keys = Array.from(keyEtagMap.keys());
|
|
193
|
+
return { list: listKeys, keys, keyEtagMap };
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
export {
|
|
197
|
+
ConfigOssService,
|
|
198
|
+
OssBase
|
|
199
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kevisual/oss",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsup",
|
|
8
|
+
"dev": "tsup --watch",
|
|
9
|
+
"dev:lib": "tsup --watch"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"dotenv": "^16.4.7",
|
|
20
|
+
"minio": "^8.0.5",
|
|
21
|
+
"tsup": "^8.4.0"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
"./*": "./dist/*.js",
|
|
25
|
+
"./services": "./dist/services/index.js"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|