@squarecloud/blob
Version:
Official Square Cloud Blob SDK for NodeJS
518 lines (498 loc) • 17.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
BlobObject: () => BlobObject,
MimeTypeUtil: () => MimeTypeUtil,
MimeTypes: () => MimeTypes,
SquareCloudBlob: () => SquareCloudBlob
});
module.exports = __toCommonJS(src_exports);
// src/structures/error.ts
var SquareCloudBlobError = class _SquareCloudBlobError extends Error {
constructor(code, message, cause) {
super(message, { cause });
this.name = _SquareCloudBlobError.name;
this.message = this.getMessage(code);
}
getMessage(rawCode) {
const code = rawCode.replaceAll("_", " ").toLowerCase().replace(/(^|\s)\S/g, (L) => L.toUpperCase());
const message = this.message ? `: ${this.message}` : "";
return `${code}${message}`;
}
};
// src/managers/api.ts
var APIManager = class {
constructor(apiKey) {
this.apiKey = apiKey;
__publicField(this, "baseUrl");
const { baseUrl, version } = SquareCloudBlob.apiInfo;
this.baseUrl = `${baseUrl}/${version}/`;
}
async request(path, options = {}) {
const { init, params } = this.parseOptions(options);
const url = new URL(`${path}?${params}`, this.baseUrl);
const response = await fetch(url, init);
const data = await response.json();
if (data.status === "error") {
throw new SquareCloudBlobError(data.code || "UNKNOWN_ERROR");
}
return data;
}
parseOptions(options) {
const paramsObject = options.params && Object.fromEntries(
Object.entries(options.params).filter(([, value]) => Boolean(value)).map(([key, value]) => [key, String(value)])
);
const params = new URLSearchParams(paramsObject);
const { params: _, headers, body, ...rest } = options;
const init = {
...rest,
headers: { ...headers || {}, Authorization: this.apiKey }
};
if (body) {
init.body = body instanceof FormData ? body : JSON.stringify(body);
}
return { init, params };
}
};
// src/utils/mimetype/mimetypes.ts
var mimeTypesWithExtension = {
"video/mp4": ["mp4"],
"video/mpeg": ["mpeg"],
"video/webm": ["webm"],
"video/x-flv": ["flv"],
"video/x-m4v": ["m4v"],
"image/jpeg": ["jpg", "jpeg"],
"image/png": ["png"],
"image/apng": ["apng"],
"image/tiff": ["tiff"],
"image/gif": ["gif"],
"image/webp": ["webp"],
"image/bmp": ["bmp"],
"image/svg+xml": ["svg"],
"image/x-icon": ["ico"],
"image/ico": ["ico"],
"image/cur": ["cur"],
"image/heic": ["heic"],
"image/heif": ["heif"],
"audio/wav": ["wav"],
"audio/ogg": ["ogg"],
"audio/opus": ["opus"],
"audio/mp4": ["mp4"],
"audio/mpeg": ["mp3"],
"audio/aac": ["aac"],
"text/plain": ["txt"],
"text/html": ["html"],
"text/css": ["css"],
"text/csv": ["csv"],
"text/x-sql": ["sql"],
"application/xml": ["xml"],
"application/sql": ["sql"],
"application/x-sql": ["sql"],
"application/x-sqlite3": ["sqlite3"],
"application/x-pkcs12": ["pfx"],
"application/pdf": ["pdf"],
"application/json": ["json"],
"application/javascript": ["js"]
};
var mimeTypes = Object.keys(mimeTypesWithExtension);
// src/utils/mimetype/enum.ts
var MimeTypes = /* @__PURE__ */ ((MimeTypes2) => {
MimeTypes2["VIDEO_MP4"] = "video/mp4";
MimeTypes2["VIDEO_MPEG"] = "video/mpeg";
MimeTypes2["VIDEO_WEBM"] = "video/webm";
MimeTypes2["VIDEO_X_FLV"] = "video/x-flv";
MimeTypes2["VIDEO_X_M4V"] = "video/x-m4v";
MimeTypes2["IMAGE_JPEG"] = "image/jpeg";
MimeTypes2["IMAGE_PNG"] = "image/png";
MimeTypes2["IMAGE_APNG"] = "image/apng";
MimeTypes2["IMAGE_TIFF"] = "image/tiff";
MimeTypes2["IMAGE_GIF"] = "image/gif";
MimeTypes2["IMAGE_WEBP"] = "image/webp";
MimeTypes2["IMAGE_BMP"] = "image/bmp";
MimeTypes2["IMAGE_SVG"] = "image/svg+xml";
MimeTypes2["IMAGE_X_ICON"] = "image/x-icon";
MimeTypes2["IMAGE_ICO"] = "image/ico";
MimeTypes2["IMAGE_CUR"] = "image/cur";
MimeTypes2["IMAGE_HEIC"] = "image/heic";
MimeTypes2["IMAGE_HEIF"] = "image/heif";
MimeTypes2["AUDIO_WAV"] = "audio/wav";
MimeTypes2["AUDIO_OGG"] = "audio/ogg";
MimeTypes2["AUDIO_OPUS"] = "audio/opus";
MimeTypes2["AUDIO_MP4"] = "audio/mp4";
MimeTypes2["AUDIO_MPEG"] = "audio/mpeg";
MimeTypes2["AUDIO_AAC"] = "audio/aac";
MimeTypes2["TEXT_PLAIN"] = "text/plain";
MimeTypes2["TEXT_HTML"] = "text/html";
MimeTypes2["TEXT_CSS"] = "text/css";
MimeTypes2["TEXT_CSV"] = "text/csv";
MimeTypes2["TEXT_X_SQL"] = "text/x-sql";
MimeTypes2["APPLICATION_XML"] = "application/xml";
MimeTypes2["APPLICATION_SQL"] = "application/sql";
MimeTypes2["APPLICATION_X_SQL"] = "application/x-sql";
MimeTypes2["APPLICATION_X_SQLITE3"] = "application/x-sqlite3";
MimeTypes2["APPLICATION_X_PKCS12"] = "application/x-pkcs12";
MimeTypes2["APPLICATION_PDF"] = "application/pdf";
MimeTypes2["APPLICATION_JSON"] = "application/json";
MimeTypes2["APPLICATION_JAVASCRIPT"] = "application/javascript";
return MimeTypes2;
})(MimeTypes || {});
// src/utils/mimetype/index.ts
var MimeTypeUtil = class {
/**
* Returns the corresponding MIME type for a given file extension.
*
* @param extension - The file extension to search for.
* @return The MIME type associated with the extension, or "text/plain" if not found.
*
* @example
* ```js
* MimeTypeUtil.fromExtension("jpeg") // "image/jpeg" | Supported
* MimeTypeUtil.fromExtension("json") // "application/json" | Supported
* MimeTypeUtil.fromExtension("potato") // "text/plain" | Unsupported, defaults to text/plain
* ```
*/
static fromExtension(extension) {
const entries = Object.entries(mimeTypesWithExtension);
const mimeType = entries.find(
([, extensions]) => extensions.includes(extension)
)?.[0];
return mimeType || "text/plain";
}
};
/** Supported mime types with their extensions */
__publicField(MimeTypeUtil, "mimeTypesWithExtension", mimeTypesWithExtension);
/** All supported mime types */
__publicField(MimeTypeUtil, "mimeTypes", mimeTypes);
// src/utils/object-url.ts
var objectUrlRegex = /^(?<url>https:\/\/public-blob\.squarecloud\.dev)?\/?(?<userId>\d+\/)(?<prefix>[\w\d-_]+\/)?(?<name>[\w\d_]+)-(?<hash>[\w\d]+)\.(?<extension>\w+)$/;
function parseObjectUrl(url) {
const match = url.match(objectUrlRegex);
if (!match?.groups) {
throw new SquareCloudBlobError("Invalid object URL");
}
const payload = {
userId: match.groups.userId.replace("/", ""),
prefix: match.groups.prefix?.replace("/", ""),
name: match.groups.name,
hash: match.groups.hash,
extension: match.groups.extension
};
return {
id: `${payload.userId}/${payload.prefix ? `${payload.prefix}/` : ""}${payload.name}-${payload.hash}.${payload.extension}`,
...payload
};
}
// src/structures/object.ts
var BlobObject = class {
constructor(data) {
/** The id of the object */
__publicField(this, "id");
/** The url to view or download the object */
__publicField(this, "url");
/** The name of the object */
__publicField(this, "name");
/** The prefix of the object (Optional) */
__publicField(this, "prefix");
/** The hash of the object */
__publicField(this, "hash");
/** The id of the user who created the object */
__publicField(this, "userId");
/** The file extension of the object */
__publicField(this, "extension");
/** The MIME type of the object */
__publicField(this, "mimeType");
/** The size of the object in bytes */
__publicField(this, "size");
/** The expiration date of the object (Only available using `objects.list`) */
__publicField(this, "expiresAt");
/** The creation date of the object (Only available using `objects.list`) */
__publicField(this, "createdAt");
const { id, name, prefix, hash, userId, extension } = parseObjectUrl(
data.idOrUrl
);
this.id = id;
this.url = `https://public-blob.squarecloud.dev/${id}`;
this.name = name;
this.prefix = prefix;
this.hash = hash;
this.userId = userId;
this.extension = extension;
this.mimeType = MimeTypeUtil.fromExtension(extension);
this.size = data.size;
this.expiresAt = data.expiresAt;
this.createdAt = data.createdAt;
}
};
// src/utils/path-like.ts
var import_promises = require("fs/promises");
async function parsePathLike(pathLike) {
if (typeof pathLike === "string") {
const fileBuffer = await (0, import_promises.readFile)(pathLike).catch(() => void 0);
if (!fileBuffer) {
throw new SquareCloudBlobError("INVALID_FILE", "File not found");
}
return fileBuffer;
}
return pathLike;
}
// src/validation/schemas/create.ts
var import_zod2 = require("zod");
// src/validation/schemas/common.ts
var import_zod = require("zod");
var stringSchema = import_zod.z.string();
var nameLikeSchema = import_zod.z.string().min(3).max(32).regex(/^[a-zA-Z0-9_]{3,32}$/, {
message: "Name must contain only letters, numbers and _"
});
// src/validation/schemas/create.ts
var createObjectSchema = import_zod2.z.object({
/** A string representing the name for the file. */
name: nameLikeSchema,
/** Use absolute path, Buffer or Blob */
file: import_zod2.z.string().or(import_zod2.z.instanceof(Buffer)),
/** A string representing the MIME type of the file. */
mimeType: import_zod2.z.enum(MimeTypeUtil.mimeTypes).optional(),
/** A string representing the prefix for the file. */
prefix: nameLikeSchema.optional(),
/** A number indicating the expiration period of the file, ranging from 1 to 365 days. */
expiresIn: import_zod2.z.number().min(1).max(365).optional(),
/** Set to true if a security hash is required. */
securityHash: import_zod2.z.boolean().optional(),
/** Set to true if the file should be set for automatic download. */
autoDownload: import_zod2.z.boolean().optional()
}).refine(({ file, mimeType }) => !(file instanceof Buffer && !mimeType), {
message: "mimeType is required if file is a Buffer",
path: ["mimeType"]
});
var createObjectPayloadSchema = createObjectSchema.transform(
({ file, securityHash, autoDownload, expiresIn, ...rest }) => ({
file,
mimeType: typeof file === "string" ? MimeTypeUtil.fromExtension(file.split(".")[1]) : void 0,
params: {
...rest,
expire: expiresIn,
security_hash: securityHash,
auto_download: autoDownload
}
})
);
var createObjectResponseSchema = import_zod2.z.object({
/** The id of the uploaded file. */
id: import_zod2.z.string(),
/** The name of the uploaded file. */
name: import_zod2.z.string(),
/** The prefix of the uploaded file. */
prefix: import_zod2.z.string().optional(),
/** The size of the uploaded file. */
size: import_zod2.z.number(),
/** The URL of the uploaded file. (File distributed in Square Cloud CDN) */
url: import_zod2.z.string()
});
// src/validation/assertions/handlers.ts
function handleAPIObjectAssertion({
schema,
value,
code
}) {
const name = code.toLowerCase().replaceAll("_", " ");
try {
return schema.parse(value);
} catch (err) {
const cause = err.errors?.map((err2) => ({
...err2,
path: err2.path.join(" > ")
}));
throw new SquareCloudBlobError(
`INVALID_API_${code}`,
`Invalid ${name} object received from API`,
{ cause }
);
}
}
// src/validation/assertions/create.ts
function assertCreateObjectResponse(value) {
return handleAPIObjectAssertion({
schema: createObjectResponseSchema,
code: "CREATE_OBJECT",
value
});
}
// src/validation/schemas/list.ts
var import_zod3 = require("zod");
var listObjectsSchema = import_zod3.z.object({
/** Filter by prefix */
prefix: import_zod3.z.string().optional(),
/** Return objects after this token */
continuationToken: import_zod3.z.string().optional()
});
var listObjectsPayloadSchema = listObjectsSchema.optional().transform((params) => ({ params }));
var listObjectResponseSchema = import_zod3.z.object({
id: import_zod3.z.string(),
size: import_zod3.z.number(),
created_at: import_zod3.z.coerce.date(),
expires_at: import_zod3.z.coerce.date().optional()
});
var listObjectsResponseSchema = import_zod3.z.object({
objects: import_zod3.z.array(listObjectResponseSchema).default([])
});
// src/validation/assertions/list.ts
function assertListObjectsResponse(value) {
return handleAPIObjectAssertion({
schema: listObjectsResponseSchema,
code: "LIST_OBJECTS",
value
});
}
// src/managers/objects.ts
var ObjectsManager = class {
constructor(client) {
this.client = client;
}
/**
* Lists all objects in the storage.
*
* @example
* ```js
* blob.objects.list();
* ```
*/
async list(options) {
const payload = listObjectsPayloadSchema.parse(options);
const { response } = await this.client.api.request(
"objects",
{ params: payload.params }
);
const { objects } = assertListObjectsResponse(response);
return objects.map((objectData) => {
const createdAt = new Date(objectData.created_at);
const expiresAt = objectData.expires_at ? new Date(objectData.expires_at) : void 0;
return new BlobObject({
idOrUrl: objectData.id,
size: objectData.size,
createdAt,
expiresAt
});
});
}
/**
* Uploads an object to the storage.
*
* @param object - An object to upload
*
* @example
* ```js
* // Basic usage with absolute path
* blob.objects.create({
* file: "path/to/file.jpeg",
* name: "my_image"
* });
*
* // Advanced usage with Buffer
* blob.objects.create({
* file: Buffer.from("content"),
* name: "my_image",
* mimeType: "image/jpeg"
* })
* ```
*/
async create(object) {
const payload = createObjectPayloadSchema.parse(object);
const file = await parsePathLike(payload.file);
const type = payload.mimeType || object.mimeType;
const formData = new FormData();
formData.append("file", new Blob([file], { type }));
const { response } = await this.client.api.request(
"objects",
{ method: "POST", body: formData, params: payload.params }
);
const objectData = assertCreateObjectResponse(response);
return new BlobObject({
idOrUrl: objectData.id,
size: objectData.size
});
}
/**
* Delete an object from the storage.
*
* @param object - An array of object IDs
*
* @example
* ```js
* blob.object.delete("userId/prefix/name1_xxx-xxx.mp4");
* ```
*/
async delete(object) {
const { status } = await this.client.api.request("objects", {
method: "DELETE",
body: { object }
});
return status === "success";
}
};
// src/validation/schemas/stats.ts
var import_zod4 = require("zod");
var statsResponseSchema = import_zod4.z.object({
/** The total number of objects in your account. */
objects: import_zod4.z.number(),
/** The total size of all objects in your account, in bytes. */
size: import_zod4.z.number(),
/** The total price of storage for all objects in your account, in BRL. */
storagePrice: import_zod4.z.number(),
/** The total price of all objects in your account, in BRL. */
objectsPrice: import_zod4.z.number(),
/** The total price of all objects in your account, in BRL. */
totalEstimate: import_zod4.z.number()
});
// src/validation/assertions/stats.ts
function assertStatsResponse(value) {
return handleAPIObjectAssertion({
schema: statsResponseSchema,
code: "ACCOUNT_STATS",
value
});
}
// src/index.ts
var SquareCloudBlob = class {
constructor(apiKey) {
__publicField(this, "api");
__publicField(this, "objects", new ObjectsManager(this));
this.api = new APIManager(apiKey);
}
async stats() {
const { response } = await this.api.request("account/stats");
return assertStatsResponse(response);
}
};
__publicField(SquareCloudBlob, "apiInfo", {
baseUrl: "https://blob.squarecloud.app",
version: "v1"
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BlobObject,
MimeTypeUtil,
MimeTypes,
SquareCloudBlob
});
//# sourceMappingURL=index.js.map