Skip to content

Commit a73de9f

Browse files
committed
new mimeType prop for objects.put
1 parent 0d82d42 commit a73de9f

File tree

17 files changed

+206
-70
lines changed

17 files changed

+206
-70
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@squarecloud/blob": minor
3+
---
4+
5+
New `mimeType` prop for `objects.put` method, required if file is a Buffer

.changeset/ninety-tips-collect.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,22 @@ const objects = await blob.objects.list()
4848

4949
```ts
5050
const blobObject = await blob.objects.put({
51-
file: "path/to/file.png", // Absolute path to your file, Buffer or Blob
52-
name: "my_image.png" // File name with extension
51+
file: "path/to/file.png", // Absolute path to your file or Buffer
52+
name: "my_image", // File name without extension
53+
})
54+
55+
console.log(blobObject.url)
56+
```
57+
58+
#### Advanced usage with Buffer
59+
60+
```ts
61+
import { MimeTypes } from "@squarecloud/blob"
62+
63+
const blobObject = await blob.objects.put({
64+
file: Buffer.from("content"),
65+
name: "my_image",
66+
mimeType: MimeTypes.IMAGE_JPEG, // Also accepts an string "image/jpeg"
5367
})
5468

5569
console.log(blobObject.url)

src/managers/objects.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { readFile } from "fs/promises";
21
import type { SquareCloudBlob } from "..";
3-
import { assertListObjectsResponse } from "../assertions/list";
4-
import { assertPutObjectResponse } from "../assertions/put";
5-
import { putObjectPayloadSchema } from "../schemas/put";
62
import { SquareCloudBlobError } from "../structures/error";
73
import type { ListObjectsResponse } from "../types/list";
84
import type { PutObjectResponse, PutObjectType } from "../types/put";
5+
import { getMimeTypeFromExtension } from "../utils/mimetype";
6+
import { parsePathLike } from "../utils/pathlike";
7+
import { assertListObjectsResponse } from "../validation/assertions/list";
8+
import { assertPutObjectResponse } from "../validation/assertions/put";
9+
import { putObjectPayloadSchema } from "../validation/schemas/put";
910

1011
export class BlobObjectsManager {
1112
constructor(private readonly client: SquareCloudBlob) {}
@@ -37,14 +38,22 @@ export class BlobObjectsManager {
3738
*/
3839
async put(object: PutObjectType) {
3940
const payload = putObjectPayloadSchema.parse(object);
40-
const file = await this.parseFile(payload.file);
41+
const file = await parsePathLike(payload.file);
42+
const mimeType =
43+
typeof object.file === "string"
44+
? getMimeTypeFromExtension(object.file.split(".")[1])
45+
: object.mimeType;
4146

4247
const formData = new FormData();
43-
formData.append("file", file instanceof Blob ? file : new Blob([file]));
48+
formData.append("file", new Blob([file], { type: mimeType }));
4449

4550
const { response } = await this.client.api.request<PutObjectResponse>(
4651
"put",
47-
{ method: "PUT", body: formData, params: payload.params },
52+
{
53+
method: "PUT",
54+
body: formData,
55+
params: payload.params,
56+
},
4857
);
4958

5059
return assertPutObjectResponse(response);
@@ -57,7 +66,7 @@ export class BlobObjectsManager {
5766
*
5867
* @example
5968
* ```js
60-
* await blob.objects.delete("ID/prefix/name1_xxx-xxx.zip", "ID/prefix/name_xxx-xxx-xxx.png");
69+
* await blob.objects.delete("ID/prefix/name1_xxx-xxx.mp4", "ID/prefix/name_xxx-xxx-xxx.png");
6170
* ```
6271
*/
6372
async delete(...objects: string[] | string[][]) {
@@ -71,20 +80,11 @@ export class BlobObjectsManager {
7180
return response.status === "success";
7281
}
7382

74-
private async parseFile(file: string | Buffer | Blob) {
75-
let result: Buffer | Blob | undefined;
76-
77-
if (typeof file === "string") {
78-
result = await readFile(file).catch(() => undefined);
79-
}
80-
81-
if (!result) {
82-
throw new SquareCloudBlobError("INVALID_FILE", "File not found");
83-
}
84-
85-
return result;
86-
}
87-
83+
/**
84+
* Parses the object URL to extract id, prefix, and name.
85+
*
86+
* @param url - The object URL to parse.
87+
*/
8888
parseObjectUrl(url: string) {
8989
const pattern =
9090
/^https:\/\/public-blob\.squarecloud\.dev\/([^\/]+)\/([^\/]+\/)?([^_]+)_[\w-]+\.\w+$/;

src/schemas/put.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/structures/error.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ export class SquareCloudBlobError extends Error {
44

55
this.name = SquareCloudBlobError.name;
66
this.message = this.getMessage(code);
7-
8-
Error.captureStackTrace(this, SquareCloudBlobError);
97
}
108

119
private getMessage(rawCode: string) {

src/types/list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import type { z } from "zod";
2-
import type { listObjectsResponseSchema } from "../schemas/list";
2+
import type { listObjectsResponseSchema } from "../validation/schemas/list";
33

44
export type ListObjectsResponse = z.infer<typeof listObjectsResponseSchema>;

src/types/put.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type { z } from "zod";
2-
import type { putObjectResponseSchema, putObjectSchema } from "../schemas/put";
2+
import type {
3+
putObjectResponseSchema,
4+
putObjectSchema,
5+
} from "../validation/schemas/put";
36

47
export type PutObjectType = z.infer<typeof putObjectSchema>;
58
export type PutObjectResponse = z.infer<typeof putObjectResponseSchema>;

src/utils/mimetype.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
const mimeTypesWithExtension = {
2+
"video/mp4": ["mp4"],
3+
"video/mpeg": ["mpeg"],
4+
"video/webm": ["webm"],
5+
"video/x-flv": ["flv"],
6+
"video/x-m4v": ["m4v"],
7+
"image/jpeg": ["jpg", "jpeg"],
8+
"image/png": ["png"],
9+
"image/apng": ["apng"],
10+
"image/tiff": ["tiff"],
11+
"image/gif": ["gif"],
12+
"image/webp": ["webp"],
13+
"image/bmp": ["bmp"],
14+
"image/svg+xml": ["svg"],
15+
"image/x-icon": ["ico"],
16+
"image/ico": ["ico"],
17+
"image/cur": ["cur"],
18+
"image/heic": ["heic"],
19+
"image/heif": ["heif"],
20+
"audio/wav": ["wav"],
21+
"audio/ogg": ["ogg"],
22+
"audio/opus": ["opus"],
23+
"audio/mp4": ["mp4"],
24+
"audio/mpeg": ["mp3"],
25+
"audio/aac": ["aac"],
26+
"text/plain": ["txt"],
27+
"text/html": ["html"],
28+
"text/css": ["css"],
29+
"text/csv": ["csv"],
30+
"text/x-sql": ["sql"],
31+
"application/xml": ["xml"],
32+
"application/sql": ["sql"],
33+
"application/x-sql": ["sql"],
34+
"application/x-sqlite3": ["sqlite3"],
35+
"application/x-pkcs12": ["pfx"],
36+
"application/pdf": ["pdf"],
37+
"application/json": ["json"],
38+
"application/javascript": ["js"],
39+
};
40+
41+
export enum MimeTypes {
42+
VIDEO_MP4 = "video/mp4",
43+
VIDEO_MPEG = "video/mpeg",
44+
VIDEO_WEBM = "video/webm",
45+
VIDEO_X_FLV = "video/x-flv",
46+
VIDEO_X_M4V = "video/x-m4v",
47+
IMAGE_JPEG = "image/jpeg",
48+
IMAGE_PNG = "image/png",
49+
IMAGE_APNG = "image/apng",
50+
IMAGE_TIFF = "image/tiff",
51+
IMAGE_GIF = "image/gif",
52+
IMAGE_WEBP = "image/webp",
53+
IMAGE_BMP = "image/bmp",
54+
IMAGE_SVG = "image/svg+xml",
55+
IMAGE_X_ICON = "image/x-icon",
56+
IMAGE_ICO = "image/ico",
57+
IMAGE_CUR = "image/cur",
58+
IMAGE_HEIC = "image/heic",
59+
IMAGE_HEIF = "image/heif",
60+
AUDIO_WAV = "audio/wav",
61+
AUDIO_OGG = "audio/ogg",
62+
AUDIO_OPUS = "audio/opus",
63+
AUDIO_MP4 = "audio/mp4",
64+
AUDIO_MPEG = "audio/mpeg",
65+
AUDIO_AAC = "audio/aac",
66+
TEXT_PLAIN = "text/plain",
67+
TEXT_HTML = "text/html",
68+
TEXT_CSS = "text/css",
69+
TEXT_CSV = "text/csv",
70+
TEXT_X_SQL = "text/x-sql",
71+
APPLICATION_XML = "application/xml",
72+
APPLICATION_SQL = "application/sql",
73+
APPLICATION_X_SQL = "application/x-sql",
74+
APPLICATION_X_SQLITE3 = "application/x-sqlite3",
75+
APPLICATION_X_PKCS12 = "application/x-pkcs12",
76+
APPLICATION_PDF = "application/pdf",
77+
APPLICATION_JSON = "application/json",
78+
APPLICATION_JAVASCRIPT = "application/javascript",
79+
}
80+
81+
export const mimeTypes = Object.keys(mimeTypesWithExtension) as [
82+
MimeType,
83+
...MimeType[],
84+
];
85+
86+
export type MimeType = keyof typeof mimeTypesWithExtension;
87+
88+
export function getMimeTypeFromExtension(extension: string): MimeType {
89+
const entries = Object.entries(mimeTypesWithExtension);
90+
const mimeType = entries.find(([, extensions]) =>
91+
extensions.includes(extension),
92+
)?.[0];
93+
94+
return (mimeType as MimeType) || "text/plain";
95+
}

src/utils/pathlike.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { readFile } from "fs/promises";
2+
import { SquareCloudBlobError } from "../structures/error";
3+
4+
export async function parsePathLike(
5+
pathLike: string | Buffer,
6+
): Promise<Buffer> {
7+
if (typeof pathLike === "string") {
8+
const fileBuffer = await readFile(pathLike).catch(() => undefined);
9+
10+
if (!fileBuffer) {
11+
throw new SquareCloudBlobError("INVALID_FILE", "File not found");
12+
}
13+
14+
return fileBuffer;
15+
}
16+
17+
return pathLike;
18+
}

0 commit comments

Comments
 (0)