@flystorage/file-storage 1.0.1 → 1.1.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/changelog.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # `@flystorage/file-storage`
2
2
 
3
+ ## 1.1.0
4
+
5
+ ## Added
6
+
7
+ - AbortSignal Support
8
+ - Normalised over stream errors for reads
9
+ - Introduce way to detect failed reads because of missing files.
10
+
3
11
  ## 1.0.1
4
12
 
5
13
  ### Fixes
@@ -1,7 +1,8 @@
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.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;
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.FileWasNotFound = exports.UnableToReadFile = exports.UnableToWriteFile = exports.UnableToGetFileSize = exports.UnableToGetLastModified = exports.UnableToGetMimeType = exports.UnableToGetChecksum = exports.ChecksumIsNotAvailable = exports.FlystorageError = void 0;
4
4
  exports.errorToMessage = errorToMessage;
5
+ exports.isFileWasNotFound = isFileWasNotFound;
5
6
  function errorToMessage(error) {
6
7
  return error instanceof Error ? error.message : String(error);
7
8
  }
@@ -59,10 +60,26 @@ class UnableToWriteFile extends FlystorageError {
59
60
  }
60
61
  exports.UnableToWriteFile = UnableToWriteFile;
61
62
  class UnableToReadFile extends FlystorageError {
63
+ wasFileNotFound;
64
+ context;
62
65
  code = 'flystorage.unable_to_read_file';
63
- static because = (reason, { context = {}, cause = undefined }) => new UnableToReadFile(`Unable to read the file. Reason: ${reason}`, context, cause);
66
+ constructor(wasFileNotFound, message, context = {}, cause = undefined) {
67
+ super(message, context, cause);
68
+ this.wasFileNotFound = wasFileNotFound;
69
+ this.context = context;
70
+ }
71
+ static because = (reason, { context = {}, cause = undefined }) => new UnableToReadFile(false, `Unable to read the file. Reason: ${reason}`, context, cause);
72
+ static becauseFileWasNotFound = (error) => new UnableToReadFile(true, `Unable to read the file. Reason: ${error.message}`, error.context, error);
64
73
  }
65
74
  exports.UnableToReadFile = UnableToReadFile;
75
+ class FileWasNotFound extends FlystorageError {
76
+ code = 'flystorage.file_was_not_found';
77
+ static atLocation = (location, { context = {}, cause = undefined }) => new FileWasNotFound(`File was not found at location: ${location}`, context, cause);
78
+ }
79
+ exports.FileWasNotFound = FileWasNotFound;
80
+ function isFileWasNotFound(error) {
81
+ return (typeof error === 'object' && error.code === 'flystorage.file_was_not_found');
82
+ }
66
83
  class UnableToSetVisibility extends FlystorageError {
67
84
  code = 'flystorage.unable_to_set_visibility';
68
85
  static because = (reason, { context = {}, cause = undefined }) => new UnableToSetVisibility(`Unable to set visibility. Reason: ${reason}`, context, cause);
@@ -8,12 +8,14 @@ exports.normalizeExpiryToDate = normalizeExpiryToDate;
8
8
  exports.normalizeExpiryToMilliseconds = normalizeExpiryToMilliseconds;
9
9
  exports.closeReadable = closeReadable;
10
10
  exports.readableToString = readableToString;
11
+ exports.readableToBuffer = readableToBuffer;
11
12
  exports.readableToUint8Array = readableToUint8Array;
12
13
  const stream_1 = require("stream");
13
14
  const checksum_from_stream_js_1 = require("./checksum-from-stream.js");
14
15
  const path_normalizer_js_1 = require("./path-normalizer.js");
15
16
  const util_1 = require("util");
16
17
  const errors_js_1 = require("./errors.js");
18
+ const node_stream_1 = require("node:stream");
17
19
  function isFile(stat) {
18
20
  return stat.isFile;
19
21
  }
@@ -67,8 +69,28 @@ function toReadable(contents) {
67
69
  }
68
70
  const naturalSorting = new Intl.Collator(undefined, {
69
71
  numeric: true,
70
- sensitivity: 'base'
72
+ sensitivity: 'base',
71
73
  });
74
+ function instrumentAbortSignal(options) {
75
+ let abortSignal = options.abortSignal;
76
+ if (options.timeout !== undefined) {
77
+ const timeoutAbort = AbortSignal.timeout(options.timeout);
78
+ if (options.abortSignal) {
79
+ const originalAbortSignal = options.abortSignal;
80
+ abortSignal = AbortSignal.any([
81
+ originalAbortSignal,
82
+ timeoutAbort,
83
+ ]);
84
+ }
85
+ else {
86
+ abortSignal = timeoutAbort;
87
+ }
88
+ }
89
+ if (abortSignal?.aborted) {
90
+ throw abortSignal.reason;
91
+ }
92
+ return { ...options, abortSignal };
93
+ }
72
94
  class FileStorage {
73
95
  adapter;
74
96
  pathNormalizer;
@@ -79,145 +101,172 @@ class FileStorage {
79
101
  this.options = options;
80
102
  }
81
103
  async write(path, contents, options = {}) {
104
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.writes, ...options });
82
105
  try {
83
106
  const body = toReadable(contents);
84
- await this.adapter.write(this.pathNormalizer.normalizePath(path), body, { ...this.options.visibility, ...this.options.writes, ...options });
107
+ await this.adapter.write(this.pathNormalizer.normalizePath(path), body, options);
85
108
  await closeReadable(body);
86
109
  }
87
110
  catch (error) {
88
111
  throw errors_js_1.UnableToWriteFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
89
112
  }
90
113
  }
