Skip to content

Commit 4d2cc8f

Browse files
committed
feat: change usage of all functions: s3Client is not optional
1 parent 9eb64bd commit 4d2cc8f

3 files changed

Lines changed: 34 additions & 90 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ialac/s3-utils",
3-
"version": "1.3.0",
3+
"version": "2.0.0",
44
"main": "dist/index.js",
55
"scripts": {
66
"test": "vitest",

src/index.ts

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import {
88
import { createHash } from "crypto";
99
import { Readable } from "stream";
1010

11-
let s3Client: S3Client | undefined;
12-
13-
function initS3Client(config: { endpoint: string, credentials: { accessKeyId: string, secretAccessKey: string } }) {
11+
export function getS3Client(config: { endpoint: string, credentials: { accessKeyId: string, secretAccessKey: string } }) {
1412
return new S3Client({
1513
endpoint: config.endpoint,
1614
credentials: config.credentials,
@@ -19,18 +17,7 @@ function initS3Client(config: { endpoint: string, credentials: { accessKeyId: st
1917
})
2018
}
2119

22-
export function getS3Client(config?: { endpoint: string, credentials: { accessKeyId: string, secretAccessKey: string } }) {
23-
if (s3Client == null) {
24-
if (config == null) {
25-
throw new Error("S3 client cannot be created with empty configuration. Please consider calling the function with a correct config object.");
26-
}
27-
s3Client = initS3Client(config);
28-
}
29-
return s3Client;
30-
}
31-
32-
export async function putObjectToS3(bucket: string, key: string, file: Buffer<ArrayBuffer>, s3Client?: S3Client) {
33-
s3Client ??= getS3Client();
20+
export async function putObjectToS3(bucket: string, key: string, file: Buffer<ArrayBuffer>, s3Client: S3Client) {
3421
await s3Client.send(
3522
new PutObjectCommand({
3623
Bucket: bucket,
@@ -40,8 +27,7 @@ export async function putObjectToS3(bucket: string, key: string, file: Buffer<Ar
4027
)
4128
}
4229

43-
export async function getObjectFromS3(bucket: string, key: string, s3Client?: S3Client) {
44-
s3Client ??= getS3Client();
30+
export async function getObjectFromS3(bucket: string, key: string, s3Client: S3Client) {
4531
const response = await s3Client.send(
4632
new GetObjectCommand({
4733
Bucket: bucket,
@@ -51,8 +37,7 @@ export async function getObjectFromS3(bucket: string, key: string, s3Client?: S3
5137
return response;
5238
}
5339

54-
export async function* listObjectsGenerator(bucket: string, prefix: string, options?: { maxKeys?: number, delimiter?: string, s3Client?: S3Client }) {
55-
const s3Client = options?.s3Client ?? getS3Client();
40+
export async function* listObjectsGenerator(bucket: string, prefix: string, s3Client: S3Client, options?: { maxKeys?: number, delimiter?: string }) {
5641
let continuationToken: string | undefined;
5742

5843
for (; ;) {
@@ -76,12 +61,11 @@ export async function* listObjectsGenerator(bucket: string, prefix: string, opti
7661
}
7762
}
7863

79-
export function getListObjectsFromS3(bucket: string, prefix: string, options?: { maxKeys?: number, delimiter?: string, s3Client?: S3Client }) {
80-
return Readable.from(listObjectsGenerator(bucket, prefix, options), { objectMode: true });
64+
export function getListObjectsFromS3(bucket: string, prefix: string, s3Client: S3Client, options?: { maxKeys?: number, delimiter?: string, }) {
65+
return Readable.from(listObjectsGenerator(bucket, prefix, s3Client, options), { objectMode: true });
8166
}
8267

83-
export async function s3FileExists(bucket: string, key: string, s3Client?: S3Client) {
84-
s3Client ??= getS3Client();
68+
export async function s3FileExists(bucket: string, key: string, s3Client: S3Client) {
8569
try {
8670
await s3Client.send(
8771
new HeadObjectCommand({ Bucket: bucket, Key: key })
@@ -92,16 +76,19 @@ export async function s3FileExists(bucket: string, key: string, s3Client?: S3Cli
9276
}
9377
}
9478

95-
export async function getHeadObjectFromS3(bucket: string, key: string, s3Client?: S3Client) {
96-
s3Client ??= getS3Client();
79+
export async function getHeadObjectFromS3(bucket: string, key: string, s3Client: S3Client) {
9780
return await s3Client.send(
9881
new HeadObjectCommand({ Bucket: bucket, Key: key })
9982
);
10083
}
10184

102-
// For tests
103-
export function resetS3Client() {
104-
s3Client = undefined;
85+
export async function getSHA1OfObject(bucket: string, key: string, s3Client: S3Client) {
86+
const obj = await getObjectFromS3(bucket, key, s3Client);
87+
const buffer = await obj.Body?.transformToByteArray()
88+
if (buffer === undefined) {
89+
throw new Error("Buffer was undefined");
90+
}
91+
return createHash("sha1").update(buffer).digest("hex");
10592
}
10693

10794
export function getEnvConfig() {
@@ -116,12 +103,3 @@ export function getEnvConfig() {
116103
}
117104
return { endpoint: process.env.S3_ENDPOINT, credentials: { accessKeyId: process.env.S3_KEY_ID, secretAccessKey: process.env.S3_ACCESS_KEY } };
118105
}
119-
120-
export async function getSHA1OfObject(bucket: string, key: string, s3Client?: S3Client) {
121-
const obj = await getObjectFromS3(bucket, key, s3Client);
122-
const buffer = await obj.Body?.transformToByteArray()
123-
if (buffer === undefined) {
124-
throw new Error("Buffer was undefined");
125-
}
126-
return createHash("sha1").update(buffer).digest("hex");
127-
}

test/index.test.ts

Lines changed: 18 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
getS3Client,
33
putObjectToS3,
44
getObjectFromS3,
5-
resetS3Client,
65
getListObjectsFromS3,
76
s3FileExists,
87
getHeadObjectFromS3,
@@ -13,48 +12,30 @@ import { S3Client, type _Object, type S3ClientConfig } from "@aws-sdk/client-s3"
1312
import { createS3Client } from "mock-aws-s3-v3";
1413
import fs from "fs";
1514
import { finished } from "stream/promises";
16-
import { describe, it, expect, beforeEach, afterAll } from "vitest";
15+
import { describe, it, expect, afterAll } from "vitest";
1716
import { createHash } from "crypto";
1817

19-
describe("getS3Client(config?)", () => {
20-
it("Should fail because config is undefined and the client is not set", () => {
21-
expect(() => getS3Client()).toThrow();
22-
});
18+
const config = {
19+
endpoint: "http://0.0.0.0:9000",
20+
credentials: {
21+
accessKeyId: "dev",
22+
secretAccessKey: "devpasswd",
23+
},
24+
};
2325

26+
describe("getS3Client(config)", () => {
2427
it("Should return an instance of an S3Client", () => {
25-
const config = {
26-
endpoint: "http://0.0.0.0:9000",
27-
credentials: {
28-
accessKeyId: "dev",
29-
secretAccessKey: "devpasswd",
30-
},
31-
};
32-
3328
expect(getS3Client(config) instanceof S3Client).toBe(true);
3429
});
35-
36-
it("Should return an instance of the S3Client even with undefined config", () => {
37-
expect(getS3Client() instanceof S3Client).toBe(true);
38-
});
3930
});
4031

41-
describe("putFileToS3(bucket, key, file, s3Client?)", () => {
42-
beforeEach(resetS3Client);
43-
32+
describe("putFileToS3(bucket, key, file, s3Client)", () => {
4433
afterAll(() => {
4534
fs.rm("test/s3_mock/dev/put_test", { recursive: true }, (err) => {
4635
if (err != null) console.error(err);
4736
});
4837
});
4938

50-
it("Should fail because s3Client is not set", async () => {
51-
const file = fs.readFileSync("test/test.xml");
52-
53-
await expect(
54-
putObjectToS3("dev", "put_test/test.xml", file),
55-
).rejects.toThrow();
56-
});
57-
5839
const mockClient = createS3Client({
5940
localDirectory: "./test/s3_mock",
6041
bucket: "dev",
@@ -69,14 +50,7 @@ describe("putFileToS3(bucket, key, file, s3Client?)", () => {
6950
});
7051
});
7152

72-
describe("getFileFromS3(bucket, key, s3Client?)", () => {
73-
beforeEach(resetS3Client);
74-
75-
it("Should fail because s3Client is not set", async () => {
76-
await expect(
77-
getObjectFromS3("dev", "get_test/test.xml"),
78-
).rejects.toThrow();
79-
});
53+
describe("getFileFromS3(bucket, key, s3Client)", () => {
8054

8155
it("Should get the file from S3 (test/mock) successfully", async () => {
8256
const mockClient = createS3Client({
@@ -93,8 +67,7 @@ describe("getFileFromS3(bucket, key, s3Client?)", () => {
9367
});
9468
});
9569

96-
describe("getListObjectsFromS3(bucket, prefix, s3Client?)", () => {
97-
beforeEach(resetS3Client);
70+
describe("getListObjectsFromS3(bucket, prefix, s3Client)", () => {
9871

9972
it("Should get the list of files from S3 (50 subfolders with 1 XML file and 1 PDF file each))", async () => {
10073
const mockClient = createS3Client({
@@ -104,8 +77,8 @@ describe("getListObjectsFromS3(bucket, prefix, s3Client?)", () => {
10477

10578
const streamNoMaxKeys = getListObjectsFromS3(
10679
"dev",
107-
"get_list_object_test",
108-
{ delimiter: "arbitrary delimiter", s3Client: mockClient },
80+
"get_list_object_test", mockClient,
81+
{ delimiter: "arbitrary delimiter" },
10982
);
11083

11184
const objectsNoMaxKeys: _Object[] = [];
@@ -118,10 +91,10 @@ describe("getListObjectsFromS3(bucket, prefix, s3Client?)", () => {
11891
const streamMaxKeys = getListObjectsFromS3(
11992
"dev",
12093
"get_list_object_test",
94+
mockClient,
12195
{
12296
delimiter: "arbitrary delimiter",
12397
maxKeys: 2,
124-
s3Client: mockClient,
12598
},
12699
);
127100

@@ -151,7 +124,7 @@ describe("getListObjectsFromS3(bucket, prefix, s3Client?)", () => {
151124
});
152125
});
153126

154-
describe("s3FileExists(bucket, key)", () => {
127+
describe("s3FileExists(bucket, key, s3Client)", () => {
155128
const mockClient = createS3Client({
156129
localDirectory: "./test/s3_mock",
157130
bucket: "dev",
@@ -179,7 +152,7 @@ describe("s3FileExists(bucket, key)", () => {
179152
});
180153
});
181154

182-
describe("getHeadObjectFromS3(bucket, key, s3Client?)", () => {
155+
describe("getHeadObjectFromS3(bucket, key, s3Client)", () => {
183156
const mockClient = createS3Client({
184157
localDirectory: "./test/s3_mock",
185158
bucket: "dev",
@@ -232,14 +205,7 @@ describe("getEnvConfig()", () => {
232205
})
233206
})
234207

235-
describe("getSHA1OfObject(bucket, key, s3Client?)", () => {
236-
beforeEach(resetS3Client);
237-
238-
it("Should fail because s3Client is not set", async () => {
239-
await expect(
240-
getSHA1OfObject("dev", "get_test/test.xml"),
241-
).rejects.toThrow();
242-
});
208+
describe("getSHA1OfObject(bucket, key, s3Client)", () => {
243209

244210
it("Should return the SHA1 of an existing object", async () => {
245211
const mockClient = createS3Client({

0 commit comments

Comments
 (0)