import type { Dirent } from 'node:fs' import { readdir, stat } from 'node:fs/promises' import path from 'node:path' import { pathToFileURL } from 'node:url' import { FunctionArtifact, FunctionFileEntry } from './types' export class FileSystemFunctionsArtifactStore { constructor(private folderPath: string) {} async getFunctions(): Promise { const dirEntries = await readdir(this.folderPath, { withFileTypes: true }) const functionsFolders = dirEntries.filter((dir) => dir.isDirectory() && dir.name !== 'main') const functionsArtifacts = await Promise.all( functionsFolders.map(parseFolderToFunctionArtifact) ) return functionsArtifacts.filter((f) => f !== undefined) } async getFunctionBySlug(slug: string): Promise { const dirEntries = await readdir(this.folderPath, { withFileTypes: true }) const functionFolder = dirEntries.find( (dir) => dir.isDirectory() && dir.name !== 'main' && dir.name === slug ) if (!functionFolder) return return parseFolderToFunctionArtifact(functionFolder) } async getFileEntriesBySlug(slug: string): Promise> { if (slug === 'main') return [] const functionFolderPath = path.resolve(this.folderPath, slug) if (!functionFolderPath.startsWith(path.resolve(this.folderPath) + path.sep)) return [] const entries = await readdir(functionFolderPath, { recursive: true, withFileTypes: true, }) const fileEntries = await Promise.all( entries .filter((entry) => entry.isFile()) .map(async (entry) => { const absolutePath = path.join(entry.parentPath, entry.name) const fileStat = await stat(absolutePath) return { absolutePath, relativePath: path.relative(functionFolderPath, absolutePath), size: fileStat.size, } }) ) return fileEntries } } async function parseFolderToFunctionArtifact( folder: Dirent ): Promise { const folderPath = path.join(folder.parentPath, folder.name) const files = await readdir(folderPath, { withFileTypes: true }) const entrypoint = files.find((file) => file.isFile() && file.name.startsWith('index')) if (!entrypoint) return const entrypointPath = path.join(folderPath, entrypoint.name) const entrypointStat = await stat(entrypointPath) return { slug: folder.name, entrypoint_path: pathToFileURL(entrypointPath).href, created_at: entrypointStat.birthtimeMs, updated_at: entrypointStat.mtimeMs, } }