UNPKG

seyfert

Version:

The most advanced framework for discord bots

220 lines (219 loc) 7.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AttachmentBuilder = exports.Attachment = void 0; exports.resolveAttachment = resolveAttachment; exports.resolveFiles = resolveFiles; exports.resolveAttachmentData = resolveAttachmentData; exports.resolveBase64 = resolveBase64; exports.resolveImage = resolveImage; const node_crypto_1 = require("node:crypto"); const node_fs_1 = require("node:fs"); const node_path_1 = __importDefault(require("node:path")); const utils_1 = require("../api/utils/utils"); const Base_1 = require("../structures/extra/Base"); class Attachment extends Base_1.Base { data; constructor(client, data) { super(client); this.data = data; this.__patchThis(data); } } exports.Attachment = Attachment; class AttachmentBuilder { data; /** * Creates a new Attachment instance. * @param data - The partial attachment data. */ constructor(data = { filename: `${((0, node_crypto_1.randomBytes)?.(8))?.toString('base64url') || 'default'}.jpg` }) { this.data = data; } /** * Sets the name of the attachment. * @param name - The name of the attachment. * @returns The Attachment instance. * @example * attachment.setName('example.jpg'); */ setName(name) { this.data.filename = name; return this; } /** * Sets the description of the attachment. * @param desc - The description of the attachment. * @returns The Attachment instance. * @example * attachment.setDescription('This is an example attachment'); */ setDescription(desc) { this.data.description = desc; return this; } /** * Sets the file data of the attachment. * @param type - The type of the attachment data. * @param data - The resolvable data of the attachment. * @returns The Attachment instance. * @example * attachment.setFile('url', 'https://example.com/example.jpg'); * attachment.setFile('path', '../assets/example.jpg'); * attachment.setFile('buffer', Buffer.from(image.decode())); */ setFile(type, data) { this.data.type = type; this.data.resolvable = data; return this; } /** * Sets whether the attachment is a spoiler. * @param spoiler - Whether the attachment is a spoiler. * @returns The Attachment instance. * @example * attachment.setSpoiler(true); */ setSpoiler(spoiler) { if (spoiler === this.spoiler) return this; if (!spoiler) { this.data.filename = this.data.filename.slice('SPOILER_'.length); return this; } this.data.filename = `SPOILER_${this.data.filename}`; return this; } /** * Gets whether the attachment is a spoiler. */ get spoiler() { return this.data.filename?.startsWith('SPOILER_') ?? false; } /** * Converts the Attachment instance to JSON. * @returns The JSON representation of the Attachment instance. */ toJSON() { return this.data; } } exports.AttachmentBuilder = AttachmentBuilder; /** * Resolves an attachment to a REST API attachment. * @param resolve - The attachment or attachment data to resolve. * @returns The resolved REST API attachment. */ function resolveAttachment(resolve) { if ('id' in resolve) return resolve; if (resolve instanceof AttachmentBuilder) { const { filename, description } = resolve.toJSON(); return { filename, description }; } return { filename: resolve.filename, description: resolve.description }; } /** * Resolves a list of attachments to raw files. * @param resources - The list of attachments to resolve. * @returns The resolved raw files. */ async function resolveFiles(resources) { const data = await Promise.all(resources.map(async (resource, i) => { if (resource instanceof AttachmentBuilder) { const { type, resolvable, filename } = resource.toJSON(); const resolve = await resolveAttachmentData(resolvable, type); return { ...resolve, key: `files[${i}]`, filename }; } if (resource instanceof Attachment) { const resolve = await resolveAttachmentData(resource.url, 'url'); return { data: resolve.data, contentType: resolve.contentType, key: `files[${i}]`, filename: resource.filename, }; } return { data: resource.data, contentType: resource.contentType, key: `files[${i}]`, filename: resource.filename, }; })); return data; } /** * Resolves the data of an attachment. * @param data - The resolvable data of the attachment. * @param type - The type of the attachment data. * @returns The resolved attachment data. */ async function resolveAttachmentData(data, type) { if (data instanceof AttachmentBuilder) { if (!data.data.resolvable) throw new Error('The attachment type has been expressed as attachment but cannot be resolved as one.'); return { data: data.data.resolvable }; } switch (type) { case 'url': { if (!/^https?:\/\//.test(data)) throw new Error(`The attachment type has been expressed as ${type.toUpperCase()} but cannot be resolved as one.`); const res = await fetch(data); return { data: Buffer.from(await res.arrayBuffer()), contentType: res.headers.get('content-type') }; } case 'path': { const file = node_path_1.default.resolve(data); const stats = await node_fs_1.promises.stat(file); if (!stats.isFile()) throw new Error(`The attachment type has been expressed as ${type.toUpperCase()} but cannot be resolved as one.`); return { data: await node_fs_1.promises.readFile(file) }; } case 'buffer': { if ((0, utils_1.isBufferLike)(data)) return { data }; // @ts-expect-error if (typeof data[Symbol.asyncIterator] === 'function') { const buffers = []; for await (const resource of data) buffers.push(Buffer.from(resource)); return { data: Buffer.concat(buffers) }; } throw new Error(`The attachment type has been expressed as ${type.toUpperCase()} but cannot be resolved as one.`); } default: { throw new Error(`The attachment type has been expressed as ${type} but cannot be resolved as one.`); } } } /** * Resolves a base64 data to a data URL. * @param data - The base64 data. * @returns The resolved data URL. */ function resolveBase64(data) { if (Buffer.isBuffer(data)) return `data:image/jpg;base64,${data.toString('base64')}`; return data; } /** * Resolves an image to a base64 data URL. * @param image - The image to resolve. * @returns The resolved base64 data URL. */ async function resolveImage(image) { if (image instanceof AttachmentBuilder) { const { data: { type, resolvable }, } = image; if (type && resolvable) return resolveBase64((await resolveAttachmentData(resolvable, type)).data); throw new Error(`The attachment type has been expressed as ${(type ?? 'Attachment').toUpperCase()} but cannot be resolved as one.`); } if (image instanceof Attachment) { const response = await fetch(image.url); return resolveBase64((await resolveAttachmentData(await response.arrayBuffer(), 'buffer')).data); } const file = await resolveAttachmentData(image.data, image.type); return resolveBase64(file.data); }