91
- async read(path) {
114
+ async read(path, options = {}) {
115
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
92
116
  try {
93
- return stream_1.Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path)));
117
+ const stream = stream_1.Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path), options));
118
+ const streamOut = new node_stream_1.PassThrough();
119
+ stream.on('error', (error) => {
120
+ stream.unpipe(streamOut);
121
+ streamOut.destroy((0, errors_js_1.isFileWasNotFound)(error)
122
+ ? errors_js_1.UnableToReadFile.becauseFileWasNotFound(error)
123
+ : error);
124
+ });
125
+ stream.pipe(streamOut);
126
+ return streamOut;
94
127
  }
95
128
  catch (error) {
129
+ if ((0, errors_js_1.isFileWasNotFound)(error)) {
130
+ throw errors_js_1.UnableToReadFile.becauseFileWasNotFound(error);
131
+ }
96
132
  throw errors_js_1.UnableToReadFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
97
133
  }
98
134
  }
99
- async readToString(path) {
100
- return await readableToString(await this.read(path));
135
+ async readToString(path, options = {}) {
136
+ return await readableToString(await this.read(path, options));
101
137
  }
102
- async readToUint8Array(path) {
103
- return await readableToUint8Array(await this.read(path));
138
+ async readToUint8Array(path, options = {}) {
139
+ return await readableToUint8Array(await this.read(path, options));
104
140
  }
105
- async readToBuffer(path) {
106
- return Buffer.from(await this.readToUint8Array(path));
141
+ async readToBuffer(path, options = {}) {
142
+ return Buffer.from(await this.readToUint8Array(path, options));
107
143
  }
108
- async deleteFile(path) {
144
+ async deleteFile(path, options = {}) {
145
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
109
146
  try {
110
- await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path));
147
+ await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path), options);
111
148
  }
112
149
  catch (error) {
113
150
  throw errors_js_1.UnableToDeleteFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
114
151
  }
115
152
  }
116
153
  async createDirectory(path, options = {}) {
154
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...options });
117
155
  try {
118
- return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), { ...this.options.visibility, ...options });
156
+ return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), options);
119
157
  }
120
158
  catch (error) {
121
159
  throw errors_js_1.UnableToCreateDirectory.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
122
160
  }
123
161
  }
124
- async deleteDirectory(path) {
162
+ async deleteDirectory(path, options = {}) {
163
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
125
164
  try {
126
- return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path));
165
+ return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path), options);
127
166
  }
128
167
  catch (error) {
129
168
  throw errors_js_1.UnableToDeleteDirectory.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
130
169
  }
131
170
  }
132
- async stat(path) {
171
+ async stat(path, options = {}) {
172
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
133
173
  try {
134
- return await this.adapter.stat(this.pathNormalizer.normalizePath(path));
174
+ return await this.adapter.stat(this.pathNormalizer.normalizePath(path), options);
135
175
  }
136
176
  catch (error) {
137
177
  throw errors_js_1.UnableToGetStat.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
138
178
  }
139
179
  }
140
180
  async moveFile(from, to, options = {}) {
181
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.moves, ...options });
141
182
  try {
142
- await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.moves, ...options });
183
+ await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), options);
143
184
  }
144
185
  catch (error) {
145
186
  throw errors_js_1.UnableToMoveFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { from, to } });
146
187
  }
147
188
  }
148
189
  async copyFile(from, to, options = {}) {
190
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.copies, ...options });
149
191
  try {
150
- await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.copies, ...options });
192
+ await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), options);
151
193
  }
152
194
  catch (error) {
153
195
  throw errors_js_1.UnableToCopyFile.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { from, to } });
154
196
  }
155
197
  }
156
- /**
157
- * @deprecated use changeVisibility instead
158
- */
159
- async setVisibility(path, visibility) {
160
- return this.changeVisibility(path, visibility);
161
- }
162
- async changeVisibility(path, visibility) {
198
+ async changeVisibility(path, visibility, options = {}) {
199
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
163
200
  try {
164
- return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility);
201
+ return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility, options);
165
202
  }
166
203
  catch (error) {
167
204
  throw errors_js_1.UnableToSetVisibility.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, visibility } });
168
205
  }
169
206
  }
170
- async visibility(path) {
207
+ async visibility(path, options = {}) {
208
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
171
209
  try {
172
- return await this.adapter.visibility(this.pathNormalizer.normalizePath(path));
210
+ return await this.adapter.visibility(this.pathNormalizer.normalizePath(path), options);
173
211
  }
174
212
  catch (error) {
175
213
  throw errors_js_1.UnableToGetVisibility.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
176
214
  }
177
215
  }
178
- async fileExists(path) {
216
+ async fileExists(path, options = {}) {
217
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
179
218
  try {
180
- return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path));
219
+ return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path), options);
181
220
  }
182
221
  catch (error) {
183
222
  throw errors_js_1.UnableToCheckFileExistence.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
184
223
  }
185
224
  }
