first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
import {UploadStrategy, UploadStrategyConfig} from './upload-strategy';
import {UploadedFile} from '../../uploaded-file';
import axios, {AxiosProgressEvent} from 'axios';
import {FileEntry} from '../../file-entry';
import {getAxiosErrorMessage} from '@common/utils/http/get-axios-error-message';
import {apiClient} from '@common/http/query-client';
interface PresignedRequest {
url: string;
key: string;
acl: string;
}
export class S3Upload implements UploadStrategy {
private abortController: AbortController;
private presignedRequest?: PresignedRequest;
constructor(
private file: UploadedFile,
private config: UploadStrategyConfig
) {
this.abortController = new AbortController();
}
async start() {
this.presignedRequest = await this.presignPostUrl();
if (!this.presignedRequest) return;
const result = await this.uploadFileToS3();
if (result !== 'uploaded') return;
const response = await this.createFileEntry();
if (response?.fileEntry) {
this.config.onSuccess?.(response.fileEntry, this.file);
} else if (!this.abortController.signal) {
this.config.onError?.(null, this.file);
}
}
abort() {
this.abortController.abort();
return Promise.resolve();
}
private presignPostUrl(): Promise<PresignedRequest> {
return apiClient
.post(
's3/simple/presign',
{
filename: this.file.name,
mime: this.file.mime,
disk: this.config.metadata?.disk,
size: this.file.size,
extension: this.file.extension,
...this.config.metadata,
},
{signal: this.abortController.signal}
)
.then(r => r.data)
.catch(err => {
if (err.code !== 'ERR_CANCELED') {
this.config.onError?.(getAxiosErrorMessage(err), this.file);
}
});
}
private uploadFileToS3() {
const {url, acl} = this.presignedRequest!;
return axios
.put(url, this.file.native, {
signal: this.abortController.signal,
withCredentials: false,
headers: {
'Content-Type': this.file.mime,
'x-amz-acl': acl,
},
onUploadProgress: (e: AxiosProgressEvent) => {
if (e.event.lengthComputable) {
this.config.onProgress?.({
bytesUploaded: e.loaded,
bytesTotal: e.total || 0,
});
}
},
})
.then(() => 'uploaded')
.catch(err => {
if (err.code !== 'ERR_CANCELED') {
this.config.onError?.(getAxiosErrorMessage(err), this.file);
}
});
}
private async createFileEntry() {
return await apiClient
.post('s3/entries', {
...this.config.metadata,
clientMime: this.file.mime,
clientName: this.file.name,
filename: this.presignedRequest!.key.split('/').pop(),
size: this.file.size,
clientExtension: this.file.extension,
})
.then(r => {
return r.data as {fileEntry: FileEntry};
})
.catch(err => {
if (err.code !== 'ERR_CANCELED') {
this.config.onError?.(getAxiosErrorMessage(err), this.file);
}
});
}
static async create(
file: UploadedFile,
config: UploadStrategyConfig
): Promise<S3Upload> {
return new S3Upload(file, config);
}
}