@contractspec/lib.files 1.57.0 → 1.58.0
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/contracts/index.d.ts +1080 -1086
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +575 -854
- package/dist/docs/files.docblock.d.ts +2 -1
- package/dist/docs/files.docblock.d.ts.map +1 -0
- package/dist/docs/files.docblock.js +17 -22
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +66 -1
- package/dist/entities/index.d.ts +134 -139
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +228 -257
- package/dist/events.d.ts +357 -363
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +217 -400
- package/dist/files.capability.d.ts +2 -7
- package/dist/files.capability.d.ts.map +1 -1
- package/dist/files.capability.js +29 -25
- package/dist/files.feature.d.ts +1 -6
- package/dist/files.feature.d.ts.map +1 -1
- package/dist/files.feature.js +50 -131
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1411 -8
- package/dist/node/contracts/index.js +576 -0
- package/dist/node/docs/files.docblock.js +65 -0
- package/dist/node/docs/index.js +65 -0
- package/dist/node/entities/index.js +235 -0
- package/dist/node/events.js +219 -0
- package/dist/node/files.capability.js +28 -0
- package/dist/node/files.feature.js +51 -0
- package/dist/node/index.js +1410 -0
- package/dist/node/storage/index.js +268 -0
- package/dist/storage/index.d.ts +163 -166
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +266 -266
- package/package.json +104 -30
- package/dist/contracts/index.js.map +0 -1
- package/dist/docs/files.docblock.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/files.capability.js.map +0 -1
- package/dist/files.feature.js.map +0 -1
- package/dist/storage/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/index.js
CHANGED
|
@@ -1,269 +1,269 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import * as
|
|
1
|
+
// @bun
|
|
2
|
+
// src/storage/index.ts
|
|
3
|
+
import * as fs from "fs/promises";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import * as crypto from "crypto";
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const { bucket, region, endpoint } = this.config;
|
|
164
|
-
if (endpoint) return `${endpoint}/${bucket}/${filePath}`;
|
|
165
|
-
return `https://${bucket}.s3.${region}.amazonaws.com/${filePath}`;
|
|
166
|
-
}
|
|
167
|
-
async copy(_sourcePath, _destinationPath) {
|
|
168
|
-
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the copy method.");
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
/**
|
|
172
|
-
* In-memory storage adapter for testing.
|
|
173
|
-
*/
|
|
174
|
-
var InMemoryStorageAdapter = class {
|
|
175
|
-
provider = "LOCAL";
|
|
176
|
-
files = /* @__PURE__ */ new Map();
|
|
177
|
-
async upload(options) {
|
|
178
|
-
const content = typeof options.content === "string" ? Buffer.from(options.content, "base64") : options.content;
|
|
179
|
-
const checksum = crypto.createHash("sha256").update(content).digest("hex");
|
|
180
|
-
const metadata = {
|
|
181
|
-
path: options.path,
|
|
182
|
-
size: content.length,
|
|
183
|
-
mimeType: options.mimeType,
|
|
184
|
-
checksum,
|
|
185
|
-
metadata: options.metadata
|
|
186
|
-
};
|
|
187
|
-
this.files.set(options.path, {
|
|
188
|
-
content,
|
|
189
|
-
metadata
|
|
190
|
-
});
|
|
191
|
-
return metadata;
|
|
192
|
-
}
|
|
193
|
-
async download(filePath) {
|
|
194
|
-
const file = this.files.get(filePath);
|
|
195
|
-
if (!file) throw new Error(`File not found: ${filePath}`);
|
|
196
|
-
return file.content;
|
|
197
|
-
}
|
|
198
|
-
async delete(filePath) {
|
|
199
|
-
this.files.delete(filePath);
|
|
200
|
-
}
|
|
201
|
-
async exists(filePath) {
|
|
202
|
-
return this.files.has(filePath);
|
|
203
|
-
}
|
|
204
|
-
async getMetadata(filePath) {
|
|
205
|
-
return this.files.get(filePath)?.metadata || null;
|
|
206
|
-
}
|
|
207
|
-
async list(options) {
|
|
208
|
-
const prefix = options?.prefix || "";
|
|
209
|
-
const files = [];
|
|
210
|
-
for (const [path, file] of this.files) if (path.startsWith(prefix)) files.push(file.metadata);
|
|
211
|
-
const limit = options?.limit || files.length;
|
|
212
|
-
return {
|
|
213
|
-
files: files.slice(0, limit),
|
|
214
|
-
hasMore: files.length > limit
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
async createPresignedUpload(options) {
|
|
218
|
-
const expiresAt = new Date(Date.now() + (options.expiresIn || 3600) * 1e3);
|
|
219
|
-
return {
|
|
220
|
-
url: `/upload?path=${encodeURIComponent(options.path)}`,
|
|
221
|
-
fields: { path: options.path },
|
|
222
|
-
expiresAt
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
async createPresignedDownload(options) {
|
|
226
|
-
const expiresAt = new Date(Date.now() + (options.expiresIn || 3600) * 1e3);
|
|
227
|
-
return {
|
|
228
|
-
url: `/download/${options.path}`,
|
|
229
|
-
expiresAt
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
getPublicUrl(filePath) {
|
|
233
|
-
return `/files/${filePath}`;
|
|
234
|
-
}
|
|
235
|
-
async copy(sourcePath, destinationPath) {
|
|
236
|
-
const source = this.files.get(sourcePath);
|
|
237
|
-
if (!source) throw new Error(`Source file not found: ${sourcePath}`);
|
|
238
|
-
const metadata = {
|
|
239
|
-
...source.metadata,
|
|
240
|
-
path: destinationPath
|
|
241
|
-
};
|
|
242
|
-
this.files.set(destinationPath, {
|
|
243
|
-
content: source.content,
|
|
244
|
-
metadata
|
|
245
|
-
});
|
|
246
|
-
return metadata;
|
|
247
|
-
}
|
|
248
|
-
clear() {
|
|
249
|
-
this.files.clear();
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
/**
|
|
253
|
-
* Create a storage adapter based on configuration.
|
|
254
|
-
*/
|
|
255
|
-
function createStorageAdapter(config) {
|
|
256
|
-
switch (config.provider) {
|
|
257
|
-
case "LOCAL":
|
|
258
|
-
if (!config.local) throw new Error("Local storage configuration required");
|
|
259
|
-
return new LocalStorageAdapter(config.local);
|
|
260
|
-
case "S3":
|
|
261
|
-
if (!config.s3) throw new Error("S3 storage configuration required");
|
|
262
|
-
return new S3StorageAdapter(config.s3);
|
|
263
|
-
default: throw new Error(`Unsupported storage provider: ${config.provider}`);
|
|
264
|
-
}
|
|
7
|
+
class LocalStorageAdapter {
|
|
8
|
+
provider = "LOCAL";
|
|
9
|
+
basePath;
|
|
10
|
+
baseUrl;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.basePath = options.basePath;
|
|
13
|
+
this.baseUrl = options.baseUrl;
|
|
14
|
+
}
|
|
15
|
+
async upload(options) {
|
|
16
|
+
const fullPath = path.join(this.basePath, options.path);
|
|
17
|
+
const dir = path.dirname(fullPath);
|
|
18
|
+
await fs.mkdir(dir, { recursive: true });
|
|
19
|
+
const content = typeof options.content === "string" ? Buffer.from(options.content, "base64") : options.content;
|
|
20
|
+
await fs.writeFile(fullPath, content);
|
|
21
|
+
const checksum = crypto.createHash("sha256").update(content).digest("hex");
|
|
22
|
+
return {
|
|
23
|
+
path: options.path,
|
|
24
|
+
size: content.length,
|
|
25
|
+
mimeType: options.mimeType,
|
|
26
|
+
checksum,
|
|
27
|
+
metadata: options.metadata
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async download(filePath) {
|
|
31
|
+
const fullPath = path.join(this.basePath, filePath);
|
|
32
|
+
return fs.readFile(fullPath);
|
|
33
|
+
}
|
|
34
|
+
async delete(filePath) {
|
|
35
|
+
const fullPath = path.join(this.basePath, filePath);
|
|
36
|
+
await fs.unlink(fullPath);
|
|
37
|
+
}
|
|
38
|
+
async exists(filePath) {
|
|
39
|
+
const fullPath = path.join(this.basePath, filePath);
|
|
40
|
+
try {
|
|
41
|
+
await fs.access(fullPath);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async getMetadata(filePath) {
|
|
48
|
+
const fullPath = path.join(this.basePath, filePath);
|
|
49
|
+
try {
|
|
50
|
+
const stat2 = await fs.stat(fullPath);
|
|
51
|
+
return {
|
|
52
|
+
path: filePath,
|
|
53
|
+
size: stat2.size,
|
|
54
|
+
mimeType: "application/octet-stream"
|
|
55
|
+
};
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async list(options) {
|
|
61
|
+
const dir = options?.prefix ? path.join(this.basePath, options.prefix) : this.basePath;
|
|
62
|
+
try {
|
|
63
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
64
|
+
const files = [];
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (entry.isFile()) {
|
|
67
|
+
const filePath = options?.prefix ? path.join(options.prefix, entry.name) : entry.name;
|
|
68
|
+
const stat2 = await fs.stat(path.join(dir, entry.name));
|
|
69
|
+
files.push({
|
|
70
|
+
path: filePath,
|
|
71
|
+
size: stat2.size,
|
|
72
|
+
mimeType: "application/octet-stream"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const limit = options?.limit || files.length;
|
|
77
|
+
return {
|
|
78
|
+
files: files.slice(0, limit),
|
|
79
|
+
hasMore: files.length > limit
|
|
80
|
+
};
|
|
81
|
+
} catch {
|
|
82
|
+
return { files: [], hasMore: false };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async createPresignedUpload(options) {
|
|
86
|
+
const expiresIn = options.expiresIn || 3600;
|
|
87
|
+
const expiresAt = new Date(Date.now() + expiresIn * 1000);
|
|
88
|
+
return {
|
|
89
|
+
url: this.baseUrl ? `${this.baseUrl}/upload?path=${encodeURIComponent(options.path)}` : `/upload?path=${encodeURIComponent(options.path)}`,
|
|
90
|
+
fields: {
|
|
91
|
+
path: options.path,
|
|
92
|
+
mimeType: options.mimeType
|
|
93
|
+
},
|
|
94
|
+
expiresAt
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async createPresignedDownload(options) {
|
|
98
|
+
const expiresIn = options.expiresIn || 3600;
|
|
99
|
+
const expiresAt = new Date(Date.now() + expiresIn * 1000);
|
|
100
|
+
return {
|
|
101
|
+
url: this.baseUrl ? `${this.baseUrl}/download/${options.path}` : `/download/${options.path}`,
|
|
102
|
+
expiresAt
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
getPublicUrl(filePath) {
|
|
106
|
+
if (!this.baseUrl)
|
|
107
|
+
return null;
|
|
108
|
+
return `${this.baseUrl}/${filePath}`;
|
|
109
|
+
}
|
|
110
|
+
async copy(sourcePath, destinationPath) {
|
|
111
|
+
const sourceFullPath = path.join(this.basePath, sourcePath);
|
|
112
|
+
const destFullPath = path.join(this.basePath, destinationPath);
|
|
113
|
+
const destDir = path.dirname(destFullPath);
|
|
114
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
115
|
+
await fs.copyFile(sourceFullPath, destFullPath);
|
|
116
|
+
const stat2 = await fs.stat(destFullPath);
|
|
117
|
+
return {
|
|
118
|
+
path: destinationPath,
|
|
119
|
+
size: stat2.size,
|
|
120
|
+
mimeType: "application/octet-stream"
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class S3StorageAdapter {
|
|
126
|
+
provider = "S3";
|
|
127
|
+
config;
|
|
128
|
+
constructor(options) {
|
|
129
|
+
this.config = options;
|
|
130
|
+
}
|
|
131
|
+
async upload(_options) {
|
|
132
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the upload method.");
|
|
133
|
+
}
|
|
134
|
+
async download(_filePath) {
|
|
135
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the download method.");
|
|
136
|
+
}
|
|
137
|
+
async delete(_filePath) {
|
|
138
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the delete method.");
|
|
139
|
+
}
|
|
140
|
+
async exists(_filePath) {
|
|
141
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the exists method.");
|
|
142
|
+
}
|
|
143
|
+
async getMetadata(_filePath) {
|
|
144
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the getMetadata method.");
|
|
145
|
+
}
|
|
146
|
+
async list(_options) {
|
|
147
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the list method.");
|
|
148
|
+
}
|
|
149
|
+
async createPresignedUpload(_options) {
|
|
150
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the createPresignedUpload method.");
|
|
151
|
+
}
|
|
152
|
+
async createPresignedDownload(_options) {
|
|
153
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the createPresignedDownload method.");
|
|
154
|
+
}
|
|
155
|
+
getPublicUrl(filePath) {
|
|
156
|
+
const { bucket, region, endpoint } = this.config;
|
|
157
|
+
if (endpoint) {
|
|
158
|
+
return `${endpoint}/${bucket}/${filePath}`;
|
|
159
|
+
}
|
|
160
|
+
return `https://${bucket}.s3.${region}.amazonaws.com/${filePath}`;
|
|
161
|
+
}
|
|
162
|
+
async copy(_sourcePath, _destinationPath) {
|
|
163
|
+
throw new Error("S3 adapter requires @aws-sdk/client-s3. Install it and implement the copy method.");
|
|
164
|
+
}
|
|
265
165
|
}
|
|
266
166
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
167
|
+
class InMemoryStorageAdapter {
|
|
168
|
+
provider = "LOCAL";
|
|
169
|
+
files = new Map;
|
|
170
|
+
async upload(options) {
|
|
171
|
+
const content = typeof options.content === "string" ? Buffer.from(options.content, "base64") : options.content;
|
|
172
|
+
const checksum = crypto.createHash("sha256").update(content).digest("hex");
|
|
173
|
+
const metadata = {
|
|
174
|
+
path: options.path,
|
|
175
|
+
size: content.length,
|
|
176
|
+
mimeType: options.mimeType,
|
|
177
|
+
checksum,
|
|
178
|
+
metadata: options.metadata
|
|
179
|
+
};
|
|
180
|
+
this.files.set(options.path, { content, metadata });
|
|
181
|
+
return metadata;
|
|
182
|
+
}
|
|
183
|
+
async download(filePath) {
|
|
184
|
+
const file = this.files.get(filePath);
|
|
185
|
+
if (!file) {
|
|
186
|
+
throw new Error(`File not found: ${filePath}`);
|
|
187
|
+
}
|
|
188
|
+
return file.content;
|
|
189
|
+
}
|
|
190
|
+
async delete(filePath) {
|
|
191
|
+
this.files.delete(filePath);
|
|
192
|
+
}
|
|
193
|
+
async exists(filePath) {
|
|
194
|
+
return this.files.has(filePath);
|
|
195
|
+
}
|
|
196
|
+
async getMetadata(filePath) {
|
|
197
|
+
const file = this.files.get(filePath);
|
|
198
|
+
return file?.metadata || null;
|
|
199
|
+
}
|
|
200
|
+
async list(options) {
|
|
201
|
+
const prefix = options?.prefix || "";
|
|
202
|
+
const files = [];
|
|
203
|
+
for (const [path2, file] of this.files) {
|
|
204
|
+
if (path2.startsWith(prefix)) {
|
|
205
|
+
files.push(file.metadata);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const limit = options?.limit || files.length;
|
|
209
|
+
return {
|
|
210
|
+
files: files.slice(0, limit),
|
|
211
|
+
hasMore: files.length > limit
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async createPresignedUpload(options) {
|
|
215
|
+
const expiresAt = new Date(Date.now() + (options.expiresIn || 3600) * 1000);
|
|
216
|
+
return {
|
|
217
|
+
url: `/upload?path=${encodeURIComponent(options.path)}`,
|
|
218
|
+
fields: { path: options.path },
|
|
219
|
+
expiresAt
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
async createPresignedDownload(options) {
|
|
223
|
+
const expiresAt = new Date(Date.now() + (options.expiresIn || 3600) * 1000);
|
|
224
|
+
return {
|
|
225
|
+
url: `/download/${options.path}`,
|
|
226
|
+
expiresAt
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
getPublicUrl(filePath) {
|
|
230
|
+
return `/files/${filePath}`;
|
|
231
|
+
}
|
|
232
|
+
async copy(sourcePath, destinationPath) {
|
|
233
|
+
const source = this.files.get(sourcePath);
|
|
234
|
+
if (!source) {
|
|
235
|
+
throw new Error(`Source file not found: ${sourcePath}`);
|
|
236
|
+
}
|
|
237
|
+
const metadata = {
|
|
238
|
+
...source.metadata,
|
|
239
|
+
path: destinationPath
|
|
240
|
+
};
|
|
241
|
+
this.files.set(destinationPath, { content: source.content, metadata });
|
|
242
|
+
return metadata;
|
|
243
|
+
}
|
|
244
|
+
clear() {
|
|
245
|
+
this.files.clear();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function createStorageAdapter(config) {
|
|
249
|
+
switch (config.provider) {
|
|
250
|
+
case "LOCAL":
|
|
251
|
+
if (!config.local) {
|
|
252
|
+
throw new Error("Local storage configuration required");
|
|
253
|
+
}
|
|
254
|
+
return new LocalStorageAdapter(config.local);
|
|
255
|
+
case "S3":
|
|
256
|
+
if (!config.s3) {
|
|
257
|
+
throw new Error("S3 storage configuration required");
|
|
258
|
+
}
|
|
259
|
+
return new S3StorageAdapter(config.s3);
|
|
260
|
+
default:
|
|
261
|
+
throw new Error(`Unsupported storage provider: ${config.provider}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export {
|
|
265
|
+
createStorageAdapter,
|
|
266
|
+
S3StorageAdapter,
|
|
267
|
+
LocalStorageAdapter,
|
|
268
|
+
InMemoryStorageAdapter
|
|
269
|
+
};
|