/**
 * Handler for fs_create messages.
 * Creates empty files or directories within a project.
 * Fails if the target already exists.
 */
import { writeFile, mkdir, stat, realpath, rm } from "node:fs/promises";
import { dirname } from "node:path";
import { ErrorCode } from "@pocketcoder/shared/constants";
import { getProject } from "../db/repositories/projects.js";
import { validateParentWithinProject, PathEscapeError } from "../services/filesystem.js";
import { logger } from "../utils/logger.js";
export async function handleFsCreate(message, send) {
    const msg = message;
    const { requestId, sessionId, payload } = msg;
    const { path: relativePath, itemType, createDirs } = payload;
    const project = getProject(sessionId);
    if (!project) {
        send({
            type: "fs_create_response",
            requestId,
            error: {
                code: ErrorCode.INVALID_REQUEST,
                message: `Project not found: ${sessionId}`,
            },
        });
        return;
    }
    try {
        const resolvedPath = await validateParentWithinProject(project.path, relativePath);
        // Check if the target already exists
        try {
            await stat(resolvedPath);
            // If stat succeeds, the path exists
            send({
                type: "fs_create_response",
                requestId,
                error: {
                    code: ErrorCode.FILE_EXISTS,
                    message: `Already exists: ${relativePath}`,
                },
            });
            return;
        }
        catch {
            // ENOENT means it doesn't exist — that's what we want
        }
        // Create parent directories if requested (default true)
        if (createDirs ?? true) {
            await mkdir(dirname(resolvedPath), { recursive: true });
        }
        if (itemType === "directory") {
            await mkdir(resolvedPath);
        }
        else {
            await writeFile(resolvedPath, "", "utf-8");
        }
        // Post-creation realpath check to guard against symlink-based TOCTOU attacks
        const realResolved = await realpath(resolvedPath);
        const realProject = await realpath(project.path);
        if (!realResolved.startsWith(realProject + "/") && realResolved !== realProject) {
            // Clean up the created file/directory outside the project
            await rm(resolvedPath, { recursive: true, force: true }).catch(() => { });
            throw new PathEscapeError("Path escapes project directory");
        }
        send({
            type: "fs_create_response",
            requestId,
            payload: {
                path: relativePath,
                itemType,
            },
        });
    }
    catch (err) {
        if (err instanceof PathEscapeError) {
            send({
                type: "fs_create_response",
                requestId,
                error: {
                    code: ErrorCode.OUTSIDE_PROJECT_ROOT,
                    message: "Path escapes project directory",
                },
            });
            return;
        }
        const errorMessage = err instanceof Error ? err.message : String(err);
        logger.error(`fs_create error: ${errorMessage}`);
        send({
            type: "fs_create_response",
            requestId,
            error: {
                code: ErrorCode.UNKNOWN_ERROR,
                message: errorMessage,
            },
        });
    }
}
//# sourceMappingURL=fs-create.js.map