186
- list(path, { deep = false } = {}) {
187
- return new DirectoryListing(this.adapter.list(this.pathNormalizer.normalizePath(path), { deep }), path, deep);
225
+ list(path, options = {}) {
226
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
227
+ const adapterOptions = {
228
+ ...options,
229
+ deep: options.deep ?? false,
230
+ };
231
+ return new DirectoryListing(this.adapter.list(this.pathNormalizer.normalizePath(path), adapterOptions), path, adapterOptions.deep);
188
232
  }
189
- async statFile(path) {
190
- const stat = await this.stat(path);
233
+ async statFile(path, options = {}) {
234
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
235
+ const stat = await this.stat(path, options);
191
236
  if (isFile(stat)) {
192
237
  return stat;
193
238
  }
194
239
  throw errors_js_1.UnableToGetStat.noFileStatResolved({ context: { path } });
195
240
  }
196
- async directoryExists(path) {
241
+ async directoryExists(path, options = {}) {
242
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
197
243
  try {
198
- return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path));
244
+ return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path), options);
199
245
  }
200
246
  catch (error) {
201
247
  throw errors_js_1.UnableToCheckDirectoryExistence.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
202
248
  }
203
249
  }
204
250
  async publicUrl(path, options = {}) {
251
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.publicUrls, ...options });
205
252
  try {
206
- return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), { ...this.options.publicUrls, ...options });
253
+ return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), options);
207
254
  }
208
255
  catch (error) {
209
256
  throw errors_js_1.UnableToGetPublicUrl.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
210
257
  }
211
258
  }
212
259
  async temporaryUrl(path, options) {
260
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.temporaryUrls, ...options });
213
261
  try {
214
- return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), { ...this.options.temporaryUrls, ...options });
262
+ return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), options);
215
263
  }
216
264
  catch (error) {
217
265
  throw errors_js_1.UnableToGetTemporaryUrl.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
218
266
  }
219
267
  }
220
268
  async prepareUpload(path, options) {
269
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.uploadRequest, ...options });
221
270
  if (this.options.preparedUploadStrategy !== undefined) {
222
271
  try {
223
272
  return this.options.preparedUploadStrategy.prepareUpload(path, options);
@@ -230,15 +279,16 @@ class FileStorage {
230
279
  throw new Error('The used adapter does not support prepared uploads.');
231
280
  }
232
281
  try {
233
- return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), { ...this.options.uploadRequest, ...options });
282
+ return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), options);
234
283
  }
235
284
  catch (error) {
236
285
  throw errors_js_1.UnableToPrepareUploadRequest.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
237
286
  }
238
287
  }
239
288
  async checksum(path, options = {}) {
289
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.checksums, ...options });
240
290
  try {
241
- return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), { ...this.options.checksums, ...options });
291
+ return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), options);
242
292
  }
243
293
  catch (error) {
244
294
  if (errors_js_1.ChecksumIsNotAvailable.isErrorOfType(error)) {
@@ -248,24 +298,27 @@ class FileStorage {
248
298
  }
249
299
  }
250
300
  async mimeType(path, options = {}) {
301
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.mimeTypes, ...options });
251
302
  try {
252
- return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), { ...this.options.mimeTypes, ...options });
303
+ return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), options);
253
304
  }
254
305
  catch (error) {
255
306
  throw errors_js_1.UnableToGetMimeType.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
256
307
  }
257
308
  }
258
- async lastModified(path) {
309
+ async lastModified(path, options = {}) {
310
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
259
311
  try {
260
- return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path));
312
+ return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path), options);
261
313
  }
262
314
  catch (error) {
263
315
  throw errors_js_1.UnableToGetLastModified.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
264
316
  }
265
317
  }
266
- async fileSize(path) {
318
+ async fileSize(path, options = {}) {
319
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
267
320
  try {
268
- return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path));
321
+ return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path), options);
269
322
  }
270
323
  catch (error) {
271
324
  throw errors_js_1.UnableToGetFileSize.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path } });
@@ -273,7 +326,7 @@ class FileStorage {
273
326
  }
