@quatrain/storage-s3 1.2.1 → 1.2.3

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.
@@ -1,13 +1,48 @@
1
1
  import { AbstractStorageAdapter, FileType, FileResponseLinkType, StorageParameters, DownloadFileMetaType } from '@quatrain/storage';
2
- import { Readable, Stream } from 'stream';
2
+ import { Readable, Stream } from 'node:stream';
3
3
  import { S3Client } from '@aws-sdk/client-s3';
4
+ /**
5
+ * Storage adapter implementation for AWS S3 compatible services.
6
+ * Implements direct stream uploads, presigned URLs, and multipart handling.
7
+ */
4
8
  export declare class S3StorageAdapter extends AbstractStorageAdapter {
5
9
  protected _client: S3Client;
6
10
  constructor(params: StorageParameters);
11
+ /**
12
+ * Validates the connection to the configured S3 endpoint by attempting to list buckets.
13
+ *
14
+ * @returns True if the connection succeeds and buckets are accessible.
15
+ */
7
16
  test(): Promise<boolean>;
17
+ /**
18
+ * Exposes the underlying AWS S3 Client instance.
19
+ *
20
+ * @returns The `S3Client` instance.
21
+ */
8
22
  getDriver(): S3Client;
23
+ /**
24
+ * Helper utility converting a Node.js Stream into a raw Buffer.
25
+ * Required for S3 payloads when streaming sizes are indeterminate.
26
+ *
27
+ * @param stream - The input stream.
28
+ * @returns A promise resolving to the concatenated Buffer.
29
+ */
9
30
  streamToBuffer(stream: Stream): Promise<Buffer>;
31
+ /**
32
+ * Uploads a file stream directly into an S3 Bucket.
33
+ *
34
+ * @param file - Target file metadata.
35
+ * @param stream - The content readable stream.
36
+ * @returns A promise resolving to the uploaded FileType metadata.
37
+ * @throws {Error} If the upload fails.
38
+ */
10
39
  create(file: FileType, stream: Readable): Promise<FileType>;
40
+ /**
41
+ * Copies an existing object within S3 to a new destination key or bucket.
42
+ *
43
+ * @param file - Source file.
44
+ * @param destFile - Destination file.
45
+ */
11
46
  copy(file: FileType, destFile: FileType): Promise<void>;
12
47
  /**
13
48
  * Move file to given destination
@@ -17,14 +52,63 @@ export declare class S3StorageAdapter extends AbstractStorageAdapter {
17
52
  * @returns
18
53
  */
19
54
  move(file: FileType, destFile: FileType): Promise<FileType>;
20
- getUrl(file: FileType, expiresIn?: number, action?: any, extra?: any): Promise<{
55
+ /**
56
+ * Generates a temporary, presigned GET URL for public or secure access.
57
+ *
58
+ * @param file - Target file.
59
+ * @param expiresIn - URL expiration time in seconds.
60
+ * @param action - The requested action ('read', etc.).
61
+ * @param extra - Extra parameters such as 'cacheControl'.
62
+ * @returns A promise resolving to the generated URL and expiration payload.
63
+ */
64
+ _getUrl(file: FileType, expiresIn?: number, action?: any, extra?: any): Promise<{
21
65
  url: string;
22
66
  expiresIn: number;
23
67
  }>;
68
+ /**
69
+ * Deletes an object from the S3 Bucket.
70
+ *
71
+ * @param file - The file to remove.
72
+ * @returns A promise resolving to true on success.
73
+ */
24
74
  delete(file: FileType): Promise<boolean>;
75
+ /**
76
+ * Downloads an S3 object and returns it as a Node.js Readable stream.
77
+ *
78
+ * @param file - The target file.
79
+ * @returns A promise resolving to the ReadStream.
80
+ */
25
81
  getReadable(file: FileType): Promise<Readable>;
82
+ /**
83
+ * Issues a HEAD request to fetch S3 object metadata like size and content-type
84
+ * without downloading the actual payload.
85
+ *
86
+ * @param file - The file footprint.
87
+ * @returns A promise resolving to the augmented metadata.
88
+ */
26
89
  getMetaData(file: FileType): Promise<FileType>;
90
+ /**
91
+ * Directly pipes an S3 object to an external HTTP response or stream.
92
+ *
93
+ * @param file - Target file.
94
+ * @param res - The response or writable stream.
95
+ * @returns The piped stream instance.
96
+ */
27
97
  stream(file: FileType, res: any): Promise<any>;
98
+ /**
99
+ * Downloads an S3 object and writes it directly to the local filesystem.
100
+ *
101
+ * @param file - The remote file.
102
+ * @param meta - Local download path instructions.
103
+ * @returns A promise resolving to the local file path.
104
+ */
28
105
  download(file: FileType, meta: DownloadFileMetaType): Promise<string>;
106
+ /**
107
+ * Generates a presigned PUT URL allowing clients to upload directly to S3, bypassing the backend.
108
+ *
109
+ * @param file - The requested upload file destination.
110
+ * @param expiresIn - Token expiration in seconds.
111
+ * @returns A promise resolving to the upload URL instructions.
112
+ */
29
113
  getUploadUrl(file: FileType, expiresIn?: number): Promise<FileResponseLinkType>;
30
114
  }
@@ -11,10 +11,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.S3StorageAdapter = void 0;
13
13
  const storage_1 = require("@quatrain/storage");
14
- const stream_1 = require("stream");
14
+ const node_stream_1 = require("node:stream");
15
15
  const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
16
- const fs_1 = require("fs");
16
+ const node_fs_1 = require("node:fs");
17
17
  const client_s3_1 = require("@aws-sdk/client-s3");
18
+ /**
19
+ * Storage adapter implementation for AWS S3 compatible services.
20
+ * Implements direct stream uploads, presigned URLs, and multipart handling.
21
+ */
18
22
  class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
19
23
  constructor(params) {
20
24
  super(params);
@@ -30,6 +34,11 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
30
34
  this._client = new client_s3_1.S3Client(config);
31
35
  storage_1.Storage.info(`AWS Storage Adapter initialized in ${this._params.config.endpoint || this._params.config.region}`);
32
36
  }
37
+ /**
38
+ * Validates the connection to the configured S3 endpoint by attempting to list buckets.
39
+ *
40
+ * @returns True if the connection succeeds and buckets are accessible.
41
+ */
33
42
  test() {
34
43
  return __awaiter(this, void 0, void 0, function* () {
35
44
  try {
@@ -44,9 +53,21 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
44
53
  }
45
54
  });
46
55
  }
56
+ /**
57
+ * Exposes the underlying AWS S3 Client instance.
58
+ *
59
+ * @returns The `S3Client` instance.
60
+ */
47
61
  getDriver() {
48
62
  return this._client;
49
63
  }
64
+ /**
65
+ * Helper utility converting a Node.js Stream into a raw Buffer.
66
+ * Required for S3 payloads when streaming sizes are indeterminate.
67
+ *
68
+ * @param stream - The input stream.
69
+ * @returns A promise resolving to the concatenated Buffer.
70
+ */
50
71
  streamToBuffer(stream) {
51
72
  return __awaiter(this, void 0, void 0, function* () {
52
73
  return new Promise((resolve, reject) => {
@@ -57,6 +78,14 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
57
78
  });
58
79
  });
59
80
  }
81
+ /**
82
+ * Uploads a file stream directly into an S3 Bucket.
83
+ *
84
+ * @param file - Target file metadata.
85
+ * @param stream - The content readable stream.
86
+ * @returns A promise resolving to the uploaded FileType metadata.
87
+ * @throws {Error} If the upload fails.
88
+ */
60
89
  create(file, stream) {
61
90
  return __awaiter(this, void 0, void 0, function* () {
62
91
  try {
@@ -77,6 +106,12 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
77
106
  }
78
107
  });
79
108
  }
109
+ /**
110
+ * Copies an existing object within S3 to a new destination key or bucket.
111
+ *
112
+ * @param file - Source file.
113
+ * @param destFile - Destination file.
114
+ */
80
115
  copy(file, destFile) {
81
116
  return __awaiter(this, void 0, void 0, function* () {
82
117
  storage_1.Storage.debug(`Copying file ${file.bucket}/${file.ref} to ${file.bucket}/${destFile.ref}`);
@@ -114,7 +149,16 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
114
149
  return destFile;
115
150
  });
116
151
  }
117
- getUrl(file_1) {
152
+ /**
153
+ * Generates a temporary, presigned GET URL for public or secure access.
154
+ *
155
+ * @param file - Target file.
156
+ * @param expiresIn - URL expiration time in seconds.
157
+ * @param action - The requested action ('read', etc.).
158
+ * @param extra - Extra parameters such as 'cacheControl'.
159
+ * @returns A promise resolving to the generated URL and expiration payload.
160
+ */
161
+ _getUrl(file_1) {
118
162
  return __awaiter(this, arguments, void 0, function* (file, expiresIn = 3600, action = 'read', extra = {}) {
119
163
  const commandArgs = {
120
164
  Bucket: file.bucket,
@@ -130,6 +174,12 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
130
174
  return { url, expiresIn };
131
175
  });
132
176
  }
177
+ /**
178
+ * Deletes an object from the S3 Bucket.
179
+ *
180
+ * @param file - The file to remove.
181
+ * @returns A promise resolving to true on success.
182
+ */
133
183
  delete(file) {
134
184
  return __awaiter(this, void 0, void 0, function* () {
135
185
  var _a;
@@ -143,6 +193,12 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
143
193
  return true;
144
194
  });
145
195
  }
196
+ /**
197
+ * Downloads an S3 object and returns it as a Node.js Readable stream.
198
+ *
199
+ * @param file - The target file.
200
+ * @returns A promise resolving to the ReadStream.
201
+ */
146
202
  getReadable(file) {
147
203
  return __awaiter(this, void 0, void 0, function* () {
148
204
  var _a, _b;
@@ -154,12 +210,19 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
154
210
  const item = yield ((_a = this._client) === null || _a === void 0 ? void 0 : _a.send(command));
155
211
  const ByteArray = yield ((_b = item === null || item === void 0 ? void 0 : item.Body) === null || _b === void 0 ? void 0 : _b.transformToByteArray());
156
212
  const buffer = Buffer.from(ByteArray, 'base64');
157
- const readable = new stream_1.Readable();
213
+ const readable = new node_stream_1.Readable();
158
214
  readable.push(buffer);
159
215
  readable.push(null);
160
216
  return readable;
161
217
  });
162
218
  }
219
+ /**
220
+ * Issues a HEAD request to fetch S3 object metadata like size and content-type
221
+ * without downloading the actual payload.
222
+ *
223
+ * @param file - The file footprint.
224
+ * @returns A promise resolving to the augmented metadata.
225
+ */
163
226
  getMetaData(file) {
164
227
  return __awaiter(this, void 0, void 0, function* () {
165
228
  const command = new client_s3_1.HeadObjectCommand({
@@ -171,6 +234,13 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
171
234
  return meta;
172
235
  });
173
236
  }
237
+ /**
238
+ * Directly pipes an S3 object to an external HTTP response or stream.
239
+ *
240
+ * @param file - Target file.
241
+ * @param res - The response or writable stream.
242
+ * @returns The piped stream instance.
243
+ */
174
244
  stream(file, res) {
175
245
  return __awaiter(this, void 0, void 0, function* () {
176
246
  var _a;
@@ -181,19 +251,33 @@ class S3StorageAdapter extends storage_1.AbstractStorageAdapter {
181
251
  const item = yield this._client.send(command);
182
252
  const ByteArray = yield ((_a = item.Body) === null || _a === void 0 ? void 0 : _a.transformToByteArray());
183
253
  const buffer = Buffer.from(ByteArray, 'base64');
184
- const readable = new stream_1.Readable();
254
+ const readable = new node_stream_1.Readable();
185
255
  readable.push(buffer);
186
256
  readable.push(null);
187
257
  return readable.pipe(res);
188
258
  });
189
259
  }
260
+ /**
261
+ * Downloads an S3 object and writes it directly to the local filesystem.
262
+ *
263
+ * @param file - The remote file.
264
+ * @param meta - Local download path instructions.
265
+ * @returns A promise resolving to the local file path.
266
+ */
190
267
  download(file, meta) {
191
268
  return __awaiter(this, void 0, void 0, function* () {
192
269
  const stream = yield this.getReadable(file);
193
- yield new Promise((res) => stream.pipe((0, fs_1.createWriteStream)(meta.path)).on('close', () => res(true)));
270
+ yield new Promise((res) => stream.pipe((0, node_fs_1.createWriteStream)(meta.path)).on('close', () => res(true)));
194
271
  return meta.path;
195
272
  });
196
273
  }
274
+ /**
275
+ * Generates a presigned PUT URL allowing clients to upload directly to S3, bypassing the backend.
276
+ *
277
+ * @param file - The requested upload file destination.
278
+ * @param expiresIn - Token expiration in seconds.
279
+ * @returns A promise resolving to the upload URL instructions.
280
+ */
197
281
  getUploadUrl(file_1) {
198
282
  return __awaiter(this, arguments, void 0, function* (file, expiresIn = 3600) {
199
283
  const command = new client_s3_1.PutObjectCommand({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/storage-s3",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Storage adapter for S3 compatible services",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@aws-sdk/client-s3": "^3.337.0",
35
35
  "@aws-sdk/s3-request-presigner": "^3.342.0",
36
- "@quatrain/storage": "^1.2.1",
36
+ "@quatrain/storage": "^1.2.4",
37
37
  "fs-extra": "^11.2.0"
38
38
  },
39
39
  "scripts": {
@@ -6,9 +6,9 @@ import {
6
6
  StorageParameters,
7
7
  DownloadFileMetaType,
8
8
  } from '@quatrain/storage'
9
- import { Readable, Stream } from 'stream'
9
+ import { Readable, Stream } from 'node:stream'
10
10
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
11
- import { createWriteStream } from 'fs'
11
+ import { createWriteStream } from 'node:fs'
12
12
  import {
13
13
  S3Client,
14
14
  PutObjectCommand,
@@ -19,6 +19,10 @@ import {
19
19
  ListBucketsCommand,
20
20
  } from '@aws-sdk/client-s3'
21
21
 
22
+ /**
23
+ * Storage adapter implementation for AWS S3 compatible services.
24
+ * Implements direct stream uploads, presigned URLs, and multipart handling.
25
+ */
22
26
  export class S3StorageAdapter extends AbstractStorageAdapter {
23
27
  protected _client: S3Client
24
28
 
@@ -44,6 +48,11 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
44
48
  )
45
49
  }
46
50
 
51
+ /**
52
+ * Validates the connection to the configured S3 endpoint by attempting to list buckets.
53
+ *
54
+ * @returns True if the connection succeeds and buckets are accessible.
55
+ */
47
56
  async test(): Promise<boolean> {
48
57
  try {
49
58
  const command = new ListBucketsCommand()
@@ -56,10 +65,22 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
56
65
  }
57
66
  }
58
67
 
68
+ /**
69
+ * Exposes the underlying AWS S3 Client instance.
70
+ *
71
+ * @returns The `S3Client` instance.
72
+ */
59
73
  getDriver() {
60
74
  return this._client
61
75
  }
62
76
 
77
+ /**
78
+ * Helper utility converting a Node.js Stream into a raw Buffer.
79
+ * Required for S3 payloads when streaming sizes are indeterminate.
80
+ *
81
+ * @param stream - The input stream.
82
+ * @returns A promise resolving to the concatenated Buffer.
83
+ */
63
84
  async streamToBuffer(stream: Stream): Promise<Buffer> {
64
85
  return new Promise<Buffer>((resolve, reject) => {
65
86
  const _buf: any[] = []
@@ -70,6 +91,14 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
70
91
  })
71
92
  }
72
93
 
94
+ /**
95
+ * Uploads a file stream directly into an S3 Bucket.
96
+ *
97
+ * @param file - Target file metadata.
98
+ * @param stream - The content readable stream.
99
+ * @returns A promise resolving to the uploaded FileType metadata.
100
+ * @throws {Error} If the upload fails.
101
+ */
73
102
  async create(file: FileType, stream: Readable): Promise<FileType> {
74
103
  try {
75
104
  const input = {
@@ -98,6 +127,12 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
98
127
  }
99
128
  }
100
129
 
130
+ /**
131
+ * Copies an existing object within S3 to a new destination key or bucket.
132
+ *
133
+ * @param file - Source file.
134
+ * @param destFile - Destination file.
135
+ */
101
136
  async copy(file: FileType, destFile: FileType) {
102
137
  Storage.debug(
103
138
  `Copying file ${file.bucket}/${file.ref} to ${file.bucket}/${destFile.ref}`
@@ -141,7 +176,16 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
141
176
  return destFile
142
177
  }
143
178
 
144
- async getUrl(file: FileType, expiresIn = 3600, action: any = 'read', extra: any = {}) {
179
+ /**
180
+ * Generates a temporary, presigned GET URL for public or secure access.
181
+ *
182
+ * @param file - Target file.
183
+ * @param expiresIn - URL expiration time in seconds.
184
+ * @param action - The requested action ('read', etc.).
185
+ * @param extra - Extra parameters such as 'cacheControl'.
186
+ * @returns A promise resolving to the generated URL and expiration payload.
187
+ */
188
+ async _getUrl(file: FileType, expiresIn = 3600, action: any = 'read', extra: any = {}) {
145
189
  const commandArgs: any = {
146
190
  Bucket: file.bucket,
147
191
  Key: encodeURI(file.ref),
@@ -159,6 +203,12 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
159
203
  return { url, expiresIn }
160
204
  }
161
205
 
206
+ /**
207
+ * Deletes an object from the S3 Bucket.
208
+ *
209
+ * @param file - The file to remove.
210
+ * @returns A promise resolving to true on success.
211
+ */
162
212
  async delete(file: FileType) {
163
213
  Storage.debug(`Deleting file ${file.bucket}/${file.ref}`)
164
214
  const command = new DeleteObjectCommand({
@@ -172,6 +222,12 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
172
222
  return true
173
223
  }
174
224
 
225
+ /**
226
+ * Downloads an S3 object and returns it as a Node.js Readable stream.
227
+ *
228
+ * @param file - The target file.
229
+ * @returns A promise resolving to the ReadStream.
230
+ */
175
231
  async getReadable(file: FileType): Promise<Readable> {
176
232
  Storage.debug(`GET Readable for ${file.ref}`)
177
233
  const command = new GetObjectCommand({
@@ -188,6 +244,13 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
188
244
  return readable
189
245
  }
190
246
 
247
+ /**
248
+ * Issues a HEAD request to fetch S3 object metadata like size and content-type
249
+ * without downloading the actual payload.
250
+ *
251
+ * @param file - The file footprint.
252
+ * @returns A promise resolving to the augmented metadata.
253
+ */
191
254
  async getMetaData(file: FileType): Promise<FileType> {
192
255
  const command = new HeadObjectCommand({
193
256
  Bucket: file.bucket,
@@ -204,6 +267,13 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
204
267
  return meta
205
268
  }
206
269
 
270
+ /**
271
+ * Directly pipes an S3 object to an external HTTP response or stream.
272
+ *
273
+ * @param file - Target file.
274
+ * @param res - The response or writable stream.
275
+ * @returns The piped stream instance.
276
+ */
207
277
  async stream(file: FileType, res: any) {
208
278
  const command = new GetObjectCommand({
209
279
  Bucket: file.bucket,
@@ -219,6 +289,13 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
219
289
  return readable.pipe(res)
220
290
  }
221
291
 
292
+ /**
293
+ * Downloads an S3 object and writes it directly to the local filesystem.
294
+ *
295
+ * @param file - The remote file.
296
+ * @param meta - Local download path instructions.
297
+ * @returns A promise resolving to the local file path.
298
+ */
222
299
  async download(file: FileType, meta: DownloadFileMetaType) {
223
300
  const stream: Readable = await this.getReadable(file)
224
301
  await new Promise((res) =>
@@ -228,6 +305,13 @@ export class S3StorageAdapter extends AbstractStorageAdapter {
228
305
  return meta.path
229
306
  }
230
307
 
308
+ /**
309
+ * Generates a presigned PUT URL allowing clients to upload directly to S3, bypassing the backend.
310
+ *
311
+ * @param file - The requested upload file destination.
312
+ * @param expiresIn - Token expiration in seconds.
313
+ * @returns A promise resolving to the upload URL instructions.
314
+ */
231
315
  async getUploadUrl(
232
316
  file: FileType,
233
317
  expiresIn = 3600