Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump @aws-sdk/lib-storage from 3.100.0 to 3.616.0 #5126

Merged
merged 19 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class EtherpadClientAdapter {
const response = await this.tryGetPadsOfAuthor(authorId);
const pads = this.handleEtherpadResponse<ListPadsUsingGET200Response>(response, { authorId });

if (!TypeGuard.isObject(pads)) {
if (!TypeGuard.isDefinedObject(pads)) {
throw new InternalServerErrorException('Etherpad listPadsOfAuthor response is not an object');
}

Expand Down Expand Up @@ -280,7 +280,7 @@ export class EtherpadClientAdapter {
const response = await this.tryGetAuthorsOfPad(padId);
const authors = this.handleEtherpadResponse<ListAuthorsOfPadUsingGET200Response>(response, { padId });

if (!TypeGuard.isObject(authors)) {
if (!TypeGuard.isDefinedObject(authors)) {
throw new InternalServerErrorException('Etherpad listAuthorsOfPad response is not an object');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class EtherpadResponseMapper {

static mapEtherpadSessionsToSessions(etherpadSessions: unknown): Session[] {
try {
const isObject = TypeGuard.isObject(etherpadSessions);
const isObject = TypeGuard.isDefinedObject(etherpadSessions);
if (!isObject) return [];

const sessions = Object.entries(etherpadSessions)
Expand All @@ -83,7 +83,7 @@ export class EtherpadResponseMapper {

static mapEtherpadSessionToSession([etherpadId, etherpadSession]: [string, unknown | undefined]): Session {
if (
!TypeGuard.isObject(etherpadSession) ||
!TypeGuard.isDefinedObject(etherpadSession) ||
!('groupID' in etherpadSession) ||
!('authorID' in etherpadSession) ||
!('validUntil' in etherpadSession)
Expand Down
32 changes: 10 additions & 22 deletions apps/server/src/infra/s3-client/s3-client.adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ describe('S3ClientAdapter', () => {
S3ClientAdapter,
{
provide: S3_CLIENT,
useValue: createMock<S3Client>(),
useValue: createMock<S3Client>({
config: {
endpoint: () => {
return { protocol: '', hostname: '' };
},
},
}),
},
{
provide: S3_CONFIG,
Expand All @@ -52,7 +58,7 @@ describe('S3ClientAdapter', () => {
}).compile();

service = module.get(S3ClientAdapter);
client = module.get('S3_Client');
client = module.get(S3_CLIENT);
});

afterAll(async () => {
Expand Down Expand Up @@ -202,27 +208,15 @@ describe('S3ClientAdapter', () => {
const { file } = createFile();
const { pathToFile } = createParameter();

// @ts-expect-error EndpointMock
client.config.endpoint = () => {
return { protocol: '' };
};

const restoreMocks = () => {
// Set of undefined works as mock restore
client.config.endpoint = undefined;
};

return { file, pathToFile, restoreMocks };
return { file, pathToFile };
};

it('should return data', async () => {
const { file, pathToFile, restoreMocks } = setup();
const { file, pathToFile } = setup();

const result = await service.create(pathToFile, file);

expect(result).toBeDefined();

restoreMocks();
});
});

Expand All @@ -235,17 +229,11 @@ describe('S3ClientAdapter', () => {
const uploadDoneMock = jest.spyOn(Upload.prototype, 'done').mockRejectedValueOnce(error);
const createBucketMock = jest.spyOn(service, 'createBucket').mockResolvedValueOnce();
const createSpy = jest.spyOn(service, 'create');
// @ts-expect-error EndpointMock
client.config.endpoint = () => {
return { protocol: '' };
};

const restoreMocks = () => {
uploadDoneMock.mockRestore();
createBucketMock.mockRestore();
createSpy.mockRestore();
// Set of undefined works as mock restore
client.config.endpoint = undefined;
};

return { file, pathToFile, error, createSpy, restoreMocks };
Expand Down
39 changes: 20 additions & 19 deletions apps/server/src/infra/s3-client/s3-client.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import {
CopyObjectCommand,
CopyObjectCommandOutput,
CreateBucketCommand,
DeleteObjectCommandOutput,
DeleteObjectsCommand,
GetObjectCommand,
HeadObjectCommand,
HeadObjectCommandOutput,
ListObjectsV2Command,
PutObjectCommandInput,
S3Client,
ServiceOutputTypes,
} from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import { Inject, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
import { TypeGuard } from '@shared/common';
import { ErrorUtils } from '@src/core/error/utils';
import { LegacyLogger } from '@src/core/logger';
import { Readable } from 'stream';
Expand All @@ -31,14 +34,14 @@ export class S3ClientAdapter {
}

// is public but only used internally
public async createBucket() {
public async createBucket(): Promise<void> {
try {
this.logger.debug({ action: 'create bucket', params: { bucket: this.config.bucket } });

const req = new CreateBucketCommand({ Bucket: this.config.bucket });
await this.client.send(req);
} catch (err) {
if (err instanceof Error) {
if (TypeGuard.isError(err)) {
this.logger.error(`${err.message} "${this.config.bucket}"`);
}
throw new InternalServerErrorException(
Expand Down Expand Up @@ -70,9 +73,8 @@ export class S3ClientAdapter {
contentRange: data.ContentRange,
etag: data.ETag,
};
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (err?.Code === 'NoSuchKey') {
} catch (err: unknown) {
if (TypeGuard.getValueFromObjectKey(err, 'Code') === 'NoSuchKey') {
this.logger.warn(`Could not get file with id ${path}`);
throw new NotFoundException('NoSuchKey', ErrorUtils.createHttpExceptionOptions(err));
} else {
Expand All @@ -85,22 +87,23 @@ export class S3ClientAdapter {
try {
this.logger.debug({ action: 'create', params: { path, bucket: this.config.bucket } });

const req = {
const req: PutObjectCommandInput = {
Body: file.data,
Bucket: this.config.bucket,
Key: path,
ContentType: file.mimeType,
};

const upload = new Upload({
client: this.client,
params: req,
});

const commandOutput = await upload.done();

return commandOutput;
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (err?.Code === 'NoSuchBucket') {
} catch (err: unknown) {
if (TypeGuard.getValueFromObjectKey(err, 'Code') === 'NoSuchBucket') {
await this.createBucket();

return await this.create(path, file);
Expand All @@ -123,10 +126,10 @@ export class S3ClientAdapter {
await this.delete(paths);

return result;
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (err?.cause?.name === 'NoSuchKey') {
} catch (err: unknown) {
if (TypeGuard.getValueFromDeepObjectKey(err, ['cause', 'name']) === 'NoSuchKey') {
this.logger.warn(`could not find one of the files for deletion with ids ${paths.join(',')}`);

return [];
}
throw new InternalServerErrorException('S3ClientAdapter:delete', ErrorUtils.createHttpExceptionOptions(err));
Expand Down Expand Up @@ -154,7 +157,7 @@ export class S3ClientAdapter {
}
}

public async copy(paths: CopyFiles[]) {
public async copy(paths: CopyFiles[]): Promise<CopyObjectCommandOutput[]> {
try {
this.logger.debug({ action: 'copy', params: { paths, bucket: this.config.bucket } });

Expand All @@ -178,7 +181,7 @@ export class S3ClientAdapter {
}
}

public async delete(paths: string[]) {
public async delete(paths: string[]): Promise<DeleteObjectCommandOutput> {
try {
this.logger.debug({ action: 'delete', params: { paths, bucket: this.config.bucket } });

Expand Down Expand Up @@ -253,16 +256,15 @@ export class S3ClientAdapter {

return headResponse;
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (err.message && err.message === 'NoSuchKey') {
if (TypeGuard.getValueFromObjectKey(err, 'message') === 'NoSuchKey') {
this.logger.warn(`could not find the file for head with id ${path}`);
throw new NotFoundException(null, ErrorUtils.createHttpExceptionOptions(err, 'NoSuchKey'));
}
throw new InternalServerErrorException(null, ErrorUtils.createHttpExceptionOptions(err, 'S3ClientAdapter:head'));
}
}

public async deleteDirectory(path: string) {
public async deleteDirectory(path: string): Promise<void> {
try {
this.logger.debug({ action: 'deleteDirectory', params: { path, bucket: this.config.bucket } });

Expand All @@ -289,10 +291,9 @@ export class S3ClientAdapter {
}

/* istanbul ignore next */
private checkStreamResponsive(stream: Readable, context: string) {
private checkStreamResponsive(stream: Readable, context: string): void {
let timer: NodeJS.Timeout;
const refreshTimeout = () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
this.logger.log(`Stream unresponsive: S3 object key ${context}`);
Expand Down
Loading
Loading