274
327
  async calculateChecksum(path, options) {
275
328
  try {
276
- return await (0, checksum_from_stream_js_1.checksumFromStream)(await this.read(path), options);
329
+ return await (0, checksum_from_stream_js_1.checksumFromStream)(await this.read(path, options), options);
277
330
  }
278
331
  catch (error) {
279
332
  throw errors_js_1.UnableToGetChecksum.because((0, errors_js_1.errorToMessage)(error), { cause: error, context: { path, options } });
@@ -292,6 +345,7 @@ async function closeReadable(body) {
292
345
  return;
293
346
  }
294
347
  await new Promise((resolve, reject) => {
348
+ body.on('error', reject);
295
349
  body.on('close', (err) => {
296
350
  err ? reject(err) : resolve();
297
351
  });
@@ -304,6 +358,15 @@ async function readableToString(stream) {
304
358
  await closeReadable(stream);
305
359
  return contents;
306
360
  }
361
+ async function readableToBuffer(stream) {
362
+ return new Promise((resolve, reject) => {
363
+ const buffers = [];
364
+ stream.on('data', chunk => buffers.push(Buffer.from(chunk)));
365
+ stream.on('end', () => resolve(Buffer.concat(buffers)));
366
+ stream.on('finish', () => resolve(Buffer.concat(buffers)));
367
+ stream.on('error', err => reject(err));
368
+ });
369
+ }
307
370
  const encoder = new util_1.TextEncoder();
308
371
  function readableToUint8Array(stream) {
309
372
  return new Promise((resolve, reject) => {
@@ -48,8 +48,23 @@ export class UnableToWriteFile extends FlystorageError {
48
48
  static because = (reason, { context = {}, cause = undefined }) => new UnableToWriteFile(`Unable to write the file. Reason: ${reason}`, context, cause);
49
49
  }
50
50
  export class UnableToReadFile extends FlystorageError {
51
+ wasFileNotFound;
52
+ context;
51
53
  code = 'flystorage.unable_to_read_file';
52
- static because = (reason, { context = {}, cause = undefined }) => new UnableToReadFile(`Unable to read the file. Reason: ${reason}`, context, cause);
54
+ constructor(wasFileNotFound, message, context = {}, cause = undefined) {
55
+ super(message, context, cause);
56
+ this.wasFileNotFound = wasFileNotFound;
57
+ this.context = context;
58
+ }
59
+ static because = (reason, { context = {}, cause = undefined }) => new UnableToReadFile(false, `Unable to read the file. Reason: ${reason}`, context, cause);
60
+ static becauseFileWasNotFound = (error) => new UnableToReadFile(true, `Unable to read the file. Reason: ${error.message}`, error.context, error);
61
+ }
62
+ export class FileWasNotFound extends FlystorageError {
63
+ code = 'flystorage.file_was_not_found';
64
+ static atLocation = (location, { context = {}, cause = undefined }) => new FileWasNotFound(`File was not found at location: ${location}`, context, cause);
65
+ }
66
+ export function isFileWasNotFound(error) {
67
+ return (typeof error === 'object' && error.code === 'flystorage.file_was_not_found');
53
68
  }
54
69
  export class UnableToSetVisibility extends FlystorageError {
55
70
  code = 'flystorage.unable_to_set_visibility';
@@ -1,8 +1,9 @@
1
1
  import { Readable } from 'stream';
2
2
  import { checksumFromStream } from './checksum-from-stream.js';
3
3
  import { PathNormalizerV1 } from './path-normalizer.js';
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';
4
+ import { TextEncoder } from 'util';
5
+ import { ChecksumIsNotAvailable, errorToMessage, isFileWasNotFound, UnableToCheckDirectoryExistence, UnableToCheckFileExistence, UnableToCopyFile, UnableToCreateDirectory, UnableToDeleteDirectory, UnableToDeleteFile, UnableToGetChecksum, UnableToGetFileSize, UnableToGetLastModified, UnableToGetMimeType, UnableToGetPublicUrl, UnableToGetStat, UnableToGetTemporaryUrl, UnableToGetVisibility, UnableToListDirectory, UnableToMoveFile, UnableToPrepareUploadRequest, UnableToReadFile, UnableToSetVisibility, UnableToWriteFile, } from './errors.js';
6
+ import { PassThrough } from 'node:stream';
6
7
  export function isFile(stat) {
7
8
  return stat.isFile;
8
9
  }
@@ -55,8 +56,28 @@ export function toReadable(contents) {
55
56
  }
56
57
  const naturalSorting = new Intl.Collator(undefined, {
57
58
  numeric: true,
58
- sensitivity: 'base'
59
+ sensitivity: 'base',
59
60
  });
61
+ function instrumentAbortSignal(options) {
62
+ let abortSignal = options.abortSignal;
63
+ if (options.timeout !== undefined) {
64
+ const timeoutAbort = AbortSignal.timeout(options.timeout);
65
+ if (options.abortSignal) {
66
+ const originalAbortSignal = options.abortSignal;
67
+ abortSignal = AbortSignal.any([
68
+ originalAbortSignal,
69
+ timeoutAbort,
70
+ ]);
71
+ }
72
+ else {
73
+ abortSignal = timeoutAbort;
74
+ }
75
+ }
76
+ if (abortSignal?.aborted) {
77
+ throw abortSignal.reason;
78
+ }
79
+ return { ...options, abortSignal };
80
+ }
60
81
  export class FileStorage {
61
82
  adapter;
62
83
  pathNormalizer;
@@ -67,145 +88,172 @@ export class FileStorage {
67
88
  this.options = options;
68
89
  }
69
90
  async write(path, contents, options = {}) {
91
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.writes, ...options });
70
92
  try {
71
93
  const body = toReadable(contents);
72
- await this.adapter.write(this.pathNormalizer.normalizePath(path), body, { ...this.options.visibility, ...this.options.writes, ...options });
94
+ await this.adapter.write(this.pathNormalizer.normalizePath(path), body, options);
73
95
  await closeReadable(body);
74
96
  }
75
97
  catch (error) {
76
98
  throw UnableToWriteFile.because(errorToMessage(error), { cause: error, context: { path, options } });
77
99
  }
78
100
  }
79
- async read(path) {
101
+ async read(path, options = {}) {
102
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
80
103
  try {
81
- return Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path)));
104
+ const stream = Readable.from(await this.adapter.read(this.pathNormalizer.normalizePath(path), options));
105
+ const streamOut = new PassThrough();
106
+ stream.on('error', (error) => {
107
+ stream.unpipe(streamOut);
108
+ streamOut.destroy(isFileWasNotFound(error)
109
+ ? UnableToReadFile.becauseFileWasNotFound(error)
110
+ : error);
111
+ });
112
+ stream.pipe(streamOut);
113
+ return streamOut;
82
114
  }
83
115
  catch (error) {
116
+ if (isFileWasNotFound(error)) {
117
+ throw UnableToReadFile.becauseFileWasNotFound(error);
118
+ }
84
119
  throw UnableToReadFile.because(errorToMessage(error), { cause: error, context: { path } });
85
120
  }
86
121
  }
87
- async readToString(path) {
88
- return await readableToString(await this.read(path));
122
+ async readToString(path, options = {}) {
123
+ return await readableToString(await this.read(path, options));
89
124
  }
90
- async readToUint8Array(path) {
91
- return await readableToUint8Array(await this.read(path));
125
+ async readToUint8Array(path, options = {}) {
126
+ return await readableToUint8Array(await this.read(path, options));
92
127
  }
93
- async readToBuffer(path) {
94
- return Buffer.from(await this.readToUint8Array(path));
128
+ async readToBuffer(path, options = {}) {
129
+ return Buffer.from(await this.readToUint8Array(path, options));
95
130
  }
96
- async deleteFile(path) {
131
+ async deleteFile(path, options = {}) {
132
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
97
133
  try {
98
- await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path));
134
+ await this.adapter.deleteFile(this.pathNormalizer.normalizePath(path), options);
99
135
  }
100
136
  catch (error) {
101
137
  throw UnableToDeleteFile.because(errorToMessage(error), { cause: error, context: { path } });
102
138
  }
103
139
  }
104
140
  async createDirectory(path, options = {}) {
141
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...options });
105
142
  try {
106
- return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), { ...this.options.visibility, ...options });
143
+ return await this.adapter.createDirectory(this.pathNormalizer.normalizePath(path), options);
107
144
  }
108
145
  catch (error) {
109
146
  throw UnableToCreateDirectory.because(errorToMessage(error), { cause: error, context: { path, options } });
110
147
  }
111
148
  }
112
- async deleteDirectory(path) {
149
+ async deleteDirectory(path, options = {}) {
150
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
113
151
  try {
114
- return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path));
152
+ return await this.adapter.deleteDirectory(this.pathNormalizer.normalizePath(path), options);
115
153
  }
116
154
  catch (error) {
117
155
  throw UnableToDeleteDirectory.because(errorToMessage(error), { cause: error, context: { path } });
118
156
  }
119
157
  }
120
- async stat(path) {
158
+ async stat(path, options = {}) {
159
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
121
160
  try {
122
- return await this.adapter.stat(this.pathNormalizer.normalizePath(path));
161
+ return await this.adapter.stat(this.pathNormalizer.normalizePath(path), options);
123
162
  }
124
163
  catch (error) {
125
164
  throw UnableToGetStat.because(errorToMessage(error), { cause: error, context: { path } });
126
165
  }
127
166
  }
128
167
  async moveFile(from, to, options = {}) {
168
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.moves, ...options });
129
169
  try {
130
- await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.moves, ...options });
170
+ await this.adapter.moveFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), options);
131
171
  }
