lean-s3 0.9.12 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +13 -31
- package/package.json +18 -17
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { Readable } from "node:stream";
|
|
|
3
3
|
import { Agent, request } from "undici";
|
|
4
4
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
5
5
|
import { createHash, createHmac } from "node:crypto";
|
|
6
|
-
|
|
7
6
|
//#region src/S3Stat.ts
|
|
8
7
|
var S3Stat = class S3Stat {
|
|
9
8
|
etag;
|
|
@@ -30,7 +29,6 @@ var S3Stat = class S3Stat {
|
|
|
30
29
|
return new S3Stat(etag, new Date(lm), size, ct);
|
|
31
30
|
}
|
|
32
31
|
};
|
|
33
|
-
|
|
34
32
|
//#endregion
|
|
35
33
|
//#region src/S3Error.ts
|
|
36
34
|
var S3Error = class extends Error {
|
|
@@ -48,7 +46,6 @@ var S3Error = class extends Error {
|
|
|
48
46
|
this.status = status;
|
|
49
47
|
}
|
|
50
48
|
};
|
|
51
|
-
|
|
52
49
|
//#endregion
|
|
53
50
|
//#region src/S3BucketEntry.ts
|
|
54
51
|
/**
|
|
@@ -78,7 +75,6 @@ var S3BucketEntry = class S3BucketEntry {
|
|
|
78
75
|
return new S3BucketEntry(source.Key, source.Size, new Date(source.LastModified), source.ETag, source.StorageClass, source.ChecksumAlgorithm, source.ChecksumType);
|
|
79
76
|
}
|
|
80
77
|
};
|
|
81
|
-
|
|
82
78
|
//#endregion
|
|
83
79
|
//#region src/sign.ts
|
|
84
80
|
function deriveSigningKey(date, region, secretAccessKey) {
|
|
@@ -116,7 +112,6 @@ function sha256(data) {
|
|
|
116
112
|
function md5Base64(data) {
|
|
117
113
|
return createHash("md5").update(data).digest("base64");
|
|
118
114
|
}
|
|
119
|
-
|
|
120
115
|
//#endregion
|
|
121
116
|
//#region src/KeyCache.ts
|
|
122
117
|
var KeyCache = class {
|
|
@@ -135,7 +130,6 @@ var KeyCache = class {
|
|
|
135
130
|
return newKey;
|
|
136
131
|
}
|
|
137
132
|
};
|
|
138
|
-
|
|
139
133
|
//#endregion
|
|
140
134
|
//#region src/AmzDate.ts
|
|
141
135
|
const ONE_DAY = 1e3 * 60 * 60 * 24;
|
|
@@ -157,7 +151,6 @@ function pad4(v) {
|
|
|
157
151
|
function pad2(v) {
|
|
158
152
|
return v < 10 ? `0${v}` : v.toString();
|
|
159
153
|
}
|
|
160
|
-
|
|
161
154
|
//#endregion
|
|
162
155
|
//#region src/url.ts
|
|
163
156
|
function buildRequestUrl(endpoint, bucket, region, path) {
|
|
@@ -196,7 +189,6 @@ function prepareHeadersForSigning(unfilteredHeadersUnsorted) {
|
|
|
196
189
|
function getRangeHeader(start, endExclusive) {
|
|
197
190
|
return typeof start === "number" || typeof endExclusive === "number" ? `bytes=${start ?? 0}-${typeof endExclusive === "number" ? endExclusive - 1 : ""}` : void 0;
|
|
198
191
|
}
|
|
199
|
-
|
|
200
192
|
//#endregion
|
|
201
193
|
//#region src/error.ts
|
|
202
194
|
const xmlParser$1 = new XMLParser();
|
|
@@ -236,17 +228,14 @@ function parseAndGetXmlError(body, path) {
|
|
|
236
228
|
}
|
|
237
229
|
return new S3Error(error.Code || "Unknown", path, { message: error.Message || void 0 });
|
|
238
230
|
}
|
|
239
|
-
|
|
240
231
|
//#endregion
|
|
241
232
|
//#region src/request.ts
|
|
242
233
|
function getAuthorizationHeader(keyCache, method, path, query, date, sortedSignedHeaders, region, contentHashStr, accessKeyId, secretAccessKey) {
|
|
243
234
|
const dataDigest = createCanonicalDataDigest(method, path, query, sortedSignedHeaders, contentHashStr);
|
|
244
|
-
const
|
|
245
|
-
const signature = signCanonicalDataHash(signingKey, dataDigest, date, region);
|
|
235
|
+
const signature = signCanonicalDataHash(keyCache.computeIfAbsent(date, region, accessKeyId, secretAccessKey), dataDigest, date, region);
|
|
246
236
|
const signedHeadersSpec = Object.keys(sortedSignedHeaders).join(";");
|
|
247
237
|
return `AWS4-HMAC-SHA256 Credential=${`${accessKeyId}/${date.date}/${region}/s3/aws4_request`}, SignedHeaders=${signedHeadersSpec}, Signature=${signature}`;
|
|
248
238
|
}
|
|
249
|
-
|
|
250
239
|
//#endregion
|
|
251
240
|
//#region src/branded.ts
|
|
252
241
|
function ensureValidBucketName(bucket) {
|
|
@@ -282,13 +271,11 @@ function ensureValidRegion(region) {
|
|
|
282
271
|
if (region.length < 1) throw new RangeError("`region` must be at least 1 character long.");
|
|
283
272
|
return region;
|
|
284
273
|
}
|
|
285
|
-
|
|
286
274
|
//#endregion
|
|
287
275
|
//#region src/assertNever.ts
|
|
288
276
|
function assertNever(v) {
|
|
289
277
|
throw new TypeError(`Expected value not to have type ${typeof v}`);
|
|
290
278
|
}
|
|
291
|
-
|
|
292
279
|
//#endregion
|
|
293
280
|
//#region src/encode.ts
|
|
294
281
|
/**
|
|
@@ -311,7 +298,6 @@ function getContentDispositionHeader(value) {
|
|
|
311
298
|
function encodeURIComponentExtended(value) {
|
|
312
299
|
return encodeURIComponent(value).replaceAll(":", "%3A").replaceAll("+", "%2B").replaceAll("(", "%28").replaceAll(")", "%29").replaceAll(",", "%2C").replaceAll("'", "%27").replaceAll("*", "%2A");
|
|
313
300
|
}
|
|
314
|
-
|
|
315
301
|
//#endregion
|
|
316
302
|
//#region src/S3Client.ts
|
|
317
303
|
const kWrite = Symbol("kWrite");
|
|
@@ -442,8 +428,7 @@ var S3Client = class {
|
|
|
442
428
|
const contentDisposition = options.response?.contentDisposition;
|
|
443
429
|
const responseContentDisposition = contentDisposition ? getContentDispositionHeader(contentDisposition) : void 0;
|
|
444
430
|
const res = buildRequestUrl(endpoint, bucket, region, ensureValidPath(path));
|
|
445
|
-
const
|
|
446
|
-
const date = getAmzDate(now);
|
|
431
|
+
const date = getAmzDate(/* @__PURE__ */ new Date());
|
|
447
432
|
const query = buildSearchParams(`${this.#options.accessKeyId}/${date.date}/${region}/s3/aws4_request`, date, options.expiresIn ?? 3600, typeof contentLength === "number" || typeof contentType === "string" ? typeof contentLength === "number" && typeof contentType === "string" ? "content-length;content-type;host" : typeof contentLength === "number" ? "content-length;host" : typeof contentType === "string" ? "content-type;host" : "" : "host", unsignedPayload, options.storageClass, this.#options.sessionToken, options.acl, responseContentDisposition);
|
|
448
433
|
const dataDigest = typeof contentLength === "number" || typeof contentType === "string" ? createCanonicalDataDigest(method, res.pathname, query, typeof contentLength === "number" && typeof contentType === "string" ? {
|
|
449
434
|
"content-length": String(contentLength),
|
|
@@ -456,8 +441,7 @@ var S3Client = class {
|
|
|
456
441
|
"content-type": contentType,
|
|
457
442
|
host: res.host
|
|
458
443
|
} : {}, unsignedPayload) : createCanonicalDataDigestHostOnly(method, res.pathname, query, res.host);
|
|
459
|
-
|
|
460
|
-
res.search = `${query}&X-Amz-Signature=${signCanonicalDataHash(signingKey, dataDigest, date, region)}`;
|
|
444
|
+
res.search = `${query}&X-Amz-Signature=${signCanonicalDataHash(this.#keyCache.computeIfAbsent(date, region, this.#options.accessKeyId, this.#options.secretAccessKey), dataDigest, date, region)}`;
|
|
461
445
|
return res.toString();
|
|
462
446
|
}
|
|
463
447
|
presignPost(options) {
|
|
@@ -925,11 +909,11 @@ var S3Client = class {
|
|
|
925
909
|
async [kSignedRequest](region, endpoint, bucket, method, pathWithoutBucket, query, body, additionalSignedHeaders, additionalUnsignedHeaders, contentHash, signal) {
|
|
926
910
|
const url = buildRequestUrl(endpoint, bucket, region, pathWithoutBucket);
|
|
927
911
|
if (query) url.search = query;
|
|
928
|
-
const now$
|
|
929
|
-
const contentHashStr = contentHash?.toString("hex") ??
|
|
912
|
+
const now$1 = now();
|
|
913
|
+
const contentHashStr = contentHash?.toString("hex") ?? "UNSIGNED-PAYLOAD";
|
|
930
914
|
const headersToBeSigned = prepareHeadersForSigning({
|
|
931
915
|
host: url.host,
|
|
932
|
-
"x-amz-date": now$
|
|
916
|
+
"x-amz-date": now$1.dateTime,
|
|
933
917
|
"x-amz-content-sha256": contentHashStr,
|
|
934
918
|
...additionalSignedHeaders
|
|
935
919
|
});
|
|
@@ -940,7 +924,7 @@ var S3Client = class {
|
|
|
940
924
|
dispatcher: this.#dispatcher,
|
|
941
925
|
headers: {
|
|
942
926
|
...headersToBeSigned,
|
|
943
|
-
authorization: getAuthorizationHeader(this.#keyCache, method, url.pathname, query ?? "", now$
|
|
927
|
+
authorization: getAuthorizationHeader(this.#keyCache, method, url.pathname, query ?? "", now$1, headersToBeSigned, region, contentHashStr, this.#options.accessKeyId, this.#options.secretAccessKey),
|
|
944
928
|
...additionalUnsignedHeaders,
|
|
945
929
|
"user-agent": "lean-s3"
|
|
946
930
|
},
|
|
@@ -961,7 +945,7 @@ var S3Client = class {
|
|
|
961
945
|
const region = this.#options.region;
|
|
962
946
|
const url = buildRequestUrl(endpoint, bucket, region, path);
|
|
963
947
|
const now$2 = now();
|
|
964
|
-
const contentHashStr = contentHash?.toString("hex") ??
|
|
948
|
+
const contentHashStr = contentHash?.toString("hex") ?? "UNSIGNED-PAYLOAD";
|
|
965
949
|
const headersToBeSigned = prepareHeadersForSigning({
|
|
966
950
|
"content-length": contentLength?.toString() ?? void 0,
|
|
967
951
|
"content-type": contentType,
|
|
@@ -1001,16 +985,16 @@ var S3Client = class {
|
|
|
1001
985
|
const bucket = this.#options.bucket;
|
|
1002
986
|
const endpoint = this.#options.endpoint;
|
|
1003
987
|
const region = this.#options.region;
|
|
1004
|
-
const now$
|
|
988
|
+
const now$3 = now();
|
|
1005
989
|
const url = buildRequestUrl(endpoint, bucket, region, path);
|
|
1006
990
|
const range = getRangeHeader(rageStart, rangeEndExclusive);
|
|
1007
|
-
const contentHashStr = contentHash?.toString("hex") ??
|
|
991
|
+
const contentHashStr = contentHash?.toString("hex") ?? "UNSIGNED-PAYLOAD";
|
|
1008
992
|
const headersToBeSigned = prepareHeadersForSigning({
|
|
1009
993
|
"amz-sdk-invocation-id": crypto.randomUUID(),
|
|
1010
994
|
host: url.host,
|
|
1011
995
|
range,
|
|
1012
996
|
"x-amz-content-sha256": contentHashStr,
|
|
1013
|
-
"x-amz-date": now$
|
|
997
|
+
"x-amz-date": now$3.dateTime
|
|
1014
998
|
});
|
|
1015
999
|
const ac = new AbortController();
|
|
1016
1000
|
return new ReadableStream({
|
|
@@ -1028,7 +1012,7 @@ var S3Client = class {
|
|
|
1028
1012
|
dispatcher: this.#dispatcher,
|
|
1029
1013
|
headers: {
|
|
1030
1014
|
...headersToBeSigned,
|
|
1031
|
-
authorization: getAuthorizationHeader(this.#keyCache, "GET", url.pathname, url.search, now$
|
|
1015
|
+
authorization: getAuthorizationHeader(this.#keyCache, "GET", url.pathname, url.search, now$3, headersToBeSigned, region, contentHashStr, this.#options.accessKeyId, this.#options.secretAccessKey),
|
|
1032
1016
|
"user-agent": "lean-s3"
|
|
1033
1017
|
}
|
|
1034
1018
|
}).then((response) => {
|
|
@@ -1120,7 +1104,6 @@ function ensureParsedXml(text) {
|
|
|
1120
1104
|
});
|
|
1121
1105
|
}
|
|
1122
1106
|
}
|
|
1123
|
-
|
|
1124
1107
|
//#endregion
|
|
1125
1108
|
//#region src/S3File.ts
|
|
1126
1109
|
var S3File = class S3File {
|
|
@@ -1289,6 +1272,5 @@ var S3File = class S3File {
|
|
|
1289
1272
|
return `S3File ${nodeUtil.formatWithOptions(options, properties)}`;
|
|
1290
1273
|
}
|
|
1291
1274
|
};
|
|
1292
|
-
|
|
1293
1275
|
//#endregion
|
|
1294
|
-
export { S3BucketEntry, S3Client, S3Error, S3File, S3Stat };
|
|
1276
|
+
export { S3BucketEntry, S3Client, S3Error, S3File, S3Stat };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lean-s3",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13",
|
|
4
4
|
"description": "A server-side S3 API for the regular user.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"AWS S3",
|
|
@@ -36,29 +36,30 @@
|
|
|
36
36
|
"build": "tsdown",
|
|
37
37
|
"test": "tsgo && tsx --test src/*.test.ts src/test/*.test.ts",
|
|
38
38
|
"test:integration": "tsgo && tsx --test src/test/test.integration.ts",
|
|
39
|
-
"ci": "oxlint --deny-warnings -f github",
|
|
39
|
+
"ci": "oxlint --type-aware --deny-warnings -f github",
|
|
40
40
|
"docs": "typedoc",
|
|
41
41
|
"format": "oxfmt",
|
|
42
|
-
"lint": "oxlint",
|
|
43
|
-
"lint:fix": "oxlint --fix",
|
|
42
|
+
"lint": "oxlint --type-aware",
|
|
43
|
+
"lint:fix": "oxlint --type-aware --fix",
|
|
44
44
|
"prepublishOnly": "npm run build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"fast-xml-parser": "^5.
|
|
48
|
-
"undici": "^7.
|
|
47
|
+
"fast-xml-parser": "^5.5.6",
|
|
48
|
+
"undici": "^7.24.4"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@testcontainers/localstack": "^11.
|
|
52
|
-
"@testcontainers/minio": "^11.
|
|
53
|
-
"@testcontainers/s3mock": "^11.
|
|
54
|
-
"@types/node": "^25.
|
|
55
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
56
|
-
"expect": "^30.
|
|
57
|
-
"lefthook": "^2.1.
|
|
58
|
-
"oxfmt": "^0.
|
|
59
|
-
"oxlint": "^1.
|
|
60
|
-
"
|
|
61
|
-
"
|
|
51
|
+
"@testcontainers/localstack": "^11.13.0",
|
|
52
|
+
"@testcontainers/minio": "^11.13.0",
|
|
53
|
+
"@testcontainers/s3mock": "^11.13.0",
|
|
54
|
+
"@types/node": "^25.5.0",
|
|
55
|
+
"@typescript/native-preview": "^7.0.0-dev.20260317.1",
|
|
56
|
+
"expect": "^30.3.0",
|
|
57
|
+
"lefthook": "^2.1.4",
|
|
58
|
+
"oxfmt": "^0.41.0",
|
|
59
|
+
"oxlint": "^1.56.0",
|
|
60
|
+
"oxlint-tsgolint": "^0.17.0",
|
|
61
|
+
"testcontainers": "^11.13.0",
|
|
62
|
+
"tsdown": "^0.21.4",
|
|
62
63
|
"tsx": "^4.21.0",
|
|
63
64
|
"typedoc": "^0.28.17"
|
|
64
65
|
},
|