profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
fs.ts 1,767 bytes
1 import { mkdir, readdir } from 'node:fs/promises'
2 import { homedir } from 'node:os'
3 import path from 'node:path'
4 import type { FastifyInstance } from 'fastify'
5 import { FsMkdirRequestSchema, type FsBrowseResponse, type FsMkdirResponse } from '../../shared/types'
6
7 export function registerFsRoutes(app: FastifyInstance): void {
8 app.get('/api/fs/browse', async (request, reply) => {
9 const query = request.query as { path?: string }
10 const target = query.path && query.path.trim().length > 0 ? query.path : homedir()
11
12 let entries
13 try {
14 entries = await readdir(target, { withFileTypes: true })
15 } catch (err) {
16 return reply.code(400).send({ error: err instanceof Error ? err.message : "can't read that folder" })
17 }
18
19 const directories = entries
20 .filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
21 .map((entry) => ({ name: entry.name, path: path.join(target, entry.name) }))
22 .sort((a, b) => a.name.localeCompare(b.name))
23
24 const parentDir = path.dirname(target)
25 const parent = parentDir === target ? null : parentDir
26
27 const response: FsBrowseResponse = { path: target, parent, directories }
28 return reply.send(response)
29 })
30
31 app.post('/api/fs/mkdir', async (request, reply) => {
32 const parsed = FsMkdirRequestSchema.safeParse(request.body)
33 if (!parsed.success) {
34 return reply.code(400).send({ error: parsed.error.message })
35 }
36
37 const newPath = path.join(parsed.data.path, parsed.data.name)
38 try {
39 await mkdir(newPath)
40 } catch (err) {
41 return reply.code(400).send({ error: err instanceof Error ? err.message : "can't create that folder" })
42 }
43
44 const response: FsMkdirResponse = { path: newPath }
45 return reply.send(response)
46 })
47 }
48