132
172
  catch (error) {
133
173
  throw UnableToMoveFile.because(errorToMessage(error), { cause: error, context: { from, to } });
134
174
  }
135
175
  }
136
176
  async copyFile(from, to, options = {}) {
177
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.visibility, ...this.options.copies, ...options });
137
178
  try {
138
- await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), { ...this.options.visibility, ...this.options.copies, ...options });
179
+ await this.adapter.copyFile(this.pathNormalizer.normalizePath(from), this.pathNormalizer.normalizePath(to), options);
139
180
  }
140
181
  catch (error) {
141
182
  throw UnableToCopyFile.because(errorToMessage(error), { cause: error, context: { from, to } });
142
183
  }
143
184
  }
144
- /**
145
- * @deprecated use changeVisibility instead
146
- */
147
- async setVisibility(path, visibility) {
148
- return this.changeVisibility(path, visibility);
149
- }
150
- async changeVisibility(path, visibility) {
185
+ async changeVisibility(path, visibility, options = {}) {
186
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
151
187
  try {
152
- return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility);
188
+ return await this.adapter.changeVisibility(this.pathNormalizer.normalizePath(path), visibility, options);
153
189
  }
154
190
  catch (error) {
155
191
  throw UnableToSetVisibility.because(errorToMessage(error), { cause: error, context: { path, visibility } });
156
192
  }
157
193
  }
158
- async visibility(path) {
194
+ async visibility(path, options = {}) {
195
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
159
196
  try {
160
- return await this.adapter.visibility(this.pathNormalizer.normalizePath(path));
197
+ return await this.adapter.visibility(this.pathNormalizer.normalizePath(path), options);
161
198
  }
162
199
  catch (error) {
163
200
  throw UnableToGetVisibility.because(errorToMessage(error), { cause: error, context: { path } });
164
201
  }
165
202
  }
166
- async fileExists(path) {
203
+ async fileExists(path, options = {}) {
204
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
167
205
  try {
168
- return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path));
206
+ return await this.adapter.fileExists(this.pathNormalizer.normalizePath(path), options);
169
207
  }
170
208
  catch (error) {
171
209
  throw UnableToCheckFileExistence.because(errorToMessage(error), { cause: error, context: { path } });
172
210
  }
173
211
  }
174
- list(path, { deep = false } = {}) {
175
- return new DirectoryListing(this.adapter.list(this.pathNormalizer.normalizePath(path), { deep }), path, deep);
212
+ list(path, options = {}) {
213
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
214
+ const adapterOptions = {
215
+ ...options,
216
+ deep: options.deep ?? false,
217
+ };
218
+ return new DirectoryListing(this.adapter.list(this.pathNormalizer.normalizePath(path), adapterOptions), path, adapterOptions.deep);
176
219
  }
177
- async statFile(path) {
178
- const stat = await this.stat(path);
220
+ async statFile(path, options = {}) {
221
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
222
+ const stat = await this.stat(path, options);
179
223
  if (isFile(stat)) {
180
224
  return stat;
181
225
  }
182
226
  throw UnableToGetStat.noFileStatResolved({ context: { path } });
183
227
  }
184
- async directoryExists(path) {
228
+ async directoryExists(path, options = {}) {
229
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
185
230
  try {
186
- return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path));
231
+ return await this.adapter.directoryExists(this.pathNormalizer.normalizePath(path), options);
187
232
  }
188
233
  catch (error) {
189
234
  throw UnableToCheckDirectoryExistence.because(errorToMessage(error), { cause: error, context: { path } });
190
235
  }
191
236
  }
192
237
  async publicUrl(path, options = {}) {
238
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.publicUrls, ...options });
193
239
  try {
194
- return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), { ...this.options.publicUrls, ...options });
240
+ return await this.adapter.publicUrl(this.pathNormalizer.normalizePath(path), options);
195
241
  }
