fp/packages/utils/src/file.ts
CJ_Clippy 140883a69c
Some checks failed
ci / build (push) Failing after 1s
dec 2024 progress
2024-12-11 23:23:46 -08:00

97 lines
2.7 KiB
TypeScript

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<string> {
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')));
});
}