@flystorage/file-storage 0.1.5 → 1.0.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/cjs/checksum-from-stream.js +14 -6
- package/dist/cjs/errors.js +9 -1
- package/dist/cjs/file-storage.js +50 -26
- package/dist/esm/checksum-from-stream.js +14 -6
- package/dist/esm/errors.js +7 -0
- package/dist/esm/file-storage.js +48 -25
- package/dist/types/errors.d.ts +8 -0
- package/dist/types/file-storage.d.ts +22 -0
- package/package.json +1 -1
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checksumFromStream = checksumFromStream;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const encoder = new util_1.TextEncoder();
|
|
5
7
|
async function checksumFromStream(stream, options) {
|
|
6
|
-
return new Promise(
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
7
9
|
const hash = (0, crypto_1.createHash)(options.algo ?? 'md5');
|
|
8
|
-
stream.on('error', reject);
|
|
9
|
-
stream.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
stream.on('error', err => reject(err));
|
|
11
|
+
stream.on('data', (chunk) => {
|
|
12
|
+
const type = typeof chunk;
|
|
13
|
+
if (type === 'string') {
|
|
14
|
+
chunk = encoder.encode(chunk);
|
|
15
|
+
}
|
|
16
|
+
else if (type === 'number') {
|
|
17
|
+
chunk = new Uint8Array([chunk]);
|
|
18
|
+
}
|
|
19
|
+
hash.update(chunk);
|
|
13
20
|
});
|
|
21
|
+
stream.on('end', () => resolve(hash.digest(options.encoding ?? 'hex')));
|
|
14
22
|
});
|
|
15
23
|
}
|
package/dist/cjs/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UnableToListDirectory = exports.UnableToCheckDirectoryExistence = exports.UnableToCheckFileExistence = exports.UnableToDeleteFile = exports.UnableToDeleteDirectory = exports.UnableToCreateDirectory = exports.UnableToGetStat = exports.UnableToMoveFile = exports.UnableToCopyFile = exports.UnableToGetTemporaryUrl = exports.UnableToGetPublicUrl = exports.UnableToGetVisibility = exports.UnableToSetVisibility = exports.UnableToReadFile = exports.UnableToWriteFile = exports.UnableToGetFileSize = exports.UnableToGetLastModified = exports.UnableToGetMimeType = exports.UnableToGetChecksum = exports.ChecksumIsNotAvailable = exports.FlystorageError = void 0;
|
|
3
|
+
exports.UnableToListDirectory = exports.UnableToCheckDirectoryExistence = exports.UnableToCheckFileExistence = exports.UnableToDeleteFile = exports.UnableToDeleteDirectory = exports.UnableToCreateDirectory = exports.UnableToGetStat = exports.UnableToMoveFile = exports.UnableToCopyFile = exports.UnableToPrepareUploadRequest = exports.UnableToGetTemporaryUrl = exports.UnableToGetPublicUrl = exports.UnableToGetVisibility = exports.UnableToSetVisibility = exports.UnableToReadFile = exports.UnableToWriteFile = exports.UnableToGetFileSize = exports.UnableToGetLastModified = exports.UnableToGetMimeType = exports.UnableToGetChecksum = exports.ChecksumIsNotAvailable = exports.FlystorageError = void 0;
|
|
4
4
|
exports.errorToMessage = errorToMessage;
|
|
5
5
|
function errorToMessage(error) {
|
|
6
6
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -28,6 +28,9 @@ class ChecksumIsNotAvailable extends FlystorageError {
|
|
|
28
28
|
this.algo = algo;
|
|
29
29
|
}
|
|
30
30
|
static checksumNotSupported = (algo, { context = {}, cause = undefined } = {}) => new ChecksumIsNotAvailable(`Checksum algo "${algo}" is not supported`, algo, { ...context, algo }, cause);
|
|
31
|
+
static isErrorOfType(error) {
|
|
32
|
+
return (typeof error === 'object' && error.code === 'flystorage.checksum_not_supported');
|
|
33
|
+
}
|
|
31
34
|
}
|
|
32
35
|
exports.ChecksumIsNotAvailable = ChecksumIsNotAvailable;
|
|
33
36
|
class UnableToGetChecksum extends FlystorageError {
|
|
@@ -80,6 +83,11 @@ class UnableToGetTemporaryUrl extends FlystorageError {
|
|
|
80
83
|
static because = (reason, { context = {}, cause = undefined }) => new UnableToGetTemporaryUrl(`Unable to get temporary URL. Reason: ${reason}`, context, cause);
|
|
81
84
|
}
|
|
82
85
|
exports.UnableToGetTemporaryUrl = UnableToGetTemporaryUrl;
|
|
86
|
+
class UnableToPrepareUploadRequest extends FlystorageError {
|
|
87
|
+
code = 'flystorage.unable_to_prepare_upload_request';
|
|
88
|
+
static because = (reason, { context = {}, cause = undefined }) => new UnableToGetTemporaryUrl(`Unable to prepare upload request. Reason: ${reason}`, context, cause);
|
|
89
|
+
}
|
|
90
|
+
exports.UnableToPrepareUploadRequest = UnableToPrepareUploadRequest;
|
|
83
91
|
class UnableToCopyFile extends FlystorageError {
|
|
84
92
|
code = 'flystorage.unable_to_copy_file';
|
|
85
93
|
static because = (reason, { context = {}, cause = undefined }) => new UnableToCopyFile(`Unable to copy file. Reason: ${reason}`, context, cause);
|
package/dist/cjs/file-storage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FileStorage = exports.DirectoryListing = void 0;
|
|
3
|
+
exports.PreparedUploadsAreNotSupported = exports.FileStorage = exports.DirectoryListing = void 0;
|
|
4
4
|
exports.isFile = isFile;
|
|
5
5
|
exports.isDirectory = isDirectory;
|
|
6
6
|
exports.toReadable = toReadable;
|
|
@@ -11,10 +11,9 @@ exports.readableToString = readableToString;
|
|
|
11
11
|
exports.readableToUint8Array = readableToUint8Array;
|
|
12
12
|
const stream_1 = require("stream");
|
|
13
13
|
const checksum_from_stream_js_1 = require("./checksum-from-stream.js");
|
|
14
|
-
const errors = require("./errors.js");
|
|
15
|
-
const errors_js_1 = require("./errors.js");
|
|
16
14
|
const path_normalizer_js_1 = require("./path-normalizer.js");
|
|
17
15
|
const util_1 = require("util");
|
|
16
|
+
const errors_js_1 = require("./errors.js");
|
|
18
17
|
function isFile(stat) {
|
|
19
18
|
return stat.isFile;
|
|
20
19
|
}
|
|
@@ -55,7 +54,7 @@ class DirectoryListing {
|
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
catch (error) {
|
|
58
|
-
throw
|
|
57
|
+
throw errors_js_1.UnableToListDirectory.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path: this.path, deep: this.deep } });
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -86,7 +85,7 @@ class FileStorage {
|
|
|
86
85
|
await closeReadable(body);
|
|
87
86
|
}
|
|
88
87
|
catch (error) {
|
|
89
|
-
throw
|
|
88
|
+
throw errors_js_1.UnableToWriteFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
async read(path) {
|
|
@@ -94,7 +93,7 @@ class FileStorage {
|
|
|
94
93
|
return stream_1.Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path)));
|
|
95
94
|
}
|
|
96
95
|
catch (error) {
|
|
97
|
-
throw
|
|
96
|
+
throw errors_js_1.UnableToReadFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
99
|
async readToString(path) {
|
|
@@ -111,7 +110,7 @@ class FileStorage {
|
|
|
111
110
|
await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path));
|
|
112
111
|
}
|
|
113
112
|
catch (error) {
|
|
114
|
-
throw
|
|
113
|
+
throw errors_js_1.UnableToDeleteFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
async createDirectory(path, options = {}) {
|
|
@@ -119,7 +118,7 @@ class FileStorage {
|
|
|
119
118
|
return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), { ...this.options.visibility, ...options });
|
|
120
119
|
}
|
|
121
120
|
catch (error) {
|
|
122
|
-
throw
|
|
121
|
+
throw errors_js_1.UnableToCreateDirectory.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
123
122
|
}
|
|
124
123
|
}
|
|
125
124
|
async deleteDirectory(path) {
|
|
@@ -127,7 +126,7 @@ class FileStorage {
|
|
|
127
126
|
return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path));
|
|
128
127
|
}
|
|
129
128
|
catch (error) {
|
|
130
|
-
throw
|
|
129
|
+
throw errors_js_1.UnableToDeleteDirectory.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
async stat(path) {
|
|
@@ -135,7 +134,7 @@ class FileStorage {
|
|
|
135
134
|
return await this.adapter.stat(this.pathNormalizer.normalizePath(path));
|
|
136
135
|
}
|
|
137
136
|
catch (error) {
|
|
138
|
-
throw
|
|
137
|
+
throw errors_js_1.UnableToGetStat.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
139
138
|
}
|
|
140
139
|
}
|
|
141
140
|
async moveFile(from, to, options = {}) {
|
|
@@ -143,7 +142,7 @@ class FileStorage {
|
|
|
143
142
|
await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.moves, ...options });
|
|
144
143
|
}
|
|
145
144
|
catch (error) {
|
|
146
|
-
throw
|
|
145
|
+
throw errors_js_1.UnableToMoveFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { from, to } });
|
|
147
146
|
}
|
|
148
147
|
}
|
|
149
148
|
async copyFile(from, to, options = {}) {
|
|
@@ -151,7 +150,7 @@ class FileStorage {
|
|
|
151
150
|
await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.copies, ...options });
|
|
152
151
|
}
|
|
153
152
|
catch (error) {
|
|
154
|
-
throw
|
|
153
|
+
throw errors_js_1.UnableToCopyFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { from, to } });
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
156
|
/**
|
|
@@ -165,7 +164,7 @@ class FileStorage {
|
|
|
165
164
|
return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility);
|
|
166
165
|
}
|
|
167
166
|
catch (error) {
|
|
168
|
-
throw
|
|
167
|
+
throw errors_js_1.UnableToSetVisibility.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, visibility } });
|
|
169
168
|
}
|
|
170
169
|
}
|
|
171
170
|
async visibility(path) {
|
|
@@ -173,7 +172,7 @@ class FileStorage {
|
|
|
173
172
|
return await this.adapter.visibility(this.pathNormalizer.normalizePath(path));
|
|
174
173
|
}
|
|
175
174
|
catch (error) {
|
|
176
|
-
throw
|
|
175
|
+
throw errors_js_1.UnableToGetVisibility.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
177
176
|
}
|
|
178
177
|
}
|
|
179
178
|
async fileExists(path) {
|
|
@@ -181,7 +180,7 @@ class FileStorage {
|
|
|
181
180
|
return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path));
|
|
182
181
|
}
|
|
183
182
|
catch (error) {
|
|
184
|
-
throw
|
|
183
|
+
throw errors_js_1.UnableToCheckFileExistence.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
list(path, { deep = false } = {}) {
|
|
@@ -192,14 +191,14 @@ class FileStorage {
|
|
|
192
191
|
if (isFile(stat)) {
|
|
193
192
|
return stat;
|
|
194
193
|
}
|
|
195
|
-
throw
|
|
194
|
+
throw errors_js_1.UnableToGetStat.noFileStatResolved({ context: { path } });
|
|
196
195
|
}
|
|
197
196
|
async directoryExists(path) {
|
|
198
197
|
try {
|
|
199
198
|
return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path));
|
|
200
199
|
}
|
|
201
200
|
catch (error) {
|
|
202
|
-
throw
|
|
201
|
+
throw errors_js_1.UnableToCheckDirectoryExistence.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
203
202
|
}
|
|
204
203
|
}
|
|
205
204
|
async publicUrl(path, options = {}) {
|
|
@@ -207,7 +206,7 @@ class FileStorage {
|
|
|
207
206
|
return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), { ...this.options.publicUrls, ...options });
|
|
208
207
|
}
|
|
209
208
|
catch (error) {
|
|
210
|
-
throw
|
|
209
|
+
throw errors_js_1.UnableToGetPublicUrl.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
211
210
|
}
|
|
212
211
|
}
|
|
213
212
|
async temporaryUrl(path, options) {
|
|
@@ -215,7 +214,26 @@ class FileStorage {
|
|
|
215
214
|
return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), { ...this.options.temporaryUrls, ...options });
|
|
216
215
|
}
|
|
217
216
|
catch (error) {
|
|
218
|
-
throw
|
|
217
|
+
throw errors_js_1.UnableToGetTemporaryUrl.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async prepareUpload(path, options) {
|
|
221
|
+
if (this.options.preparedUploadStrategy !== undefined) {
|
|
222
|
+
try {
|
|
223
|
+
return this.options.preparedUploadStrategy.prepareUpload(path, options);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
throw errors_js_1.UnableToPrepareUploadRequest.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (typeof this.adapter.prepareUpload !== 'function') {
|
|
230
|
+
throw new Error('The used adapter does not support prepared uploads.');
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), { ...this.options.uploadRequest, ...options });
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
throw errors_js_1.UnableToPrepareUploadRequest.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
219
237
|
}
|
|
220
238
|
}
|
|
221
239
|
async checksum(path, options = {}) {
|
|
@@ -223,10 +241,10 @@ class FileStorage {
|
|
|
223
241
|
return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), { ...this.options.checksums, ...options });
|
|
224
242
|
}
|
|
225
243
|
catch (error) {
|
|
226
|
-
if (
|
|
244
|
+
if (errors_js_1.ChecksumIsNotAvailable.isErrorOfType(error)) {
|
|
227
245
|
return this.calculateChecksum(path, options);
|
|
228
246
|
}
|
|
229
|
-
throw
|
|
247
|
+
throw errors_js_1.UnableToGetChecksum.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
230
248
|
}
|
|
231
249
|
}
|
|
232
250
|
async mimeType(path, options = {}) {
|
|
@@ -234,7 +252,7 @@ class FileStorage {
|
|
|
234
252
|
return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), { ...this.options.mimeTypes, ...options });
|
|
235
253
|
}
|
|
236
254
|
catch (error) {
|
|
237
|
-
throw
|
|
255
|
+
throw errors_js_1.UnableToGetMimeType.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
238
256
|
}
|
|
239
257
|
}
|
|
240
258
|
async lastModified(path) {
|
|
@@ -242,7 +260,7 @@ class FileStorage {
|
|
|
242
260
|
return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path));
|
|
243
261
|
}
|
|
244
262
|
catch (error) {
|
|
245
|
-
throw
|
|
263
|
+
throw errors_js_1.UnableToGetLastModified.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
246
264
|
}
|
|
247
265
|
}
|
|
248
266
|
async fileSize(path) {
|
|
@@ -250,7 +268,7 @@ class FileStorage {
|
|
|
250
268
|
return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path));
|
|
251
269
|
}
|
|
252
270
|
catch (error) {
|
|
253
|
-
throw
|
|
271
|
+
throw errors_js_1.UnableToGetFileSize.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
|
|
254
272
|
}
|
|
255
273
|
}
|
|
256
274
|
async calculateChecksum(path, options) {
|
|
@@ -258,7 +276,7 @@ class FileStorage {
|
|
|
258
276
|
return await (0, checksum_from_stream_js_1.checksumFromStream)(await this.read(path), options);
|
|
259
277
|
}
|
|
260
278
|
catch (error) {
|
|
261
|
-
throw
|
|
279
|
+
throw errors_js_1.UnableToGetChecksum.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
|
|
262
280
|
}
|
|
263
281
|
}
|
|
264
282
|
}
|
|
@@ -270,7 +288,7 @@ function normalizeExpiryToMilliseconds(expiresAt) {
|
|
|
270
288
|
return expiresAt instanceof Date ? expiresAt.getTime() : expiresAt;
|
|
271
289
|
}
|
|
272
290
|
async function closeReadable(body) {
|
|
273
|
-
if (body.closed) {
|
|
291
|
+
if (body.closed || body.destroyed) {
|
|
274
292
|
return;
|
|
275
293
|
}
|
|
276
294
|
await new Promise((resolve, reject) => {
|
|
@@ -314,3 +332,9 @@ function concatUint8Arrays(input) {
|
|
|
314
332
|
});
|
|
315
333
|
return output;
|
|
316
334
|
}
|
|
335
|
+
class PreparedUploadsAreNotSupported {
|
|
336
|
+
prepareUpload() {
|
|
337
|
+
throw new Error('The used adapter does not support prepared uploads.');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
exports.PreparedUploadsAreNotSupported = PreparedUploadsAreNotSupported;
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
|
+
import { TextEncoder } from 'util';
|
|
3
|
+
const encoder = new TextEncoder();
|
|
2
4
|
export async function checksumFromStream(stream, options) {
|
|
3
|
-
return new Promise(
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
4
6
|
const hash = createHash(options.algo ?? 'md5');
|
|
5
|
-
stream.on('error', reject);
|
|
6
|
-
stream.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
stream.on('error', err => reject(err));
|
|
8
|
+
stream.on('data', (chunk) => {
|
|
9
|
+
const type = typeof chunk;
|
|
10
|
+
if (type === 'string') {
|
|
11
|
+
chunk = encoder.encode(chunk);
|
|
12
|
+
}
|
|
13
|
+
else if (type === 'number') {
|
|
14
|
+
chunk = new Uint8Array([chunk]);
|
|
15
|
+
}
|
|
16
|
+
hash.update(chunk);
|
|
10
17
|
});
|
|
18
|
+
stream.on('end', () => resolve(hash.digest(options.encoding ?? 'hex')));
|
|
11
19
|
});
|
|
12
20
|
}
|
package/dist/esm/errors.js
CHANGED
|
@@ -23,6 +23,9 @@ export class ChecksumIsNotAvailable extends FlystorageError {
|
|
|
23
23
|
this.algo = algo;
|
|
24
24
|
}
|
|
25
25
|
static checksumNotSupported = (algo, { context = {}, cause = undefined } = {}) => new ChecksumIsNotAvailable(`Checksum algo "${algo}" is not supported`, algo, { ...context, algo }, cause);
|
|
26
|
+
static isErrorOfType(error) {
|
|
27
|
+
return (typeof error === 'object' && error.code === 'flystorage.checksum_not_supported');
|
|
28
|
+
}
|
|
26
29
|
}
|
|
27
30
|
export class UnableToGetChecksum extends FlystorageError {
|
|
28
31
|
code = 'flystorage.unable_to_get_checksum';
|
|
@@ -64,6 +67,10 @@ export class UnableToGetTemporaryUrl extends FlystorageError {
|
|
|
64
67
|
code = 'flystorage.unable_to_get_temporary_url';
|
|
65
68
|
static because = (reason, { context = {}, cause = undefined }) => new UnableToGetTemporaryUrl(`Unable to get temporary URL. Reason: ${reason}`, context, cause);
|
|
66
69
|
}
|
|
70
|
+
export class UnableToPrepareUploadRequest extends FlystorageError {
|
|
71
|
+
code = 'flystorage.unable_to_prepare_upload_request';
|
|
72
|
+
static because = (reason, { context = {}, cause = undefined }) => new UnableToGetTemporaryUrl(`Unable to prepare upload request. Reason: ${reason}`, context, cause);
|
|
73
|
+
}
|
|
67
74
|
export class UnableToCopyFile extends FlystorageError {
|
|
68
75
|
code = 'flystorage.unable_to_copy_file';
|
|
69
76
|
static because = (reason, { context = {}, cause = undefined }) => new UnableToCopyFile(`Unable to copy file. Reason: ${reason}`, context, cause);
|
package/dist/esm/file-storage.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Readable } from 'stream';
|
|
2
2
|
import { checksumFromStream } from './checksum-from-stream.js';
|
|
3
|
-
import * as errors from './errors.js';
|
|
4
|
-
import { ChecksumIsNotAvailable } from './errors.js';
|
|
5
3
|
import { PathNormalizerV1 } from './path-normalizer.js';
|
|
6
4
|
import { TextEncoder } from "util";
|
|
5
|
+
import { ChecksumIsNotAvailable, errorToMessage, UnableToCheckDirectoryExistence, UnableToCheckFileExistence, UnableToCopyFile, UnableToCreateDirectory, UnableToDeleteDirectory, UnableToDeleteFile, UnableToGetChecksum, UnableToGetFileSize, UnableToGetLastModified, UnableToGetMimeType, UnableToGetPublicUrl, UnableToGetStat, UnableToGetTemporaryUrl, UnableToGetVisibility, UnableToListDirectory, UnableToMoveFile, UnableToPrepareUploadRequest, UnableToReadFile, UnableToSetVisibility, UnableToWriteFile, } from './errors.js';
|
|
7
6
|
export function isFile(stat) {
|
|
8
7
|
return stat.isFile;
|
|
9
8
|
}
|
|
@@ -44,7 +43,7 @@ export class DirectoryListing {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
catch (error) {
|
|
47
|
-
throw
|
|
46
|
+
throw UnableToListDirectory.because(errorToMessage(error), { cause: error, context: { path: this.path, deep: this.deep } });
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
}
|
|
@@ -74,7 +73,7 @@ export class FileStorage {
|
|
|
74
73
|
await closeReadable(body);
|
|
75
74
|
}
|
|
76
75
|
catch (error) {
|
|
77
|
-
throw
|
|
76
|
+
throw UnableToWriteFile.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
async read(path) {
|
|
@@ -82,7 +81,7 @@ export class FileStorage {
|
|
|
82
81
|
return Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path)));
|
|
83
82
|
}
|
|
84
83
|
catch (error) {
|
|
85
|
-
throw
|
|
84
|
+
throw UnableToReadFile.because(errorToMessage(error), { cause: error, context: { path } });
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
async readToString(path) {
|
|
@@ -99,7 +98,7 @@ export class FileStorage {
|
|
|
99
98
|
await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path));
|
|
100
99
|
}
|
|
101
100
|
catch (error) {
|
|
102
|
-
throw
|
|
101
|
+
throw UnableToDeleteFile.because(errorToMessage(error), { cause: error, context: { path } });
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
async createDirectory(path, options = {}) {
|
|
@@ -107,7 +106,7 @@ export class FileStorage {
|
|
|
107
106
|
return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), { ...this.options.visibility, ...options });
|
|
108
107
|
}
|
|
109
108
|
catch (error) {
|
|
110
|
-
throw
|
|
109
|
+
throw UnableToCreateDirectory.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
112
|
async deleteDirectory(path) {
|
|
@@ -115,7 +114,7 @@ export class FileStorage {
|
|
|
115
114
|
return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path));
|
|
116
115
|
}
|
|
117
116
|
catch (error) {
|
|
118
|
-
throw
|
|
117
|
+
throw UnableToDeleteDirectory.because(errorToMessage(error), { cause: error, context: { path } });
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
120
|
async stat(path) {
|
|
@@ -123,7 +122,7 @@ export class FileStorage {
|
|
|
123
122
|
return await this.adapter.stat(this.pathNormalizer.normalizePath(path));
|
|
124
123
|
}
|
|
125
124
|
catch (error) {
|
|
126
|
-
throw
|
|
125
|
+
throw UnableToGetStat.because(errorToMessage(error), { cause: error, context: { path } });
|
|
127
126
|
}
|
|
128
127
|
}
|
|
129
128
|
async moveFile(from, to, options = {}) {
|
|
@@ -131,7 +130,7 @@ export class FileStorage {
|
|
|
131
130
|
await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.moves, ...options });
|
|
132
131
|
}
|
|
133
132
|
catch (error) {
|
|
134
|
-
throw
|
|
133
|
+
throw UnableToMoveFile.because(errorToMessage(error), { cause: error, context: { from, to } });
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
async copyFile(from, to, options = {}) {
|
|
@@ -139,7 +138,7 @@ export class FileStorage {
|
|
|
139
138
|
await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.copies, ...options });
|
|
140
139
|
}
|
|
141
140
|
catch (error) {
|
|
142
|
-
throw
|
|
141
|
+
throw UnableToCopyFile.because(errorToMessage(error), { cause: error, context: { from, to } });
|
|
143
142
|
}
|
|
144
143
|
}
|
|
145
144
|
/**
|
|
@@ -153,7 +152,7 @@ export class FileStorage {
|
|
|
153
152
|
return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility);
|
|
154
153
|
}
|
|
155
154
|
catch (error) {
|
|
156
|
-
throw
|
|
155
|
+
throw UnableToSetVisibility.because(errorToMessage(error), { cause: error, context: { path, visibility } });
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
async visibility(path) {
|
|
@@ -161,7 +160,7 @@ export class FileStorage {
|
|
|
161
160
|
return await this.adapter.visibility(this.pathNormalizer.normalizePath(path));
|
|
162
161
|
}
|
|
163
162
|
catch (error) {
|
|
164
|
-
throw
|
|
163
|
+
throw UnableToGetVisibility.because(errorToMessage(error), { cause: error, context: { path } });
|
|
165
164
|
}
|
|
166
165
|
}
|
|
167
166
|
async fileExists(path) {
|
|
@@ -169,7 +168,7 @@ export class FileStorage {
|
|
|
169
168
|
return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path));
|
|
170
169
|
}
|
|
171
170
|
catch (error) {
|
|
172
|
-
throw
|
|
171
|
+
throw UnableToCheckFileExistence.because(errorToMessage(error), { cause: error, context: { path } });
|
|
173
172
|
}
|
|
174
173
|
}
|
|
175
174
|
list(path, { deep = false } = {}) {
|
|
@@ -180,14 +179,14 @@ export class FileStorage {
|
|
|
180
179
|
if (isFile(stat)) {
|
|
181
180
|
return stat;
|
|
182
181
|
}
|
|
183
|
-
throw
|
|
182
|
+
throw UnableToGetStat.noFileStatResolved({ context: { path } });
|
|
184
183
|
}
|
|
185
184
|
async directoryExists(path) {
|
|
186
185
|
try {
|
|
187
186
|
return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path));
|
|
188
187
|
}
|
|
189
188
|
catch (error) {
|
|
190
|
-
throw
|
|
189
|
+
throw UnableToCheckDirectoryExistence.because(errorToMessage(error), { cause: error, context: { path } });
|
|
191
190
|
}
|
|
192
191
|
}
|
|
193
192
|
async publicUrl(path, options = {}) {
|
|
@@ -195,7 +194,7 @@ export class FileStorage {
|
|
|
195
194
|
return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), { ...this.options.publicUrls, ...options });
|
|
196
195
|
}
|
|
197
196
|
catch (error) {
|
|
198
|
-
throw
|
|
197
|
+
throw UnableToGetPublicUrl.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
199
198
|
}
|
|
200
199
|
}
|
|
201
200
|
async temporaryUrl(path, options) {
|
|
@@ -203,7 +202,26 @@ export class FileStorage {
|
|
|
203
202
|
return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), { ...this.options.temporaryUrls, ...options });
|
|
204
203
|
}
|
|
205
204
|
catch (error) {
|
|
206
|
-
throw
|
|
205
|
+
throw UnableToGetTemporaryUrl.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async prepareUpload(path, options) {
|
|
209
|
+
if (this.options.preparedUploadStrategy !== undefined) {
|
|
210
|
+
try {
|
|
211
|
+
return this.options.preparedUploadStrategy.prepareUpload(path, options);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
throw UnableToPrepareUploadRequest.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (typeof this.adapter.prepareUpload !== 'function') {
|
|
218
|
+
throw new Error('The used adapter does not support prepared uploads.');
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), { ...this.options.uploadRequest, ...options });
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
throw UnableToPrepareUploadRequest.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
207
225
|
}
|
|
208
226
|
}
|
|
209
227
|
async checksum(path, options = {}) {
|
|
@@ -211,10 +229,10 @@ export class FileStorage {
|
|
|
211
229
|
return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), { ...this.options.checksums, ...options });
|
|
212
230
|
}
|
|
213
231
|
catch (error) {
|
|
214
|
-
if (error
|
|
232
|
+
if (ChecksumIsNotAvailable.isErrorOfType(error)) {
|
|
215
233
|
return this.calculateChecksum(path, options);
|
|
216
234
|
}
|
|
217
|
-
throw
|
|
235
|
+
throw UnableToGetChecksum.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
218
236
|
}
|
|
219
237
|
}
|
|
220
238
|
async mimeType(path, options = {}) {
|
|
@@ -222,7 +240,7 @@ export class FileStorage {
|
|
|
222
240
|
return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), { ...this.options.mimeTypes, ...options });
|
|
223
241
|
}
|
|
224
242
|
catch (error) {
|
|
225
|
-
throw
|
|
243
|
+
throw UnableToGetMimeType.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
226
244
|
}
|
|
227
245
|
}
|
|
228
246
|
async lastModified(path) {
|
|
@@ -230,7 +248,7 @@ export class FileStorage {
|
|
|
230
248
|
return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path));
|
|
231
249
|
}
|
|
232
250
|
catch (error) {
|
|
233
|
-
throw
|
|
251
|
+
throw UnableToGetLastModified.because(errorToMessage(error), { cause: error, context: { path } });
|
|
234
252
|
}
|
|
235
253
|
}
|
|
236
254
|
async fileSize(path) {
|
|
@@ -238,7 +256,7 @@ export class FileStorage {
|
|
|
238
256
|
return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path));
|
|
239
257
|
}
|
|
240
258
|
catch (error) {
|
|
241
|
-
throw
|
|
259
|
+
throw UnableToGetFileSize.because(errorToMessage(error), { cause: error, context: { path } });
|
|
242
260
|
}
|
|
243
261
|
}
|
|
244
262
|
async calculateChecksum(path, options) {
|
|
@@ -246,7 +264,7 @@ export class FileStorage {
|
|
|
246
264
|
return await checksumFromStream(await this.read(path), options);
|
|
247
265
|
}
|
|
248
266
|
catch (error) {
|
|
249
|
-
throw
|
|
267
|
+
throw UnableToGetChecksum.because(errorToMessage(error), { cause: error, context: { path, options } });
|
|
250
268
|
}
|
|
251
269
|
}
|
|
252
270
|
}
|
|
@@ -257,7 +275,7 @@ export function normalizeExpiryToMilliseconds(expiresAt) {
|
|
|
257
275
|
return expiresAt instanceof Date ? expiresAt.getTime() : expiresAt;
|
|
258
276
|
}
|
|
259
277
|
export async function closeReadable(body) {
|
|
260
|
-
if (body.closed) {
|
|
278
|
+
if (body.closed || body.destroyed) {
|
|
261
279
|
return;
|
|
262
280
|
}
|
|
263
281
|
await new Promise((resolve, reject) => {
|
|
@@ -301,3 +319,8 @@ function concatUint8Arrays(input) {
|
|
|
301
319
|
});
|
|
302
320
|
return output;
|
|
303
321
|
}
|
|
322
|
+
export class PreparedUploadsAreNotSupported {
|
|
323
|
+
prepareUpload() {
|
|
324
|
+
throw new Error('The used adapter does not support prepared uploads.');
|
|
325
|
+
}
|
|
326
|
+
}
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare class ChecksumIsNotAvailable extends FlystorageError {
|
|
|
23
23
|
context?: ErrorContext;
|
|
24
24
|
cause?: unknown;
|
|
25
25
|
}) => ChecksumIsNotAvailable;
|
|
26
|
+
static isErrorOfType(error: unknown): error is ChecksumIsNotAvailable;
|
|
26
27
|
}
|
|
27
28
|
export declare class UnableToGetChecksum extends FlystorageError {
|
|
28
29
|
readonly code = "flystorage.unable_to_get_checksum";
|
|
@@ -94,6 +95,13 @@ export declare class UnableToGetTemporaryUrl extends FlystorageError {
|
|
|
94
95
|
cause?: unknown;
|
|
95
96
|
}) => UnableToGetTemporaryUrl;
|
|
96
97
|
}
|
|
98
|
+
export declare class UnableToPrepareUploadRequest extends FlystorageError {
|
|
99
|
+
readonly code = "flystorage.unable_to_prepare_upload_request";
|
|
100
|
+
static because: (reason: string, { context, cause }: {
|
|
101
|
+
context?: ErrorContext;
|
|
102
|
+
cause?: unknown;
|
|
103
|
+
}) => UnableToGetTemporaryUrl;
|
|
104
|
+
}
|
|
97
105
|
export declare class UnableToCopyFile extends FlystorageError {
|
|
98
106
|
readonly code = "flystorage.unable_to_copy_file";
|
|
99
107
|
static because: (reason: string, { context, cause }: {
|
|
@@ -39,6 +39,7 @@ export interface StorageAdapter {
|
|
|
39
39
|
directoryExists(path: string): Promise<boolean>;
|
|
40
40
|
publicUrl(path: string, options: PublicUrlOptions): Promise<string>;
|
|
41
41
|
temporaryUrl(path: string, options: TemporaryUrlOptions): Promise<string>;
|
|
42
|
+
prepareUpload?(path: string, options: UploadRequestOptions): Promise<UploadRequest>;
|
|
42
43
|
checksum(path: string, options: ChecksumOptions): Promise<string>;
|
|
43
44
|
mimeType(path: string, options: MimeTypeOptions): Promise<string>;
|
|
44
45
|
lastModified(path: string): Promise<number>;
|
|
@@ -72,6 +73,11 @@ export type WriteOptions = VisibilityOptions & MiscellaneousOptions & {
|
|
|
72
73
|
};
|
|
73
74
|
export type CreateDirectoryOptions = MiscellaneousOptions & Pick<VisibilityOptions, 'directoryVisibility'> & {};
|
|
74
75
|
export type PublicUrlOptions = MiscellaneousOptions & {};
|
|
76
|
+
export type UploadRequestOptions = MiscellaneousOptions & {
|
|
77
|
+
expiresAt: ExpiresAt;
|
|
78
|
+
contentType?: string;
|
|
79
|
+
headers?: UploadRequestHeaders;
|
|
80
|
+
};
|
|
75
81
|
export type CopyFileOptions = MiscellaneousOptions & VisibilityOptions & {
|
|
76
82
|
retainVisibility?: boolean;
|
|
77
83
|
};
|
|
@@ -98,8 +104,10 @@ export type ConfigurationOptions = {
|
|
|
98
104
|
copies?: CopyFileOptions;
|
|
99
105
|
publicUrls?: PublicUrlOptions;
|
|
100
106
|
temporaryUrls?: TemporaryUrlOptions;
|
|
107
|
+
uploadRequest?: UploadRequestOptions;
|
|
101
108
|
checksums?: ChecksumOptions;
|
|
102
109
|
mimeTypes?: MimeTypeOptions;
|
|
110
|
+
preparedUploadStrategy?: PreparedUploadStrategy;
|
|
103
111
|
};
|
|
104
112
|
export declare function toReadable(contents: FileContents): Readable;
|
|
105
113
|
export declare class FileStorage {
|
|
@@ -130,6 +138,7 @@ export declare class FileStorage {
|
|
|
130
138
|
directoryExists(path: string): Promise<boolean>;
|
|
131
139
|
publicUrl(path: string, options?: PublicUrlOptions): Promise<string>;
|
|
132
140
|
temporaryUrl(path: string, options: TemporaryUrlOptions): Promise<string>;
|
|
141
|
+
prepareUpload(path: string, options: UploadRequestOptions): Promise<UploadRequest>;
|
|
133
142
|
checksum(path: string, options?: ChecksumOptions): Promise<string>;
|
|
134
143
|
mimeType(path: string, options?: MimeTypeOptions): Promise<string>;
|
|
135
144
|
lastModified(path: string): Promise<number>;
|
|
@@ -143,3 +152,16 @@ export declare function normalizeExpiryToMilliseconds(expiresAt: ExpiresAt): num
|
|
|
143
152
|
export declare function closeReadable(body: Readable): Promise<void>;
|
|
144
153
|
export declare function readableToString(stream: Readable): Promise<string>;
|
|
145
154
|
export declare function readableToUint8Array(stream: Readable): Promise<Uint8Array>;
|
|
155
|
+
export type UploadRequestHeaders = Record<string, string | ReadonlyArray<string>>;
|
|
156
|
+
export type UploadRequest = {
|
|
157
|
+
url: string;
|
|
158
|
+
provider?: string;
|
|
159
|
+
method: 'PUT' | 'POST';
|
|
160
|
+
headers: UploadRequestHeaders;
|
|
161
|
+
};
|
|
162
|
+
export interface PreparedUploadStrategy {
|
|
163
|
+
prepareUpload(path: string, options: UploadRequestOptions): Promise<UploadRequest>;
|
|
164
|
+
}
|
|
165
|
+
export declare class PreparedUploadsAreNotSupported implements PreparedUploadStrategy {
|
|
166
|
+
prepareUpload(): Promise<UploadRequest>;
|
|
167
|
+
}
|
package/package.json
CHANGED