mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
Updated `MediaApi` to include improved generic typing for upload methods, ensuring type safety and consistency. Refactored example configuration logic in development environment setup for better modularity and maintainability.
170 lines
4.8 KiB
TypeScript
170 lines
4.8 KiB
TypeScript
import type { FileListObject } from "media/storage/Storage";
|
|
import {
|
|
type BaseModuleApiOptions,
|
|
type FetchPromise,
|
|
type ResponseObject,
|
|
ModuleApi,
|
|
type PrimaryFieldType,
|
|
type TInput,
|
|
} from "modules/ModuleApi";
|
|
import type { ApiFetcher } from "Api";
|
|
import type { DB, FileUploadedEventData } from "bknd";
|
|
|
|
export type MediaApiOptions = BaseModuleApiOptions & {
|
|
upload_fetcher: ApiFetcher;
|
|
init?: RequestInit;
|
|
};
|
|
|
|
export class MediaApi extends ModuleApi<MediaApiOptions> {
|
|
protected override getDefaultOptions(): Partial<MediaApiOptions> {
|
|
return {
|
|
basepath: "/api/media",
|
|
upload_fetcher: fetch,
|
|
init: {},
|
|
};
|
|
}
|
|
|
|
listFiles() {
|
|
return this.get<FileListObject[]>(["files"]);
|
|
}
|
|
|
|
getFile(filename: string) {
|
|
return this.get<ReadableStream<Uint8Array>>(["file", filename], undefined, {
|
|
headers: {
|
|
Accept: "*/*",
|
|
},
|
|
});
|
|
}
|
|
|
|
async getFileStream(filename: string): Promise<ReadableStream<Uint8Array>> {
|
|
const { res } = await this.getFile(filename);
|
|
if (!res.ok || !res.body) {
|
|
throw new Error("Failed to fetch file");
|
|
}
|
|
return res.body;
|
|
}
|
|
|
|
async download(filename: string): Promise<File> {
|
|
const { res } = await this.getFile(filename);
|
|
if (!res.ok || !res.body) {
|
|
throw new Error("Failed to fetch file");
|
|
}
|
|
return (await res.blob()) as File;
|
|
}
|
|
|
|
getFileUploadUrl(file?: { path: string }): string {
|
|
if (!file) return this.getUrl("/upload");
|
|
return this.getUrl(`/upload/${file.path}`);
|
|
}
|
|
|
|
getEntityUploadUrl(entity: string, id: PrimaryFieldType, field: string) {
|
|
return this.getUrl(`/entity/${entity}/${id}/${field}`);
|
|
}
|
|
|
|
getUploadHeaders(): Headers {
|
|
if (this.options.token_transport === "header" && this.options.token) {
|
|
return new Headers({
|
|
Authorization: `Bearer ${this.options.token}`,
|
|
});
|
|
}
|
|
return new Headers();
|
|
}
|
|
|
|
protected uploadFile<T extends FileUploadedEventData>(
|
|
body: File | Blob | ReadableStream | Buffer<ArrayBufferLike>,
|
|
opts?: {
|
|
filename?: string;
|
|
path?: TInput;
|
|
_init?: Omit<RequestInit, "body">;
|
|
},
|
|
): FetchPromise<ResponseObject<T>> {
|
|
const headers = {
|
|
"Content-Type": "application/octet-stream",
|
|
...(opts?._init?.headers || {}),
|
|
};
|
|
let name: string = opts?.filename || "";
|
|
try {
|
|
if (typeof (body as File).type !== "undefined") {
|
|
headers["Content-Type"] = (body as File).type;
|
|
}
|
|
if (!opts?.filename) {
|
|
name = (body as File).name;
|
|
}
|
|
} catch (e) {}
|
|
|
|
if (name && name.length > 0 && name.includes("/")) {
|
|
name = name.split("/").pop() || "";
|
|
}
|
|
|
|
const init = {
|
|
...this.options.init,
|
|
...(opts?._init || {}),
|
|
headers,
|
|
};
|
|
if (opts?.path) {
|
|
return this.post(opts.path, body, init);
|
|
}
|
|
|
|
if (!name || name.length === 0) {
|
|
throw new Error("Invalid filename");
|
|
}
|
|
|
|
return this.post<T>(opts?.path ?? ["upload", name], body, init);
|
|
}
|
|
|
|
async upload<T extends FileUploadedEventData>(
|
|
item: Request | Response | string | File | Blob | ReadableStream | Buffer<ArrayBufferLike>,
|
|
opts: {
|
|
filename?: string;
|
|
_init?: Omit<RequestInit, "body">;
|
|
path?: TInput;
|
|
fetcher?: ApiFetcher;
|
|
} = {},
|
|
) {
|
|
if (item instanceof Request || typeof item === "string") {
|
|
const fetcher = opts.fetcher ?? this.options.upload_fetcher;
|
|
const res = await fetcher(item);
|
|
if (!res.ok || !res.body) {
|
|
throw new Error("Failed to fetch file");
|
|
}
|
|
return this.uploadFile<T>(res.body, opts);
|
|
} else if (item instanceof Response) {
|
|
if (!item.body) {
|
|
throw new Error("Invalid response");
|
|
}
|
|
return this.uploadFile<T>(item.body, {
|
|
...(opts ?? {}),
|
|
_init: {
|
|
...(opts._init ?? {}),
|
|
headers: {
|
|
...(opts._init?.headers ?? {}),
|
|
"Content-Type": item.headers.get("Content-Type") || "application/octet-stream",
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
return this.uploadFile<T>(item, opts);
|
|
}
|
|
|
|
async uploadToEntity(
|
|
entity: string,
|
|
id: PrimaryFieldType,
|
|
field: string,
|
|
item: Request | Response | string | File | ReadableStream | Buffer<ArrayBufferLike>,
|
|
opts?: {
|
|
_init?: Omit<RequestInit, "body">;
|
|
fetcher?: typeof fetch;
|
|
},
|
|
): Promise<ResponseObject<FileUploadedEventData & { result: DB["media"] }>> {
|
|
return this.upload(item, {
|
|
...opts,
|
|
path: ["entity", entity, id, field],
|
|
});
|
|
}
|
|
|
|
deleteFile(filename: string) {
|
|
return this.delete(["file", filename]);
|
|
}
|
|
}
|