196
242
  catch (error) {
197
243
  throw UnableToGetPublicUrl.because(errorToMessage(error), { cause: error, context: { path, options } });
198
244
  }
199
245
  }
200
246
  async temporaryUrl(path, options) {
247
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.temporaryUrls, ...options });
201
248
  try {
202
- return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), { ...this.options.temporaryUrls, ...options });
249
+ return await this.adapter.temporaryUrl(this.pathNormalizer.normalizePath(path), options);
203
250
  }
204
251
  catch (error) {
205
252
  throw UnableToGetTemporaryUrl.because(errorToMessage(error), { cause: error, context: { path, options } });
206
253
  }
207
254
  }
208
255
  async prepareUpload(path, options) {
256
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.uploadRequest, ...options });
209
257
  if (this.options.preparedUploadStrategy !== undefined) {
210
258
  try {
211
259
  return this.options.preparedUploadStrategy.prepareUpload(path, options);
@@ -218,15 +266,16 @@ export class FileStorage {
218
266
  throw new Error('The used adapter does not support prepared uploads.');
219
267
  }
220
268
  try {
221
- return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), { ...this.options.uploadRequest, ...options });
269
+ return await this.adapter.prepareUpload(this.pathNormalizer.normalizePath(path), options);
222
270
  }
223
271
  catch (error) {
224
272
  throw UnableToPrepareUploadRequest.because(errorToMessage(error), { cause: error, context: { path, options } });
225
273
  }
226
274
  }
227
275
  async checksum(path, options = {}) {
276
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.checksums, ...options });
228
277
  try {
229
- return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), { ...this.options.checksums, ...options });
278
+ return await this.adapter.checksum(this.pathNormalizer.normalizePath(path), options);
230
279
  }
231
280
  catch (error) {
232
281
  if (ChecksumIsNotAvailable.isErrorOfType(error)) {
@@ -236,24 +285,27 @@ export class FileStorage {
236
285
  }
237
286
  }
238
287
  async mimeType(path, options = {}) {
288
+ options = instrumentAbortSignal({ ...this.options.timeout, ...this.options.mimeTypes, ...options });
239
289
  try {
240
- return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), { ...this.options.mimeTypes, ...options });
290
+ return await this.adapter.mimeType(this.pathNormalizer.normalizePath(path), options);
241
291
  }
242
292
  catch (error) {
243
293
  throw UnableToGetMimeType.because(errorToMessage(error), { cause: error, context: { path, options } });
244
294
  }
245
295
  }
246
- async lastModified(path) {
296
+ async lastModified(path, options = {}) {
297
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
247
298
  try {
248
- return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path));
299
+ return await this.adapter.lastModified(this.pathNormalizer.normalizePath(path), options);
249
300
  }
250
301
  catch (error) {
251
302
  throw UnableToGetLastModified.because(errorToMessage(error), { cause: error, context: { path } });
252
303
  }
253
304
  }
254
- async fileSize(path) {
305
+ async fileSize(path, options = {}) {
306
+ options = instrumentAbortSignal({ ...this.options.timeout, ...options });
255
307
  try {
256
- return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path));
308
+ return await this.adapter.fileSize(this.pathNormalizer.normalizePath(path), options);
257
309
  }
