s3mini 0.3.0 → 0.4.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/src/S3.ts CHANGED
@@ -27,7 +27,7 @@ import * as U from './utils.js';
27
27
  * // Delete a file
28
28
  * await s3.deleteObject('example.txt');
29
29
  */
30
- class s3mini {
30
+ class S3mini {
31
31
  /**
32
32
  * Creates an instance of the S3 class.
33
33
  *
@@ -260,8 +260,17 @@ class s3mini {
260
260
  headers[C.HEADER_AMZ_CONTENT_SHA256] = C.UNSIGNED_PAYLOAD; // body ? U.hash(body) : C.UNSIGNED_PAYLOAD;
261
261
  headers[C.HEADER_AMZ_DATE] = fullDatetime;
262
262
  headers[C.HEADER_HOST] = url.host;
263
- const canonicalHeaders = this._buildCanonicalHeaders(headers);
264
- const signedHeaders = Object.keys(headers)
263
+ // sort headers alphabetically by key
264
+ const ignoredHeaders = ['authorization', 'content-length', 'content-type', 'user-agent'];
265
+ let headersForSigning = Object.fromEntries(
266
+ Object.entries(headers).filter(([key]) => !ignoredHeaders.includes(key.toLowerCase())),
267
+ );
268
+
269
+ headersForSigning = Object.fromEntries(
270
+ Object.entries(headersForSigning).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)),
271
+ );
272
+ const canonicalHeaders = this._buildCanonicalHeaders(headersForSigning);
273
+ const signedHeaders = Object.keys(headersForSigning)
265
274
  .map(key => key.toLowerCase())
266
275
  .sort()
267
276
  .join(';');
@@ -277,7 +286,6 @@ class s3mini {
277
286
  private _buildCanonicalHeaders(headers: Record<string, string | number>): string {
278
287
  return Object.entries(headers)
279
288
  .map(([key, value]) => `${key.toLowerCase()}:${String(value).trim()}`)
280
- .sort()
281
289
  .join('\n');
282
290
  }
283
291
 
@@ -288,14 +296,15 @@ class s3mini {
288
296
  canonicalHeaders: string,
289
297
  signedHeaders: string,
290
298
  ): string {
291
- return [
299
+ const parts = [
292
300
  method,
293
301
  url.pathname,
294
302
  this._buildCanonicalQueryString(query),
295
- `${canonicalHeaders}\n`,
303
+ canonicalHeaders + '\n', // Canonical headers end with extra newline
296
304
  signedHeaders,
297
305
  C.UNSIGNED_PAYLOAD,
298
- ].join('\n');
306
+ ];
307
+ return parts.join('\n');
299
308
  }
300
309
 
301
310
  private _buildCredentialScope(shortDatetime: string): string {
@@ -332,9 +341,9 @@ class s3mini {
332
341
  tolerated = [], // [200, 404] etc.
333
342
  withQuery = false, // append query string to signed URL
334
343
  }: {
335
- query?: Record<string, unknown>;
344
+ query?: Record<string, unknown> | undefined;
336
345
  body?: string | Buffer | undefined;
337
- headers?: Record<string, string | number | undefined>;
346
+ headers?: Record<string, string | number | undefined> | IT.SSECHeaders | undefined;
338
347
  tolerated?: number[] | undefined;
339
348
  withQuery?: boolean | undefined;
340
349
  } = {},
@@ -343,14 +352,10 @@ class s3mini {
343
352
  if (!['GET', 'HEAD', 'PUT', 'POST', 'DELETE'].includes(method)) {
344
353
  throw new Error(`${C.ERROR_PREFIX}Unsupported HTTP method ${method as string}`);
345
354
  }
346
- if (key) {
347
- this._checkKey(key); // allow '' for bucket‑level
348
- }
349
355
 
350
356
  const { filteredOpts, conditionalHeaders } = ['GET', 'HEAD'].includes(method)
351
357
  ? this._filterIfHeaders(query)
352
358
  : { filteredOpts: query, conditionalHeaders: {} };
353
-
354
359
  const baseHeaders: Record<string, string | number> = {
355
360
  [C.HEADER_AMZ_CONTENT_SHA256]: C.UNSIGNED_PAYLOAD,
356
361
  // ...(['GET', 'HEAD'].includes(method) ? { [C.HEADER_CONTENT_TYPE]: C.JSON_CONTENT_TYPE } : {}),
@@ -475,7 +480,7 @@ class s3mini {
475
480
  * @param {string} [prefix=''] - The prefix to filter objects by.
476
481
  * @param {number} [maxKeys] - The maximum number of keys to return. If not provided, all keys will be returned.
477
482
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
478
- * @returns {Promise<object[] | null>} A promise that resolves to an array of objects or null if the bucket is empty.
483
+ * @returns {Promise<IT.ListObject[] | null>} A promise that resolves to an array of objects or null if the bucket is empty.
479
484
  * @example
480
485
  * // List all objects
481
486
  * const objects = await s3.listObjects();
@@ -489,7 +494,7 @@ class s3mini {
489
494
  maxKeys?: number,
490
495
  // method: IT.HttpMethod = 'GET', // 'GET' or 'HEAD'
491
496
  opts: Record<string, unknown> = {},
492
- ): Promise<object[] | null> {
497
+ ): Promise<IT.ListObject[] | null> {
493
498
  this._checkDelimiter(delimiter);
494
499
  this._checkPrefix(prefix);
495
500
  this._checkOpts(opts);
@@ -499,7 +504,7 @@ class s3mini {
499
504
  const unlimited = !(maxKeys && maxKeys > 0);
500
505
  let remaining = unlimited ? Infinity : maxKeys;
501
506
  let token: string | undefined;
502
- const all: object[] = [];
507
+ const all: IT.ListObject[] = [];
503
508
 
504
509
  do {
505
510
  const batchSize = Math.min(remaining, 1000); // S3 ceiling
@@ -542,7 +547,7 @@ class s3mini {
542
547
  const contents = out.Contents || out.contents; // S3 v2 vs v1
543
548
  if (contents) {
544
549
  const batch = Array.isArray(contents) ? contents : [contents];
545
- all.push(...(batch as object[]));
550
+ all.push(...(batch as IT.ListObject[]));
546
551
  if (!unlimited) {
547
552
  remaining -= batch.length;
548
553
  }
@@ -607,11 +612,21 @@ class s3mini {
607
612
  * Get an object from the S3-compatible service.
608
613
  * This method sends a request to retrieve the specified object from the S3-compatible service.
609
614
  * @param {string} key - The key of the object to retrieve.
610
- * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
615
+ * @param {Record<string, unknown>} [opts] - Additional options for the request.
616
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
611
617
  * @returns A promise that resolves to the object data (string) or null if not found.
612
618
  */
613
- public async getObject(key: string, opts: Record<string, unknown> = {}): Promise<string | null> {
614
- const res = await this._signedRequest('GET', key, { query: opts, tolerated: [200, 404, 412, 304] });
619
+ public async getObject(
620
+ key: string,
621
+ opts: Record<string, unknown> = {},
622
+ ssecHeaders?: IT.SSECHeaders,
623
+ ): Promise<string | null> {
624
+ // if ssecHeaders is set, add it to headers
625
+ const res = await this._signedRequest('GET', key, {
626
+ query: opts, // use opts.query if it exists, otherwise use an empty object
627
+ tolerated: [200, 404, 412, 304],
628
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
629
+ });
615
630
  if ([404, 412, 304].includes(res.status)) {
616
631
  return null;
617
632
  }
@@ -623,10 +638,19 @@ class s3mini {
623
638
  * This method sends a request to retrieve the specified object and returns the full response.
624
639
  * @param {string} key - The key of the object to retrieve.
625
640
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
641
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
626
642
  * @returns A promise that resolves to the Response object or null if not found.
627
643
  */
628
- public async getObjectResponse(key: string, opts: Record<string, unknown> = {}): Promise<Response | null> {
629
- const res = await this._signedRequest('GET', key, { query: opts, tolerated: [200, 404, 412, 304] });
644
+ public async getObjectResponse(
645
+ key: string,
646
+ opts: Record<string, unknown> = {},
647
+ ssecHeaders?: IT.SSECHeaders,
648
+ ): Promise<Response | null> {
649
+ const res = await this._signedRequest('GET', key, {
650
+ query: opts,
651
+ tolerated: [200, 404, 412, 304],
652
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
653
+ });
630
654
  if ([404, 412, 304].includes(res.status)) {
631
655
  return null;
632
656
  }
@@ -638,10 +662,19 @@ class s3mini {
638
662
  * This method sends a request to retrieve the specified object and returns it as an ArrayBuffer.
639
663
  * @param {string} key - The key of the object to retrieve.
640
664
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
665
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
641
666
  * @returns A promise that resolves to the object data as an ArrayBuffer or null if not found.
642
667
  */
643
- public async getObjectArrayBuffer(key: string, opts: Record<string, unknown> = {}): Promise<ArrayBuffer | null> {
644
- const res = await this._signedRequest('GET', key, { query: opts, tolerated: [200, 404, 412, 304] });
668
+ public async getObjectArrayBuffer(
669
+ key: string,
670
+ opts: Record<string, unknown> = {},
671
+ ssecHeaders?: IT.SSECHeaders,
672
+ ): Promise<ArrayBuffer | null> {
673
+ const res = await this._signedRequest('GET', key, {
674
+ query: opts,
675
+ tolerated: [200, 404, 412, 304],
676
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
677
+ });
645
678
  if ([404, 412, 304].includes(res.status)) {
646
679
  return null;
647
680
  }
@@ -653,10 +686,19 @@ class s3mini {
653
686
  * This method sends a request to retrieve the specified object and returns it as JSON.
654
687
  * @param {string} key - The key of the object to retrieve.
655
688
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
689
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
656
690
  * @returns A promise that resolves to the object data as JSON or null if not found.
657
691
  */
658
- public async getObjectJSON<T = unknown>(key: string, opts: Record<string, unknown> = {}): Promise<T | null> {
659
- const res = await this._signedRequest('GET', key, { query: opts, tolerated: [200, 404, 412, 304] });
692
+ public async getObjectJSON<T = unknown>(
693
+ key: string,
694
+ opts: Record<string, unknown> = {},
695
+ ssecHeaders?: IT.SSECHeaders,
696
+ ): Promise<T | null> {
697
+ const res = await this._signedRequest('GET', key, {
698
+ query: opts,
699
+ tolerated: [200, 404, 412, 304],
700
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
701
+ });
660
702
  if ([404, 412, 304].includes(res.status)) {
661
703
  return null;
662
704
  }
@@ -668,14 +710,20 @@ class s3mini {
668
710
  * This method sends a request to retrieve the specified object and its ETag.
669
711
  * @param {string} key - The key of the object to retrieve.
670
712
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
713
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
671
714
  * @returns A promise that resolves to an object containing the ETag and the object data as an ArrayBuffer or null if not found.
672
715
  */
673
716
  public async getObjectWithETag(
674
717
  key: string,
675
718
  opts: Record<string, unknown> = {},
719
+ ssecHeaders?: IT.SSECHeaders,
676
720
  ): Promise<{ etag: string | null; data: ArrayBuffer | null }> {
677
721
  try {
678
- const res = await this._signedRequest('GET', key, { query: opts, tolerated: [200, 404, 412, 304] });
722
+ const res = await this._signedRequest('GET', key, {
723
+ query: opts,
724
+ tolerated: [200, 404, 412, 304],
725
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
726
+ });
679
727
 
680
728
  if ([404, 412, 304].includes(res.status)) {
681
729
  return { etag: null, data: null };
@@ -700,6 +748,7 @@ class s3mini {
700
748
  * @param {number} [rangeFrom=0] - The starting byte for the range (if not whole file).
701
749
  * @param {number} [rangeTo=this.requestSizeInBytes] - The ending byte for the range (if not whole file).
702
750
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
751
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
703
752
  * @returns A promise that resolves to the Response object.
704
753
  */
705
754
  public async getObjectRaw(
@@ -708,12 +757,13 @@ class s3mini {
708
757
  rangeFrom = 0,
709
758
  rangeTo = this.requestSizeInBytes,
710
759
  opts: Record<string, unknown> = {},
760
+ ssecHeaders?: IT.SSECHeaders,
711
761
  ): Promise<Response> {
712
762
  const rangeHdr: Record<string, string | number> = wholeFile ? {} : { range: `bytes=${rangeFrom}-${rangeTo - 1}` };
713
763
 
714
764
  return this._signedRequest('GET', key, {
715
765
  query: { ...opts },
716
- headers: rangeHdr,
766
+ headers: { ...rangeHdr, ...ssecHeaders },
717
767
  withQuery: true, // keep ?query=string behaviour
718
768
  });
719
769
  }
@@ -725,9 +775,11 @@ class s3mini {
725
775
  * @returns A promise that resolves to the content length of the object in bytes, or 0 if not found.
726
776
  * @throws {Error} If the content length header is not found in the response.
727
777
  */
728
- public async getContentLength(key: string): Promise<number> {
778
+ public async getContentLength(key: string, ssecHeaders?: IT.SSECHeaders): Promise<number> {
729
779
  try {
730
- const res = await this._signedRequest('HEAD', key);
780
+ const res = await this._signedRequest('HEAD', key, {
781
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
782
+ });
731
783
  const len = res.headers.get(C.HEADER_CONTENT_LENGTH);
732
784
  return len ? +len : 0;
733
785
  } catch (err) {
@@ -762,6 +814,7 @@ class s3mini {
762
814
  * Retrieves the ETag of an object without downloading its content.
763
815
  * @param {string} key - The key of the object to retrieve the ETag for.
764
816
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
817
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
765
818
  * @returns {Promise<string | null>} A promise that resolves to the ETag value or null if the object is not found.
766
819
  * @throws {Error} If the ETag header is not found in the response.
767
820
  * @example
@@ -770,16 +823,25 @@ class s3mini {
770
823
  * console.log(`File ETag: ${etag}`);
771
824
  * }
772
825
  */
773
- public async getEtag(key: string, opts: Record<string, unknown> = {}): Promise<string | null> {
826
+ public async getEtag(
827
+ key: string,
828
+ opts: Record<string, unknown> = {},
829
+ ssecHeaders?: IT.SSECHeaders,
830
+ ): Promise<string | null> {
774
831
  const res = await this._signedRequest('HEAD', key, {
775
832
  query: opts,
776
- tolerated: [200, 404],
833
+ tolerated: [200, 304, 404, 412],
834
+ headers: ssecHeaders ? { ...ssecHeaders } : undefined,
777
835
  });
778
836
 
779
837
  if (res.status === 404) {
780
838
  return null;
781
839
  }
782
840
 
841
+ if (res.status === 412 || res.status === 304) {
842
+ return null; // ETag mismatch
843
+ }
844
+
783
845
  const etag = res.headers.get(C.HEADER_ETAG);
784
846
  if (!etag) {
785
847
  throw new Error(`${C.ERROR_PREFIX}ETag not found in response headers`);
@@ -793,6 +855,7 @@ class s3mini {
793
855
  * @param {string} key - The key/path where the object will be stored.
794
856
  * @param {string | Buffer} data - The data to upload (string or Buffer).
795
857
  * @param {string} [fileType='application/octet-stream'] - The MIME type of the file.
858
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
796
859
  * @returns {Promise<Response>} A promise that resolves to the Response object from the upload request.
797
860
  * @throws {TypeError} If data is not a string or Buffer.
798
861
  * @example
@@ -807,6 +870,7 @@ class s3mini {
807
870
  key: string,
808
871
  data: string | Buffer,
809
872
  fileType: string = C.DEFAULT_STREAM_CONTENT_TYPE,
873
+ ssecHeaders?: IT.SSECHeaders,
810
874
  ): Promise<Response> {
811
875
  if (!(data instanceof Buffer || typeof data === 'string')) {
812
876
  throw new TypeError(C.ERROR_DATA_BUFFER_REQUIRED);
@@ -816,6 +880,7 @@ class s3mini {
816
880
  headers: {
817
881
  [C.HEADER_CONTENT_LENGTH]: typeof data === 'string' ? Buffer.byteLength(data) : data.length,
818
882
  [C.HEADER_CONTENT_TYPE]: fileType,
883
+ ...ssecHeaders,
819
884
  },
820
885
  tolerated: [200],
821
886
  });
@@ -825,6 +890,7 @@ class s3mini {
825
890
  * Initiates a multipart upload and returns the upload ID.
826
891
  * @param {string} key - The key/path where the object will be stored.
827
892
  * @param {string} [fileType='application/octet-stream'] - The MIME type of the file.
893
+ * @param {IT.SSECHeaders?} [ssecHeaders] - Server-Side Encryption headers, if any.
828
894
  * @returns {Promise<string>} A promise that resolves to the upload ID for the multipart upload.
829
895
  * @throws {TypeError} If key is invalid or fileType is not a string.
830
896
  * @throws {Error} If the multipart upload fails to initialize.
@@ -832,13 +898,17 @@ class s3mini {
832
898
  * const uploadId = await s3.getMultipartUploadId('large-file.zip', 'application/zip');
833
899
  * console.log(`Started multipart upload: ${uploadId}`);
834
900
  */
835
- public async getMultipartUploadId(key: string, fileType: string = C.DEFAULT_STREAM_CONTENT_TYPE): Promise<string> {
901
+ public async getMultipartUploadId(
902
+ key: string,
903
+ fileType: string = C.DEFAULT_STREAM_CONTENT_TYPE,
904
+ ssecHeaders?: IT.SSECHeaders,
905
+ ): Promise<string> {
836
906
  this._checkKey(key);
837
907
  if (typeof fileType !== 'string') {
838
908
  throw new TypeError(`${C.ERROR_PREFIX}fileType must be a string`);
839
909
  }
840
910
  const query = { uploads: '' };
841
- const headers = { [C.HEADER_CONTENT_TYPE]: fileType };
911
+ const headers = { [C.HEADER_CONTENT_TYPE]: fileType, ...ssecHeaders };
842
912
 
843
913
  const res = await this._signedRequest('POST', key, {
844
914
  query,
@@ -883,6 +953,7 @@ class s3mini {
883
953
  * @param {Buffer | string} data - The data for this part.
884
954
  * @param {number} partNumber - The part number (must be between 1 and 10,000).
885
955
  * @param {Record<string, unknown>} [opts={}] - Additional options for the request.
956
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
886
957
  * @returns {Promise<IT.UploadPart>} A promise that resolves to an object containing the partNumber and etag.
887
958
  * @throws {TypeError} If any parameter is invalid.
888
959
  * @example
@@ -900,6 +971,7 @@ class s3mini {
900
971
  data: Buffer | string,
901
972
  partNumber: number,
902
973
  opts: Record<string, unknown> = {},
974
+ ssecHeaders?: IT.SSECHeaders,
903
975
  ): Promise<IT.UploadPart> {
904
976
  this._validateUploadPartParams(key, uploadId, data, partNumber, opts);
905
977
 
@@ -907,7 +979,10 @@ class s3mini {
907
979
  const res = await this._signedRequest('PUT', key, {
908
980
  query,
909
981
  body: data,
910
- headers: { [C.HEADER_CONTENT_LENGTH]: typeof data === 'string' ? Buffer.byteLength(data) : data.length },
982
+ headers: {
983
+ [C.HEADER_CONTENT_LENGTH]: typeof data === 'string' ? Buffer.byteLength(data) : data.length,
984
+ ...ssecHeaders,
985
+ },
911
986
  });
912
987
 
913
988
  return { partNumber, etag: U.sanitizeETag(res.headers.get('etag') || '') };
@@ -978,6 +1053,7 @@ class s3mini {
978
1053
  * Aborts a multipart upload and removes all uploaded parts.
979
1054
  * @param {string} key - The key of the object being uploaded.
980
1055
  * @param {string} uploadId - The upload ID to abort.
1056
+ * @param {IT.SSECHeaders} [ssecHeaders] - Server-Side Encryption headers, if any.
981
1057
  * @returns {Promise<object>} A promise that resolves to an object containing the abort status and details.
982
1058
  * @throws {TypeError} If key or uploadId is invalid.
983
1059
  * @throws {Error} If the abort operation fails.
@@ -989,14 +1065,14 @@ class s3mini {
989
1065
  * console.error('Failed to abort upload:', error);
990
1066
  * }
991
1067
  */
992
- public async abortMultipartUpload(key: string, uploadId: string): Promise<object> {
1068
+ public async abortMultipartUpload(key: string, uploadId: string, ssecHeaders?: IT.SSECHeaders): Promise<object> {
993
1069
  this._checkKey(key);
994
1070
  if (!uploadId) {
995
1071
  throw new TypeError(C.ERROR_UPLOAD_ID_REQUIRED);
996
1072
  }
997
1073
 
998
1074
  const query = { uploadId };
999
- const headers = { [C.HEADER_CONTENT_TYPE]: C.XML_CONTENT_TYPE };
1075
+ const headers = { [C.HEADER_CONTENT_TYPE]: C.XML_CONTENT_TYPE, ...(ssecHeaders ? { ...ssecHeaders } : {}) };
1000
1076
 
1001
1077
  const res = await this._signedRequest('DELETE', key, {
1002
1078
  query,
@@ -1192,5 +1268,10 @@ class s3mini {
1192
1268
  }
1193
1269
  }
1194
1270
 
1195
- export { s3mini };
1196
- export default s3mini;
1271
+ /**
1272
+ * @deprecated Use `S3mini` instead.
1273
+ */
1274
+ const s3mini = S3mini;
1275
+
1276
+ export { S3mini, s3mini };
1277
+ export default S3mini;
package/src/consts.ts CHANGED
@@ -15,9 +15,9 @@ export const DEFAULT_REQUEST_SIZE_IN_BYTES = 8 * 1024 * 1024;
15
15
  export const HEADER_AMZ_CONTENT_SHA256 = 'x-amz-content-sha256';
16
16
  export const HEADER_AMZ_DATE = 'x-amz-date';
17
17
  export const HEADER_HOST = 'host';
18
- export const HEADER_AUTHORIZATION = 'Authorization';
19
- export const HEADER_CONTENT_TYPE = 'Content-Type';
20
- export const HEADER_CONTENT_LENGTH = 'Content-Length';
18
+ export const HEADER_AUTHORIZATION = 'authorization';
19
+ export const HEADER_CONTENT_TYPE = 'content-type';
20
+ export const HEADER_CONTENT_LENGTH = 'content-length';
21
21
  export const HEADER_ETAG = 'etag';
22
22
  export const HEADER_LAST_MODIFIED = 'last-modified';
23
23
 
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- import { s3mini } from './S3.js';
3
+ import { S3mini, s3mini } from './S3.js';
4
4
  import { sanitizeETag, runInBatches } from './utils.js';
5
5
 
6
6
  // Export the S3 class as default export and named export
7
- export { s3mini, sanitizeETag, runInBatches };
8
- export default s3mini;
7
+ export { S3mini, s3mini, sanitizeETag, runInBatches };
8
+ export default S3mini;
9
9
 
10
10
  // Re-export types
11
11
  export type {
package/src/types.ts CHANGED
@@ -8,6 +8,12 @@ export interface S3Config {
8
8
  logger?: Logger;
9
9
  }
10
10
 
11
+ export interface SSECHeaders {
12
+ 'x-amz-server-side-encryption-customer-algorithm': string;
13
+ 'x-amz-server-side-encryption-customer-key': string;
14
+ 'x-amz-server-side-encryption-customer-key-md5': string;
15
+ }
16
+
11
17
  export interface Crypto {
12
18
  createHmac: (
13
19
  algorithm: string,
@@ -33,6 +39,14 @@ export interface UploadPart {
33
39
  etag: string;
34
40
  }
35
41
 
42
+ export interface ListObject {
43
+ Key: string;
44
+ Size: number;
45
+ LastModified: Date;
46
+ ETag: string;
47
+ StorageClass: string;
48
+ }
49
+
36
50
  export interface CompleteMultipartUploadResult {
37
51
  location: string;
38
52
  bucket: string;
package/src/utils.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  'use strict';
2
-
3
2
  import type { Crypto, XmlValue, XmlMap, ListBucketResponse, ErrorWithCode } from './types.js';
4
3
  declare const crypto: Crypto;
5
4