Skip to content

Commit d2df79e

Browse files
committed
create blob objects manager and put method
1 parent fc10ac4 commit d2df79e

File tree

7 files changed

+128
-0
lines changed

7 files changed

+128
-0
lines changed

.changeset/funny-melons-prove.md

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+
Add `BlobObjectsManager#put` method for creating blobs

.changeset/two-moose-exercise.md

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 blob objects manager for creating, deleting and listing blobs

src/assertions/put.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { putBlobObjectResponseSchema } from "../schemas/put";
2+
import type { PutBlobObjectResponse } from "../types/put";
3+
import { handleAPIObjectAssertion } from "./handlers";
4+
5+
export function assertPutBlobObjectResponse(
6+
value: unknown,
7+
): PutBlobObjectResponse {
8+
return handleAPIObjectAssertion({
9+
schema: putBlobObjectResponseSchema,
10+
code: "PUT_OBJECT",
11+
route: "/put",
12+
value,
13+
});
14+
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { APIManager } from "./managers/api";
2+
import { BlobObjectsManager } from "./managers/objects";
23

34
export class SquareCloudBlob {
45
public static apiInfo = {
@@ -7,6 +8,7 @@ export class SquareCloudBlob {
78
};
89

910
public readonly api: APIManager;
11+
public readonly objects = new BlobObjectsManager(this);
1012

1113
constructor(apiKey: string) {
1214
this.api = new APIManager(apiKey);

src/managers/objects.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { readFile } from "fs/promises";
2+
import type { SquareCloudBlob } from "..";
3+
import { assertPutBlobObjectResponse } from "../assertions/put";
4+
import { putBlobObjectPayloadSchema } from "../schemas/put";
5+
import { SquareCloudBlobError } from "../structures/error";
6+
import type { PutBlobObjectResponse, PutBlobObjectType } from "../types/put";
7+
8+
export class BlobObjectsManager {
9+
constructor(private readonly client: SquareCloudBlob) {}
10+
11+
async put(object: PutBlobObjectType) {
12+
const payload = putBlobObjectPayloadSchema.parse(object);
13+
const file = await this.parseFile(payload.file);
14+
15+
const formData = new FormData();
16+
formData.append("file", new Blob([file]));
17+
18+
const { response } = await this.client.api.request<PutBlobObjectResponse>(
19+
"blob/put",
20+
{
21+
method: "POST",
22+
body: formData,
23+
params: payload.params,
24+
},
25+
);
26+
27+
return assertPutBlobObjectResponse(response);
28+
}
29+
30+
private async parseFile(file: string | Buffer) {
31+
let result: Buffer | undefined;
32+
33+
if (typeof file === "string") {
34+
result = await readFile(file).catch(() => undefined);
35+
}
36+
37+
if (!result) {
38+
throw new SquareCloudBlobError("INVALID_FILE", "File not found");
39+
}
40+
41+
return result;
42+
}
43+
44+
parseObjectUrl(url: string) {
45+
const pattern =
46+
/^https:\/\/public-blob\.squarecloud\.dev\/([^\/]+)\/([^\/]+\/)?([^_]+)_[\w-]+\.\w+$/;
47+
const match = pattern.exec(url);
48+
49+
if (!match) {
50+
throw new SquareCloudBlobError(
51+
"INVALID_BLOB_URL",
52+
"Invalid blob object URL",
53+
);
54+
}
55+
56+
let [, id, prefix, name] = match;
57+
prefix = prefix ? prefix.slice(0, -1) : "";
58+
59+
return { id, prefix, name };
60+
}
61+
}

src/schemas/put.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { z } from "zod";
2+
import { nameLikeStringSchema } from "./common";
3+
4+
export const putBlobObjectSchema = z.object({
5+
/** A string representing the name for the file. */
6+
name: nameLikeStringSchema,
7+
/** Use absolute path or Buffer, can be a single file or compressed (zip) */
8+
file: z.string().or(z.instanceof(Buffer)),
9+
/** A string representing the prefix for the file. */
10+
prefix: nameLikeStringSchema.optional(),
11+
/** A number indicating the expiration period of the file, ranging from 1 to 365 days. */
12+
expire: z.number().min(1).max(365).optional(),
13+
/** Set to true if a security hash is required. */
14+
securityHash: z.boolean().optional(),
15+
/** Set to true if the file should be set for automatic download. */
16+
autoDownload: z.boolean().optional(),
17+
});
18+
19+
export const putBlobObjectPayloadSchema = putBlobObjectSchema.transform(
20+
({ file, securityHash, autoDownload, ...rest }) => ({
21+
file,
22+
params: {
23+
...rest,
24+
security_hash: securityHash,
25+
auto_download: autoDownload,
26+
},
27+
}),
28+
);
29+
30+
export const putBlobObjectResponseSchema = z.object({
31+
/** The URL of the uploaded file. (File distributed in Square Cloud CDN) */
32+
url: z.string(),
33+
});

src/types/put.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { z } from "zod";
2+
import type {
3+
putBlobObjectResponseSchema,
4+
putBlobObjectSchema,
5+
} from "../schemas/put";
6+
7+
export type PutBlobObjectType = z.infer<typeof putBlobObjectSchema>;
8+
export type PutBlobObjectResponse = z.infer<typeof putBlobObjectResponseSchema>;

0 commit comments

Comments
 (0)