258
310
  catch (error) {
259
311
  throw UnableToGetFileSize.because(errorToMessage(error), { cause: error, context: { path } });
@@ -261,7 +313,7 @@ export class FileStorage {
261
313
  }
262
314
  async calculateChecksum(path, options) {
263
315
  try {
264
- return await checksumFromStream(await this.read(path), options);
316
+ return await checksumFromStream(await this.read(path, options), options);
265
317
  }
266
318
  catch (error) {
267
319
  throw UnableToGetChecksum.because(errorToMessage(error), { cause: error, context: { path, options } });
@@ -279,6 +331,7 @@ export async function closeReadable(body) {
279
331
  return;
280
332
  }
281
333
  await new Promise((resolve, reject) => {
334
+ body.on('error', reject);
282
335
  body.on('close', (err) => {
283
336
  err ? reject(err) : resolve();
284
337
  });
@@ -291,6 +344,15 @@ export async function readableToString(stream) {
291
344
  await closeReadable(stream);
292
345
  return contents;
293
346
  }
347
+ export async function readableToBuffer(stream) {
348
+ return new Promise((resolve, reject) => {
349
+ const buffers = [];
350
+ stream.on('data', chunk => buffers.push(Buffer.from(chunk)));
351
+ stream.on('end', () => resolve(Buffer.concat(buffers)));
352
+ stream.on('finish', () => resolve(Buffer.concat(buffers)));
353
+ stream.on('error', err => reject(err));
354
+ });
355
+ }
294
356
  const encoder = new TextEncoder();
295
357
  export function readableToUint8Array(stream) {
296
358
  return new Promise((resolve, reject) => {
@@ -61,12 +61,24 @@ export declare class UnableToWriteFile extends FlystorageError {
61
61
  }) => UnableToWriteFile;
62
62
  }
63
63
  export declare class UnableToReadFile extends FlystorageError {
64
+ readonly wasFileNotFound: boolean;
65
+ readonly context: ErrorContext;
64
66
  readonly code = "flystorage.unable_to_read_file";
67
+ constructor(wasFileNotFound: boolean, message: string, context?: ErrorContext, cause?: unknown);
65
68
  static because: (reason: string, { context, cause }: {
66
69
  context?: ErrorContext;
67
70
  cause?: unknown;
68
71
  }) => UnableToReadFile;
72
+ static becauseFileWasNotFound: (error: FileWasNotFound) => UnableToReadFile;
73
+ }
74
+ export declare class FileWasNotFound extends FlystorageError {
75
+ readonly code = "flystorage.file_was_not_found";
76
+ static atLocation: (location: string, { context, cause }: {
77
+ context?: ErrorContext;
78
+ cause?: unknown;
79
+ }) => FileWasNotFound;
69
80
  }
81
+ export declare function isFileWasNotFound(error: unknown): error is FileWasNotFound;
70
82
  export declare class UnableToSetVisibility extends FlystorageError {
71
83
  readonly code = "flystorage.unable_to_set_visibility";
72
84
  static because: (reason: string, { context, cause }: {
@@ -21,29 +21,30 @@ export type DirectoryInfo = Readonly<{
21
21
  export declare function isFile(stat: StatEntry): stat is FileInfo;
22
22
  export declare function isDirectory(stat: StatEntry): stat is DirectoryInfo;
23
23
  export type StatEntry = FileInfo | DirectoryInfo;
24
+ export type AdapterListOptions = ListOptions & {
25
+ deep: boolean;
26
+ };
24
27
  export interface StorageAdapter {
25
28
  write(path: string, contents: Readable, options: WriteOptions): Promise<void>;
26
- read(path: string): Promise<FileContents>;
27
- deleteFile(path: string): Promise<void>;
29
+ read(path: string, options: MiscellaneousOptions): Promise<FileContents>;
30
+ deleteFile(path: string, options: MiscellaneousOptions): Promise<void>;
28
31
  createDirectory(path: string, options: CreateDirectoryOptions): Promise<void>;
29
32
  copyFile(from: string, to: string, options: CopyFileOptions): Promise<void>;
30
33
  moveFile(from: string, to: string, options: MoveFileOptions): Promise<void>;
31
- stat(path: string): Promise<StatEntry>;
32
- list(path: string, options: {
33
- deep: boolean;
34
- }): AsyncGenerator<StatEntry>;
35
- changeVisibility(path: string, visibility: string): Promise<void>;
36
- visibility(path: string): Promise<string>;
37
- deleteDirectory(path: string): Promise<void>;
38
- fileExists(path: string): Promise<boolean>;
39
- directoryExists(path: string): Promise<boolean>;
34
+ stat(path: string, options: MiscellaneousOptions): Promise<StatEntry>;
35
+ list(path: string, options: AdapterListOptions): AsyncGenerator<StatEntry>;
36
+ changeVisibility(path: string, visibility: string, options: MiscellaneousOptions): Promise<void>;
37
+ visibility(path: string, options: MiscellaneousOptions): Promise<string>;
38
+ deleteDirectory(path: string, options: MiscellaneousOptions): Promise<void>;
39
+ fileExists(path: string, options: MiscellaneousOptions): Promise<boolean>;
40
+ directoryExists(path: string, options: MiscellaneousOptions): Promise<boolean>;
40
41
  publicUrl(path: string, options: PublicUrlOptions): Promise<string>;
41
42
  temporaryUrl(path: string, options: TemporaryUrlOptions): Promise<string>;
42
43
  prepareUpload?(path: string, options: UploadRequestOptions): Promise<UploadRequest>;
43
44
  checksum(path: string, options: ChecksumOptions): Promise<string>;
44
45
  mimeType(path: string, options: MimeTypeOptions): Promise<string>;
45
- lastModified(path: string): Promise<number>;
46
- fileSize(path: string): Promise<number>;
46
+ lastModified(path: string, options: MiscellaneousOptions): Promise<number>;
47
+ fileSize(path: string, options: MiscellaneousOptions): Promise<number>;
47
48
  }
48
49
  export declare class DirectoryListing implements AsyncIterable<StatEntry> {
49
50
  private readonly listing;
@@ -55,8 +56,12 @@ export declare class DirectoryListing implements AsyncIterable<StatEntry> {
55
56
  [Symbol.asyncIterator](): AsyncGenerator<StatEntry, void, unknown>;
56
57
  }
57
58
  export type FileContents = Iterable<any> | AsyncIterable<any> | NodeJS.ReadableStream | Readable | string;
58
- export type MiscellaneousOptions = {
59
+ export type TimeoutOptions = {
60
+ timout?: number;
61
+ };
62
+ export type MiscellaneousOptions = TimeoutOptions & {
59
63
  [option: string]: any;
64
+ abortSignal?: AbortSignal;
60
65
  };
61
66
  export type MimeTypeOptions = MiscellaneousOptions & {
62
67
  disallowFallback?: boolean;
@@ -84,7 +89,7 @@ export type CopyFileOptions = MiscellaneousOptions & VisibilityOptions & {
84
89
  export type MoveFileOptions = MiscellaneousOptions & VisibilityOptions & {
85
90
  retainVisibility?: boolean;
86
91
  };
87
- export type ListOptions = {
92
+ export type ListOptions = MiscellaneousOptions & {
88
93
  deep?: boolean;
89
94
  };
90
95
  export type TemporaryUrlOptions = MiscellaneousOptions & {
@@ -108,6 +113,7 @@ export type ConfigurationOptions = {
108
113
  checksums?: ChecksumOptions;
109
114
  mimeTypes?: MimeTypeOptions;
110
115
  preparedUploadStrategy?: PreparedUploadStrategy;
116
+ timeout?: TimeoutOptions;
111
117
  };
112
118
  export declare function toReadable(contents: FileContents): Readable;
113
119
  export declare class FileStorage {
@@ -116,33 +122,29 @@ export declare class FileStorage {
116
122
  private readonly options;
117
123
  constructor(adapter: StorageAdapter, pathNormalizer?: PathNormalizer, options?: ConfigurationOptions);
118
124
  write(path: string, contents: FileContents, options?: WriteOptions): Promise<void>;
119
- read(path: string): Promise<Readable>;
120
- readToString(path: string): Promise<string>;
121
- readToUint8Array(path: string): Promise<Uint8Array>;
122
- readToBuffer(path: string): Promise<Buffer>;
123
- deleteFile(path: string): Promise<void>;
125
+ read(path: string, options?: MiscellaneousOptions): Promise<Readable>;
126
+ readToString(path: string, options?: MiscellaneousOptions): Promise<string>;
127
+ readToUint8Array(path: string, options?: MiscellaneousOptions): Promise<Uint8Array>;
128
+ readToBuffer(path: string, options?: MiscellaneousOptions): Promise<Buffer>;
129
+ deleteFile(path: string, options?: MiscellaneousOptions): Promise<void>;
124
130
  createDirectory(path: string, options?: CreateDirectoryOptions): Promise<void>;
125
- deleteDirectory(path: string): Promise<void>;
126
- stat(path: string): Promise<StatEntry>;
131
+ deleteDirectory(path: string, options?: MiscellaneousOptions): Promise<void>;
132
+ stat(path: string, options?: MiscellaneousOptions): Promise<StatEntry>;
127
133
  moveFile(from: string, to: string, options?: MoveFileOptions): Promise<void>;
128
134
  copyFile(from: string, to: string, options?: CopyFileOptions): Promise<void>;
129
- /**
130
- * @deprecated use changeVisibility instead
131
- */
132
- setVisibility(path: string, visibility: string): Promise<void>;
133
- changeVisibility(path: string, visibility: string): Promise<void>;
134
- visibility(path: string): Promise<string>;
135
- fileExists(path: string): Promise<boolean>;
136
- list(path: string, { deep }?: ListOptions): DirectoryListing;
137
- statFile(path: string): Promise<FileInfo>;
138
- directoryExists(path: string): Promise<boolean>;
135
+ changeVisibility(path: string, visibility: string, options?: MiscellaneousOptions): Promise<void>;
136
+ visibility(path: string, options?: MiscellaneousOptions): Promise<string>;
137
+ fileExists(path: string, options?: MiscellaneousOptions): Promise<boolean>;
138
+ list(path: string, options?: ListOptions): DirectoryListing;
139
+ statFile(path: string, options?: MiscellaneousOptions): Promise<FileInfo>;
140
+ directoryExists(path: string, options?: MiscellaneousOptions): Promise<boolean>;
139
141
  publicUrl(path: string, options?: PublicUrlOptions): Promise<string>;
140
142
  temporaryUrl(path: string, options: TemporaryUrlOptions): Promise<string>;
141
143
  prepareUpload(path: string, options: UploadRequestOptions): Promise<UploadRequest>;
142
144
  checksum(path: string, options?: ChecksumOptions): Promise<string>;
143
145
  mimeType(path: string, options?: MimeTypeOptions): Promise<string>;
144
- lastModified(path: string): Promise<number>;
145
- fileSize(path: string): Promise<number>;
146
+ lastModified(path: string, options?: MiscellaneousOptions): Promise<number>;
147
+ fileSize(path: string, options?: MiscellaneousOptions): Promise<number>;
146
148
  private calculateChecksum;
147
149
  }
148
150
  export type TimestampMs = number;
@@ -151,6 +153,7 @@ export declare function normalizeExpiryToDate(expiresAt: ExpiresAt): Date;
151
153
  export declare function normalizeExpiryToMilliseconds(expiresAt: ExpiresAt): number;
152
154
  export declare function closeReadable(body: Readable): Promise<void>;
153
155
  export declare function readableToString(stream: Readable): Promise<string>;
156
+ export declare function readableToBuffer(stream: Readable): Promise<Buffer>;
154
157
  export declare function readableToUint8Array(stream: Readable): Promise<Uint8Array>;
155
158
  export type UploadRequestHeaders = Record<string, string | ReadonlyArray<string>>;
156
159
  export type UploadRequest = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flystorage/file-storage",
3
3
  "type": "module",
4
- "version": "1.0.1",
4
+ "version": "1.1.0",
5
5
  "description": "File-storage abstraction: multiple filesystems, one API.",
6
6
  "main": "./dist/cjs/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -30,6 +30,7 @@
30
30
  "url": "git+https://github.com/duna-oss/flystorage.git",
31
31
  "directory": "packages/file-storage"
32
32
  },
33
+ "homepage": "https://flystorage.dev/",
33
34
  "keywords": [
34
35
  "fs",
35
36
  "file",