mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
183 lines
5.2 KiB
TypeScript
183 lines
5.2 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: BodyInit,
|
|
opts?: {
|
|
filename?: string;
|
|
path?: TInput;
|
|
_init?: Omit<RequestInit, "body">;
|
|
query?: Record<string, any>;
|
|
},
|
|
): 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.request<T>(opts.path, opts?.query, {
|
|
...init,
|
|
body,
|
|
method: "POST",
|
|
});
|
|
}
|
|
|
|
if (!name || name.length === 0) {
|
|
throw new Error("Invalid filename");
|
|
}
|
|
|
|
return this.request<T>(opts?.path ?? ["upload", name], opts?.query, {
|
|
...init,
|
|
body,
|
|
method: "POST",
|
|
});
|
|
}
|
|
|
|
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;
|
|
query?: Record<string, any>;
|
|
} = {},
|
|
) {
|
|
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 as BodyInit, 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;
|
|
overwrite?: boolean;
|
|
},
|
|
): Promise<ResponseObject<FileUploadedEventData & { result: DB["media"] }>> {
|
|
const query = opts?.overwrite !== undefined ? { overwrite: opts.overwrite } : undefined;
|
|
return this.upload(item, {
|
|
...opts,
|
|
path: ["entity", entity, id, field],
|
|
query,
|
|
});
|
|
}
|
|
|
|
deleteFile(filename: string) {
|
|
return this.delete(["file", filename]);
|
|
}
|
|
}
|