Merge pull request #80 from bknd-io/fix/api-and-media

fix/api-and-media
This commit is contained in:
dswbx
2025-02-14 11:42:50 +01:00
committed by GitHub
21 changed files with 796 additions and 266 deletions

View File

@@ -13,12 +13,6 @@ export const cloudinaryAdapterConfig = Type.Object(
);
export type CloudinaryConfig = Static<typeof cloudinaryAdapterConfig>;
/*export type CloudinaryConfig = {
cloud_name: string;
api_key: string;
api_secret: string;
upload_preset?: string;
};*/
type CloudinaryObject = {
asset_id: string;
@@ -91,10 +85,8 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
}
async putObject(_key: string, body: FileBody) {
//console.log("_key", _key);
// remove extension, as it is added by cloudinary
const key = _key.replace(/\.[a-z0-9]{2,5}$/, "");
//console.log("key", key);
const formData = new FormData();
formData.append("file", body as any);
@@ -117,21 +109,12 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
body: formData
}
);
//console.log("putObject:cloudinary", formData);
if (!result.ok) {
/*console.log(
"failed to upload using cloudinary",
Object.fromEntries(formData.entries()),
result
);*/
return undefined;
}
//console.log("putObject:result", result);
const data = (await result.json()) as CloudinaryPutObjectResponse;
//console.log("putObject:result:json", data);
return {
name: data.public_id + "." + data.format,
@@ -154,7 +137,6 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
}
}
);
//console.log("result", result);
if (!result.ok) {
throw new Error("Failed to list objects");
@@ -179,10 +161,7 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
}
async objectExists(key: string): Promise<boolean> {
//console.log("--object exists?", key);
const result = await this.headObject(key);
//console.log("object exists", result);
return result.ok;
}
@@ -214,12 +193,10 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
const type = this.guessType(key) ?? "image";
const objectUrl = `https://res.cloudinary.com/${this.config.cloud_name}/${type}/upload/${key}`;
//console.log("objectUrl", objectUrl);
return objectUrl;
}
async getObject(key: string, headers: Headers): Promise<Response> {
//console.log("url", this.getObjectUrl(key));
const res = await fetch(this.getObjectUrl(key), {
method: "GET",
headers: pickHeaders(headers, ["range"])
@@ -237,14 +214,10 @@ export class StorageCloudinaryAdapter implements StorageAdapter {
const formData = new FormData();
formData.append("public_ids[]", key);
const result = await fetch(
`https://res.cloudinary.com/${this.config.cloud_name}/${type}/upload/`,
{
method: "DELETE",
body: formData
}
);
//console.log("deleteObject:result", result);
await fetch(`https://res.cloudinary.com/${this.config.cloud_name}/${type}/upload/`, {
method: "DELETE",
body: formData
});
}
toJSON(secrets?: boolean) {

View File

@@ -1,6 +1,12 @@
import { readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
import { type Static, Type, parse } from "core/utils";
import type { FileBody, FileListObject, FileMeta, StorageAdapter } from "../../Storage";
import { type Static, Type, isFile, parse } from "core/utils";
import type {
FileBody,
FileListObject,
FileMeta,
FileUploadPayload,
StorageAdapter
} from "../../Storage";
import { guess } from "../../mime-types-tiny";
export const localAdapterConfig = Type.Object(
@@ -43,8 +49,9 @@ export class StorageLocalAdapter implements StorageAdapter {
return fileStats;
}
private async computeEtag(content: BufferSource): Promise<string> {
const hashBuffer = await crypto.subtle.digest("SHA-256", content);
private async computeEtag(body: FileBody): Promise<string> {
const content = isFile(body) ? body : new Response(body);
const hashBuffer = await crypto.subtle.digest("SHA-256", await content.arrayBuffer());
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
@@ -52,17 +59,16 @@ export class StorageLocalAdapter implements StorageAdapter {
return `"${hashHex}"`;
}
async putObject(key: string, body: FileBody): Promise<string> {
async putObject(key: string, body: FileBody): Promise<string | FileUploadPayload> {
if (body === null) {
throw new Error("Body is empty");
}
// @todo: this is too hacky
const file = body as File;
const filePath = `${this.config.path}/${key}`;
await writeFile(filePath, file.stream());
return await this.computeEtag(await file.arrayBuffer());
const is_file = isFile(body);
await writeFile(filePath, is_file ? body.stream() : body);
return await this.computeEtag(body);
}
async deleteObject(key: string): Promise<void> {

View File

@@ -7,7 +7,7 @@ import type {
PutObjectRequest
} from "@aws-sdk/client-s3";
import { AwsClient, isDebug } from "core";
import { type Static, Type, parse, pickHeaders } from "core/utils";
import { type Static, Type, isFile, parse, pickHeaders } from "core/utils";
import { transform } from "lodash-es";
import type { FileBody, FileListObject, StorageAdapter } from "../Storage";
@@ -82,17 +82,14 @@ export class StorageS3Adapter extends AwsClient implements StorageAdapter {
};
const url = this.getUrl("", params);
//console.log("url", url);
const res = await this.fetchJson<{ ListBucketResult: ListObjectsV2Output }>(url, {
method: "GET"
});
//console.log("res", res);
// absolutely weird, but if only one object is there, it's an object, not an array
const { Contents } = res.ListBucketResult;
const objects = !Contents ? [] : Array.isArray(Contents) ? Contents : [Contents];
//console.log(JSON.stringify(res.ListBucketResult, null, 2), objects);
const transformed = transform(
objects,
(acc, obj) => {
@@ -107,28 +104,21 @@ export class StorageS3Adapter extends AwsClient implements StorageAdapter {
},
[] as FileListObject[]
);
//console.log(transformed);
return transformed;
}
async putObject(
key: string,
body: FileBody | null,
body: FileBody,
// @todo: params must be added as headers, skipping for now
params: Omit<PutObjectRequest, "Bucket" | "Key"> = {}
) {
const url = this.getUrl(key, {});
//console.log("url", url);
const res = await this.fetch(url, {
method: "PUT",
body
});
/*console.log("putObject:raw:res", {
ok: res.ok,
status: res.status,
statusText: res.statusText,
});*/
if (res.ok) {
// "df20fcb574dba1446cf5ec997940492b"