@bejibun/storage 0.1.0 → 0.1.11
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/.prettierignore +45 -0
- package/.prettierrc.json +14 -0
- package/CHANGELOG.md +74 -0
- package/README.md +24 -0
- package/benchmarks/README.md +46 -0
- package/benchmarks/package.json +12 -0
- package/benchmarks/scripts/coldstart-baseline.mjs +9 -0
- package/benchmarks/scripts/coldstart-optimized.mjs +9 -0
- package/benchmarks/scripts/coldstart.mjs +93 -0
- package/benchmarks/scripts/readme-writer.mjs +35 -0
- package/benchmarks/scripts/table-format.mjs +123 -0
- package/benchmarks/scripts/throughput-baseline.mjs +68 -0
- package/benchmarks/scripts/throughput-optimized.mjs +68 -0
- package/benchmarks/scripts/throughput.mjs +83 -0
- package/builders/StorageBuilder.d.ts +117 -0
- package/builders/StorageBuilder.js +165 -32
- package/builders/storage/StorageLocalBuilder.d.ts +89 -0
- package/builders/storage/StorageLocalBuilder.js +119 -25
- package/builders/storage/StorageS3Builder.d.ts +90 -0
- package/builders/storage/StorageS3Builder.js +117 -22
- package/config/storage.d.ts +3 -0
- package/config/storage.js +8 -0
- package/configure.js +6 -2
- package/enums/StorageDiskDriverEnum.d.ts +5 -0
- package/enums/StorageDiskDriverEnum.js +5 -0
- package/enums/index.d.ts +4 -1
- package/enums/index.js +4 -1
- package/eslint.config.js +61 -0
- package/exceptions/StorageException.d.ts +10 -0
- package/exceptions/StorageException.js +10 -0
- package/exceptions/index.d.ts +4 -1
- package/exceptions/index.js +4 -1
- package/facades/Storage.d.ts +87 -0
- package/facades/Storage.js +88 -1
- package/facades/index.d.ts +4 -1
- package/facades/index.js +4 -1
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/package.json +23 -12
- package/tests/integration/storage.integration.test.ts +145 -0
- package/tests/unit/storage.test.ts +177 -0
- package/tsconfig.json +2 -2
- package/types/index.d.ts +4 -1
- package/types/storage.d.ts +138 -138
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
mock,
|
|
7
|
+
test
|
|
8
|
+
} from "bun:test";
|
|
9
|
+
import StorageBuilder from "../../src/builders/StorageBuilder";
|
|
10
|
+
import StorageException from "../../src/exceptions/StorageException";
|
|
11
|
+
import Storage from "../../src/facades/Storage";
|
|
12
|
+
|
|
13
|
+
const log = mock(console.log);
|
|
14
|
+
const error = mock(console.error);
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
log.mockReset();
|
|
18
|
+
error.mockReset();
|
|
19
|
+
console.log = log;
|
|
20
|
+
console.error = error;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
console.log = console.log;
|
|
25
|
+
console.error = console.error;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("StorageBuilder", () => {
|
|
29
|
+
test("build applies the disk override and returns the builder", () => {
|
|
30
|
+
const disk = {driver: "local", root: "/tmp"};
|
|
31
|
+
const builder = new StorageBuilder().build(disk);
|
|
32
|
+
|
|
33
|
+
expect(builder).toBeInstanceOf(StorageBuilder);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("disk selects a disk by name and returns the builder", () => {
|
|
37
|
+
const builder = new StorageBuilder().disk("local");
|
|
38
|
+
|
|
39
|
+
expect(builder).toBeInstanceOf(StorageBuilder);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("exists throws when the file path is empty", async () => {
|
|
43
|
+
const builder = new StorageBuilder();
|
|
44
|
+
|
|
45
|
+
const error: any = await builder.exists("").catch((e) => e);
|
|
46
|
+
|
|
47
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
48
|
+
expect(error.message).toBe("The file path is required.");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("missing throws when the file path is empty", async () => {
|
|
52
|
+
const builder = new StorageBuilder();
|
|
53
|
+
|
|
54
|
+
const error: any = await builder.missing("").catch((e) => e);
|
|
55
|
+
|
|
56
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
57
|
+
expect(error.message).toBe("The file path is required.");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("metadata throws when the file path is empty", async () => {
|
|
61
|
+
const builder = new StorageBuilder();
|
|
62
|
+
|
|
63
|
+
const error: any = await builder.metadata("").catch((e) => e);
|
|
64
|
+
|
|
65
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
66
|
+
expect(error.message).toBe("The file path is required.");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("size throws when the file path is empty", async () => {
|
|
70
|
+
const builder = new StorageBuilder();
|
|
71
|
+
|
|
72
|
+
const error: any = await builder.size("").catch((e) => e);
|
|
73
|
+
|
|
74
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
75
|
+
expect(error.message).toBe("The file path is required.");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("mimeType throws when the file path is empty", async () => {
|
|
79
|
+
const builder = new StorageBuilder();
|
|
80
|
+
|
|
81
|
+
const error: any = await builder.mimeType("").catch((e) => e);
|
|
82
|
+
|
|
83
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
84
|
+
expect(error.message).toBe("The file path is required.");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("lastModified throws when the file path is empty", async () => {
|
|
88
|
+
const builder = new StorageBuilder();
|
|
89
|
+
|
|
90
|
+
const error: any = await builder.lastModified("").catch((e) => e);
|
|
91
|
+
|
|
92
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
93
|
+
expect(error.message).toBe("The file path is required.");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("get throws when the file path is empty", async () => {
|
|
97
|
+
const builder = new StorageBuilder();
|
|
98
|
+
|
|
99
|
+
const error: any = await builder.get("").catch((e) => e);
|
|
100
|
+
|
|
101
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
102
|
+
expect(error.message).toBe("The file path is required.");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("put throws when the file path or content is empty", async () => {
|
|
106
|
+
const builder = new StorageBuilder();
|
|
107
|
+
|
|
108
|
+
const pathError: any = await builder.put("", "x").catch((e) => e);
|
|
109
|
+
|
|
110
|
+
expect(pathError).toBeInstanceOf(StorageException);
|
|
111
|
+
expect(pathError.message).toBe("The file path is required.");
|
|
112
|
+
|
|
113
|
+
const contentError: any = await builder.put("file.txt", "").catch((e) => e);
|
|
114
|
+
|
|
115
|
+
expect(contentError).toBeInstanceOf(StorageException);
|
|
116
|
+
expect(contentError.message).toBe("The content is required.");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("copy throws when the source or destination path is empty", async () => {
|
|
120
|
+
const builder = new StorageBuilder();
|
|
121
|
+
|
|
122
|
+
const sourceError: any = await builder.copy("", "dst").catch((e) => e);
|
|
123
|
+
|
|
124
|
+
expect(sourceError.message).toBe("The source file path is required.");
|
|
125
|
+
|
|
126
|
+
const destError: any = await builder.copy("src", "").catch((e) => e);
|
|
127
|
+
|
|
128
|
+
expect(destError.message).toBe("The destination file path is required.");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("move throws when the source or destination path is empty", async () => {
|
|
132
|
+
const builder = new StorageBuilder();
|
|
133
|
+
|
|
134
|
+
const sourceError: any = await builder.move("", "dst").catch((e) => e);
|
|
135
|
+
|
|
136
|
+
expect(sourceError.message).toBe("The source file path is required.");
|
|
137
|
+
|
|
138
|
+
const destError: any = await builder.move("src", "").catch((e) => e);
|
|
139
|
+
|
|
140
|
+
expect(destError.message).toBe("The destination file path is required.");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("delete throws when the file path is empty", async () => {
|
|
144
|
+
const builder = new StorageBuilder();
|
|
145
|
+
|
|
146
|
+
const error: any = await builder.delete("").catch((e) => e);
|
|
147
|
+
|
|
148
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
149
|
+
expect(error.message).toBe("The file path is required.");
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("Storage facade", () => {
|
|
154
|
+
test("build returns a StorageBuilder", () => {
|
|
155
|
+
expect(Storage.build({driver: "local", root: "/tmp"})).toBeInstanceOf(
|
|
156
|
+
StorageBuilder
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("disk returns a StorageBuilder", () => {
|
|
161
|
+
expect(Storage.disk("local")).toBeInstanceOf(StorageBuilder);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("exists throws when the file path is empty", async () => {
|
|
165
|
+
const error: any = await Storage.exists("").catch((e) => e);
|
|
166
|
+
|
|
167
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
168
|
+
expect(error.message).toBe("The file path is required.");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("put throws when the file path is empty", async () => {
|
|
172
|
+
const error: any = await Storage.put("", "x").catch((e) => e);
|
|
173
|
+
|
|
174
|
+
expect(error).toBeInstanceOf(StorageException);
|
|
175
|
+
expect(error.message).toBe("The file path is required.");
|
|
176
|
+
});
|
|
177
|
+
});
|
package/tsconfig.json
CHANGED
package/types/index.d.ts
CHANGED
package/types/storage.d.ts
CHANGED
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
import type {Stats} from "fs";
|
|
2
|
-
|
|
3
|
-
export type StorageDisk = {
|
|
4
|
-
driver: string;
|
|
5
|
-
[key: string]: unknown;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export type StorageOptions = {
|
|
9
|
-
mode?: number;
|
|
10
|
-
createPath?: boolean;
|
|
11
|
-
acl?:
|
|
12
|
-
| "private"
|
|
13
|
-
| "public-read"
|
|
14
|
-
| "public-read-write"
|
|
15
|
-
| "aws-exec-read"
|
|
16
|
-
| "authenticated-read"
|
|
17
|
-
| "bucket-owner-read"
|
|
18
|
-
| "bucket-owner-full-control"
|
|
19
|
-
| "log-delivery-write";
|
|
20
|
-
bucket?: string;
|
|
21
|
-
region?: string;
|
|
22
|
-
accessKeyId?: string;
|
|
23
|
-
secretAccessKey?: string;
|
|
24
|
-
sessionToken?: string;
|
|
25
|
-
endpoint?: string;
|
|
26
|
-
virtualHostedStyle?: boolean;
|
|
27
|
-
partSize?: number;
|
|
28
|
-
queueSize?: number;
|
|
29
|
-
retry?: number;
|
|
30
|
-
type?: string;
|
|
31
|
-
contentDisposition?: string | undefined;
|
|
32
|
-
storageClass?:
|
|
33
|
-
| "STANDARD"
|
|
34
|
-
| "DEEP_ARCHIVE"
|
|
35
|
-
| "EXPRESS_ONEZONE"
|
|
36
|
-
| "GLACIER"
|
|
37
|
-
| "GLACIER_IR"
|
|
38
|
-
| "INTELLIGENT_TIERING"
|
|
39
|
-
| "ONEZONE_IA"
|
|
40
|
-
| "OUTPOSTS"
|
|
41
|
-
| "REDUCED_REDUNDANCY"
|
|
42
|
-
| "SNOW"
|
|
43
|
-
| "STANDARD_IA";
|
|
44
|
-
requestPayer?: boolean;
|
|
45
|
-
highWaterMark?: number;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export interface StorageDriver {
|
|
49
|
-
/**
|
|
50
|
-
* Determine whether a file exists.
|
|
51
|
-
*
|
|
52
|
-
* @param filepath The path to the file.
|
|
53
|
-
* @returns True if the file exists; otherwise false.
|
|
54
|
-
*/
|
|
55
|
-
exists(filepath: string): Promise<boolean>;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Determine whether a file is missing.
|
|
59
|
-
*
|
|
60
|
-
* @param filepath The path to the file.
|
|
61
|
-
* @returns True if the file does not exist; otherwise false.
|
|
62
|
-
*/
|
|
63
|
-
missing(filepath: string): Promise<boolean>;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Retrieve metadata for a file.
|
|
67
|
-
*
|
|
68
|
-
* @param filepath The path to the file.
|
|
69
|
-
* @returns File metadata and statistics.
|
|
70
|
-
*/
|
|
71
|
-
metadata(filepath: string): Promise<Stats | Bun.S3Stats>;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get the file size in bytes.
|
|
75
|
-
*
|
|
76
|
-
* @param filepath The path to the file.
|
|
77
|
-
* @returns The file size in bytes.
|
|
78
|
-
*/
|
|
79
|
-
size(filepath: string): Promise<number>;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Get the file MIME type.
|
|
83
|
-
*
|
|
84
|
-
* @param filepath The path to the file.
|
|
85
|
-
* @returns The detected MIME type.
|
|
86
|
-
*/
|
|
87
|
-
mimeType(filepath: string): Promise<string>;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get the file's last modification date.
|
|
91
|
-
*
|
|
92
|
-
* @param filepath The path to the file.
|
|
93
|
-
* @returns The last modified timestamp.
|
|
94
|
-
*/
|
|
95
|
-
lastModified(filepath: string): Promise<Date>;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Retrieve a file from storage.
|
|
99
|
-
*
|
|
100
|
-
* @param filepath The path to the file.
|
|
101
|
-
* @returns The storage file instance.
|
|
102
|
-
*/
|
|
103
|
-
get(filepath: string): Promise<Bun.BunFile | Bun.S3File>;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Store content at the given path.
|
|
107
|
-
*
|
|
108
|
-
* @param filepath The destination file path.
|
|
109
|
-
* @param content The content to store.
|
|
110
|
-
* @param options Additional storage options.
|
|
111
|
-
*/
|
|
112
|
-
put(filepath: string, content: any, options?: StorageOptions): Promise<void>;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Copy a file to a new location.
|
|
116
|
-
*
|
|
117
|
-
* @param source The source file path.
|
|
118
|
-
* @param destination The destination file path.
|
|
119
|
-
* @param options Additional storage options.
|
|
120
|
-
*/
|
|
121
|
-
copy(source: string, destination: string, options?: StorageOptions): Promise<void>;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Move a file to a new location.
|
|
125
|
-
*
|
|
126
|
-
* @param source The source file path.
|
|
127
|
-
* @param destination The destination file path.
|
|
128
|
-
* @param options Additional storage options.
|
|
129
|
-
*/
|
|
130
|
-
move(source: string, destination: string, options?: StorageOptions): Promise<void>;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Delete a file from storage.
|
|
134
|
-
*
|
|
135
|
-
* @param filepath The path to the file.
|
|
136
|
-
*/
|
|
137
|
-
delete(filepath: string): Promise<void>;
|
|
138
|
-
}
|
|
1
|
+
import type {Stats} from "fs";
|
|
2
|
+
|
|
3
|
+
export type StorageDisk = {
|
|
4
|
+
driver: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type StorageOptions = {
|
|
9
|
+
mode?: number;
|
|
10
|
+
createPath?: boolean;
|
|
11
|
+
acl?:
|
|
12
|
+
| "private"
|
|
13
|
+
| "public-read"
|
|
14
|
+
| "public-read-write"
|
|
15
|
+
| "aws-exec-read"
|
|
16
|
+
| "authenticated-read"
|
|
17
|
+
| "bucket-owner-read"
|
|
18
|
+
| "bucket-owner-full-control"
|
|
19
|
+
| "log-delivery-write";
|
|
20
|
+
bucket?: string;
|
|
21
|
+
region?: string;
|
|
22
|
+
accessKeyId?: string;
|
|
23
|
+
secretAccessKey?: string;
|
|
24
|
+
sessionToken?: string;
|
|
25
|
+
endpoint?: string;
|
|
26
|
+
virtualHostedStyle?: boolean;
|
|
27
|
+
partSize?: number;
|
|
28
|
+
queueSize?: number;
|
|
29
|
+
retry?: number;
|
|
30
|
+
type?: string;
|
|
31
|
+
contentDisposition?: string | undefined;
|
|
32
|
+
storageClass?:
|
|
33
|
+
| "STANDARD"
|
|
34
|
+
| "DEEP_ARCHIVE"
|
|
35
|
+
| "EXPRESS_ONEZONE"
|
|
36
|
+
| "GLACIER"
|
|
37
|
+
| "GLACIER_IR"
|
|
38
|
+
| "INTELLIGENT_TIERING"
|
|
39
|
+
| "ONEZONE_IA"
|
|
40
|
+
| "OUTPOSTS"
|
|
41
|
+
| "REDUCED_REDUNDANCY"
|
|
42
|
+
| "SNOW"
|
|
43
|
+
| "STANDARD_IA";
|
|
44
|
+
requestPayer?: boolean;
|
|
45
|
+
highWaterMark?: number;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export interface StorageDriver {
|
|
49
|
+
/**
|
|
50
|
+
* Determine whether a file exists.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} filepath The path to the file.
|
|
53
|
+
* @returns {boolean} True if the file exists; otherwise false.
|
|
54
|
+
*/
|
|
55
|
+
exists(filepath: string): Promise<boolean>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Determine whether a file is missing.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} filepath The path to the file.
|
|
61
|
+
* @returns {boolean} True if the file does not exist; otherwise false.
|
|
62
|
+
*/
|
|
63
|
+
missing(filepath: string): Promise<boolean>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Retrieve metadata for a file.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} filepath The path to the file.
|
|
69
|
+
* @returns {Stats|Bun.S3Stats} File metadata and statistics.
|
|
70
|
+
*/
|
|
71
|
+
metadata(filepath: string): Promise<Stats | Bun.S3Stats>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get the file size in bytes.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} filepath The path to the file.
|
|
77
|
+
* @returns {number} The file size in bytes.
|
|
78
|
+
*/
|
|
79
|
+
size(filepath: string): Promise<number>;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the file MIME type.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} filepath The path to the file.
|
|
85
|
+
* @returns {string} The detected MIME type.
|
|
86
|
+
*/
|
|
87
|
+
mimeType(filepath: string): Promise<string>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the file's last modification date.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} filepath The path to the file.
|
|
93
|
+
* @returns {Date} The last modified timestamp.
|
|
94
|
+
*/
|
|
95
|
+
lastModified(filepath: string): Promise<Date>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Retrieve a file from storage.
|
|
99
|
+
*
|
|
100
|
+
* @param {string} filepath The path to the file.
|
|
101
|
+
* @returns {Bun.BunFile|Bun.S3File} The storage file instance.
|
|
102
|
+
*/
|
|
103
|
+
get(filepath: string): Promise<Bun.BunFile | Bun.S3File>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Store content at the given path.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} filepath The destination file path.
|
|
109
|
+
* @param {any} content The content to store.
|
|
110
|
+
* @param {StorageOptions} options Additional storage options.
|
|
111
|
+
*/
|
|
112
|
+
put(filepath: string, content: any, options?: StorageOptions): Promise<void>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Copy a file to a new location.
|
|
116
|
+
*
|
|
117
|
+
* @param {string} source The source file path.
|
|
118
|
+
* @param {string} destination The destination file path.
|
|
119
|
+
* @param {StorageOptions} options Additional storage options.
|
|
120
|
+
*/
|
|
121
|
+
copy(source: string, destination: string, options?: StorageOptions): Promise<void>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Move a file to a new location.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} source The source file path.
|
|
127
|
+
* @param {string} destination The destination file path.
|
|
128
|
+
* @param {StorageOptions} options Additional storage options.
|
|
129
|
+
*/
|
|
130
|
+
move(source: string, destination: string, options?: StorageOptions): Promise<void>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Delete a file from storage.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} filepath The path to the file.
|
|
136
|
+
*/
|
|
137
|
+
delete(filepath: string): Promise<void>;
|
|
138
|
+
}
|