logos-storage-js/src/data/browser-upload.ts
2025-03-28 09:13:01 +01:00

82 lines
2.1 KiB
TypeScript

import { CodexError } from "../errors/errors";
import type { SafeValue } from "../values/values";
import type { UploadStategy, UploadStategyOptions } from "./types";
export class BrowserUploadStategy implements UploadStategy {
private readonly file: Document | XMLHttpRequestBodyInit;
private readonly onProgress:
| ((loaded: number, total: number) => void)
| undefined;
private readonly metadata:
| { filename?: string; mimetype?: string }
| undefined;
private xhr: XMLHttpRequest | undefined;
constructor(
file: Document | XMLHttpRequestBodyInit,
onProgress?: (loaded: number, total: number) => void,
metadata?: { filename?: string; mimetype?: string }
) {
this.file = file;
this.onProgress = onProgress;
this.metadata = metadata;
}
upload(
url: string,
{ auth }: UploadStategyOptions
): Promise<SafeValue<string>> {
const xhr = new XMLHttpRequest();
this.xhr = xhr;
return new Promise<SafeValue<string>>((resolve) => {
xhr.upload.onprogress = (evt) => {
if (evt.lengthComputable) {
this.onProgress?.(evt.loaded, evt.total);
}
};
xhr.open("POST", url, true);
if (this.metadata?.filename) {
xhr.setRequestHeader(
"Content-Disposition",
'attachment; filename="' + this.metadata.filename + '"'
);
}
if (auth?.basic) {
xhr.setRequestHeader("Authorization", "Basic " + auth.basic);
}
if (this.metadata?.mimetype) {
xhr.setRequestHeader("Content-Type", this.metadata.mimetype);
}
xhr.send(this.file);
xhr.onload = function () {
if (xhr.status != 200) {
resolve({
error: true,
data: new CodexError(xhr.responseText, { code: xhr.status }),
});
} else {
resolve({ error: false, data: xhr.response });
}
};
xhr.onerror = function () {
resolve({
error: true,
data: new CodexError("Something went wrong during the file upload."),
});
};
});
}
abort(): void {
this.xhr?.abort();
}
}