import os from 'node:os'; import fs from 'node:fs'; import { createId } from '@paralleldrive/cuid2'; import { Readable } from 'stream'; import { finished } from 'stream/promises'; import { dirname, basename, join, isAbsolute } from 'node:path'; import { fileURLToPath } from 'url'; import { createHash } from 'node:crypto'; export const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(fileURLToPath(import.meta.url)); const ua0 = 'Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0' export function getPackageVersion(packageJsonPath: string): string { if (!packageJsonPath) throw new Error('getPackageVersion requires packageJsonPath as first argument, but it was undefined.'); if (!isAbsolute(packageJsonPath)) { packageJsonPath = join(__dirname, packageJsonPath) } try { const raw = fs.readFileSync(packageJsonPath, { encoding: 'utf-8' }) const json = JSON.parse(raw) return json.version } catch (e) { console.error('failed to getPackageVersion') console.error(e) return 'IDK' } } export function getTmpFile(str: string): string { return join(os.tmpdir(), `${createId()}_${basename(str)}`); } /** * * @param {String} url * @returns {String} filePath * * @see https://stackoverflow.com/a/74722818/1004931 */ export async function download({ url, filePath, }: { url: string; filePath?: string; }): Promise { if (!url) throw new Error(`The 'url' parameter is required and must be a string.`); const fileBaseName = basename(url); filePath = filePath || join(os.tmpdir(), `${createId()}_${fileBaseName}`); const stream = fs.createWriteStream(filePath); const requestData = async () => { const response = await fetch(url, { headers: { 'user-agent': ua0, }, }); const { body } = response; if (!body) throw new Error('Response body was null.'); // Convert the Fetch API ReadableStream to a Node.js Readable stream const nodeStream = Readable.from(body as any); await finished(nodeStream.pipe(stream)); // Abort retrying if the resource doesn't exist if (response.status === 404) { throw new Error('Resource not found (404).'); } }; await requestData(); return filePath; } export const tmpFileRegex = /^\/tmp\/.*\.jpg$/; /** * getFileChecksum * @see https://stackoverflow.com/a/44643479/1004931 */ export async function getFileChecksum(filePath: string, algorithm = 'md5') { return new Promise((resolve, reject) => { const hash = createHash(algorithm); const stream = fs.createReadStream(filePath); stream.on('error', err => reject(err)); stream.on('data', chunk => hash.update(chunk)); stream.on('end', () => resolve(hash.digest('hex'))); }); }