afterbefore 0.2.25 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CC6QEACR.js → chunk-U4SMF2RN.js} +28 -10
- package/dist/chunk-U4SMF2RN.js.map +1 -0
- package/dist/overlay/index.js +851 -514
- package/dist/overlay/index.js.map +1 -1
- package/dist/server/middleware.js +1 -1
- package/dist/server/route.js +1 -1
- package/package.json +4 -6
- package/dist/chunk-CC6QEACR.js.map +0 -1
|
@@ -95,12 +95,14 @@ async function getRepoName() {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// src/server/save.ts
|
|
98
|
-
async function saveGlobalCopy(
|
|
98
|
+
async function saveGlobalCopy(rawBuffer, viewportBuffer, repoName, branch) {
|
|
99
99
|
const globalDir = join2(homedir2(), ".afterbefore", repoName, branch);
|
|
100
100
|
await mkdir2(globalDir, { recursive: true });
|
|
101
101
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
await writeFile2(join2(globalDir, `${timestamp}.png`), rawBuffer);
|
|
103
|
+
if (viewportBuffer) {
|
|
104
|
+
await writeFile2(join2(globalDir, `${timestamp}.viewport.png`), viewportBuffer);
|
|
105
|
+
}
|
|
104
106
|
}
|
|
105
107
|
var VALID_MODES = ["fullpage", "viewport", "component"];
|
|
106
108
|
var DATA_URL_PREFIX = "data:image/png;base64,";
|
|
@@ -114,7 +116,7 @@ async function handleSave(req) {
|
|
|
114
116
|
{ status: 400 }
|
|
115
117
|
);
|
|
116
118
|
}
|
|
117
|
-
const { mode, image } = body;
|
|
119
|
+
const { mode, image, rawImage, viewportImage } = body;
|
|
118
120
|
if (!VALID_MODES.includes(mode)) {
|
|
119
121
|
return NextResponse2.json(
|
|
120
122
|
{ error: `Invalid mode: must be "fullpage", "viewport", or "component"` },
|
|
@@ -127,8 +129,7 @@ async function handleSave(req) {
|
|
|
127
129
|
{ status: 400 }
|
|
128
130
|
);
|
|
129
131
|
}
|
|
130
|
-
const
|
|
131
|
-
const buffer = Buffer.from(base64, "base64");
|
|
132
|
+
const buffer = Buffer.from(image.slice(DATA_URL_PREFIX.length), "base64");
|
|
132
133
|
const [branch, repoName, saveDir] = await Promise.all([
|
|
133
134
|
getBranch(),
|
|
134
135
|
getRepoName(),
|
|
@@ -145,7 +146,9 @@ async function handleSave(req) {
|
|
|
145
146
|
);
|
|
146
147
|
}
|
|
147
148
|
try {
|
|
148
|
-
|
|
149
|
+
const archiveBuffer = rawImage?.startsWith(DATA_URL_PREFIX) ? Buffer.from(rawImage.slice(DATA_URL_PREFIX.length), "base64") : buffer;
|
|
150
|
+
const vpBuffer = viewportImage?.startsWith(DATA_URL_PREFIX) ? Buffer.from(viewportImage.slice(DATA_URL_PREFIX.length), "base64") : null;
|
|
151
|
+
await saveGlobalCopy(archiveBuffer, vpBuffer, repoName, branch);
|
|
149
152
|
} catch {
|
|
150
153
|
}
|
|
151
154
|
return NextResponse2.json({ success: true, path: filepath });
|
|
@@ -358,7 +361,7 @@ async function listBranches(repoDir) {
|
|
|
358
361
|
async function listPngs(dir) {
|
|
359
362
|
try {
|
|
360
363
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
361
|
-
return entries.filter((e) => e.isFile() && e.name.endsWith(".png")).map((e) => ({
|
|
364
|
+
return entries.filter((e) => e.isFile() && e.name.endsWith(".png") && !e.name.endsWith(".viewport.png")).map((e) => ({
|
|
362
365
|
filename: e.name,
|
|
363
366
|
timestamp: e.name.replace(/\.png$/, "")
|
|
364
367
|
})).sort((a, b) => b.filename.localeCompare(a.filename)).slice(0, MAX_SCREENSHOTS);
|
|
@@ -423,6 +426,12 @@ async function handleHistoryRename(req) {
|
|
|
423
426
|
}
|
|
424
427
|
try {
|
|
425
428
|
await rename(oldPath, newPath);
|
|
429
|
+
const oldVp = oldPath.replace(/\.png$/, ".viewport.png");
|
|
430
|
+
const newVp = newPath.replace(/\.png$/, ".viewport.png");
|
|
431
|
+
try {
|
|
432
|
+
await rename(oldVp, newVp);
|
|
433
|
+
} catch {
|
|
434
|
+
}
|
|
426
435
|
return NextResponse5.json({ success: true, filename: safeName });
|
|
427
436
|
} catch {
|
|
428
437
|
return NextResponse5.json({ error: "Rename failed" }, { status: 500 });
|
|
@@ -448,6 +457,11 @@ async function handleHistoryDelete(req) {
|
|
|
448
457
|
}
|
|
449
458
|
try {
|
|
450
459
|
await unlink(filepath);
|
|
460
|
+
const viewportPath = filepath.replace(/\.png$/, ".viewport.png");
|
|
461
|
+
try {
|
|
462
|
+
await unlink(viewportPath);
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
451
465
|
return NextResponse5.json({ success: true });
|
|
452
466
|
} catch {
|
|
453
467
|
return NextResponse5.json({ error: "Delete failed" }, { status: 500 });
|
|
@@ -457,10 +471,14 @@ async function handleHistoryImage(req) {
|
|
|
457
471
|
const url = req.nextUrl;
|
|
458
472
|
const repo = url.searchParams.get("repo");
|
|
459
473
|
const branch = url.searchParams.get("branch");
|
|
460
|
-
|
|
474
|
+
let file = url.searchParams.get("file");
|
|
475
|
+
const variant = url.searchParams.get("variant");
|
|
461
476
|
if (!repo || !branch || !file) {
|
|
462
477
|
return NextResponse5.json({ error: "Missing repo, branch, or file param" }, { status: 400 });
|
|
463
478
|
}
|
|
479
|
+
if (variant === "viewport") {
|
|
480
|
+
file = file.replace(/\.png$/, ".viewport.png");
|
|
481
|
+
}
|
|
464
482
|
if (!isSafeName2(repo) || !isSafeBranchName2(branch) || !isSafeName2(file)) {
|
|
465
483
|
return NextResponse5.json({ error: "Invalid parameter" }, { status: 400 });
|
|
466
484
|
}
|
|
@@ -493,4 +511,4 @@ export {
|
|
|
493
511
|
handleHistoryDelete,
|
|
494
512
|
handleHistoryImage
|
|
495
513
|
};
|
|
496
|
-
//# sourceMappingURL=chunk-
|
|
514
|
+
//# sourceMappingURL=chunk-U4SMF2RN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/config.ts","../src/server/save.ts","../src/server/git.ts","../src/server/push.ts","../src/server/open.ts","../src/server/history.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface Config {\n saveDir: string;\n}\n\nconst CONFIG_DIR = join(process.cwd(), \".afterbefore\");\nconst CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\nconst DEFAULT_SAVE_DIR = join(homedir(), \"Desktop\");\n\nasync function readConfig(): Promise<Config> {\n try {\n const raw = await readFile(CONFIG_PATH, \"utf-8\");\n const parsed = JSON.parse(raw);\n return { saveDir: parsed.saveDir || DEFAULT_SAVE_DIR };\n } catch {\n return { saveDir: DEFAULT_SAVE_DIR };\n }\n}\n\nasync function writeConfig(config: Config): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport async function getSaveDir(): Promise<string> {\n const config = await readConfig();\n return config.saveDir;\n}\n\nexport async function handleGetConfig(): Promise<NextResponse> {\n const config = await readConfig();\n return NextResponse.json(config);\n}\n\nexport async function handleSetConfig(req: NextRequest): Promise<NextResponse> {\n let body: Partial<Config>;\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n if (typeof body.saveDir !== \"string\" || body.saveDir.trim() === \"\") {\n return NextResponse.json({ error: \"Invalid saveDir\" }, { status: 400 });\n }\n\n const config: Config = { saveDir: body.saveDir.trim() };\n await writeConfig(config);\n return NextResponse.json(config);\n}\n\nexport async function handlePickFolder(): Promise<NextResponse> {\n if (process.platform !== \"darwin\") {\n return NextResponse.json(\n { error: \"Folder picker is only supported on macOS\" },\n { status: 501 },\n );\n }\n\n try {\n const { stdout } = await execFileAsync(\"osascript\", [\n \"-e\",\n 'POSIX path of (choose folder with prompt \"Select screenshot save location\")',\n ]);\n const folder = stdout.trim().replace(/\\/$/, \"\");\n if (!folder) {\n return NextResponse.json({ cancelled: true });\n }\n return NextResponse.json({ folder });\n } catch {\n // User cancelled the dialog\n return NextResponse.json({ cancelled: true });\n }\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getSaveDir } from \"./config\";\nimport { getBranch, getRepoName } from \"./git\";\n\nasync function saveGlobalCopy(\n rawBuffer: Buffer,\n viewportBuffer: Buffer | null,\n repoName: string,\n branch: string,\n): Promise<void> {\n const globalDir = join(homedir(), \".afterbefore\", repoName, branch);\n await mkdir(globalDir, { recursive: true });\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n await writeFile(join(globalDir, `${timestamp}.png`), rawBuffer);\n if (viewportBuffer) {\n await writeFile(join(globalDir, `${timestamp}.viewport.png`), viewportBuffer);\n }\n}\n\nconst VALID_MODES = [\"fullpage\", \"viewport\", \"component\"] as const;\n\nconst DATA_URL_PREFIX = \"data:image/png;base64,\";\n\ninterface SaveRequestBody {\n mode: string;\n image: string;\n rawImage?: string;\n viewportImage?: string;\n}\n\nexport async function handleSave(req: NextRequest): Promise<NextResponse> {\n let body: SaveRequestBody;\n try {\n body = await req.json();\n } catch {\n return NextResponse.json(\n { error: \"Invalid JSON body\" },\n { status: 400 },\n );\n }\n\n const { mode, image, rawImage, viewportImage } = body;\n\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n return NextResponse.json(\n { error: `Invalid mode: must be \"fullpage\", \"viewport\", or \"component\"` },\n { status: 400 },\n );\n }\n\n if (typeof image !== \"string\" || !image.startsWith(DATA_URL_PREFIX)) {\n return NextResponse.json(\n { error: \"Invalid image: must be a data:image/png;base64 data URL\" },\n { status: 400 },\n );\n }\n\n const buffer = Buffer.from(image.slice(DATA_URL_PREFIX.length), \"base64\");\n\n const [branch, repoName, saveDir] = await Promise.all([\n getBranch(),\n getRepoName(),\n getSaveDir(),\n ]);\n const filename = `${branch}.png`;\n const filepath = join(saveDir, filename);\n\n try {\n await writeFile(filepath, buffer);\n } catch (err) {\n return NextResponse.json(\n { error: \"Failed to write screenshot\", detail: String(err) },\n { status: 500 },\n );\n }\n\n // Always keep a copy in the global ~/.afterbefore/<repo>/<branch>/ archive\n // Save raw images (without frame) so settings can be applied dynamically\n try {\n const archiveBuffer = rawImage?.startsWith(DATA_URL_PREFIX)\n ? Buffer.from(rawImage.slice(DATA_URL_PREFIX.length), \"base64\")\n : buffer;\n const vpBuffer = viewportImage?.startsWith(DATA_URL_PREFIX)\n ? Buffer.from(viewportImage.slice(DATA_URL_PREFIX.length), \"base64\")\n : null;\n await saveGlobalCopy(archiveBuffer, vpBuffer, repoName, branch);\n } catch {\n // Non-fatal: don't fail the save if the global copy fails\n }\n\n return NextResponse.json({ success: true, path: filepath });\n}\n","import { basename } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport async function getBranch(): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], {\n cwd: process.cwd(),\n });\n return stdout.trim();\n}\n\nexport async function getRepoName(): Promise<string> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd: process.cwd(),\n });\n return basename(stdout.trim());\n } catch {\n return basename(process.cwd());\n }\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { access, mkdir, copyFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { getSaveDir } from \"./config\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface PrInfo {\n number: number;\n url: string;\n headRepository: { owner: { login: string }; name: string };\n headRefName: string;\n}\n\nasync function run(\n cmd: string,\n args: string[],\n): Promise<{ stdout: string; stderr: string }> {\n return execFileAsync(cmd, args, { cwd: process.cwd() });\n}\n\nasync function ghAvailable(): Promise<boolean> {\n try {\n await run(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function getPrInfo(): Promise<PrInfo | null> {\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,url,headRepository,headRefName\",\n ]);\n return JSON.parse(stdout) as PrInfo;\n } catch {\n return null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function handlePush(req: NextRequest): Promise<NextResponse> {\n // 1. Check gh CLI availability\n if (!(await ghAvailable())) {\n return NextResponse.json(\n { success: false, error: \"GitHub CLI (gh) is not installed or not in PATH\" },\n { status: 500 },\n );\n }\n\n // 2. Check for active PR\n const pr = await getPrInfo();\n if (!pr) {\n return NextResponse.json(\n { success: false, error: \"No PR found for current branch\" },\n { status: 404 },\n );\n }\n\n // 3. Check that screenshot file exists in save directory\n const saveDir = await getSaveDir();\n const branch = pr.headRefName;\n const screenshotPath = join(saveDir, `${branch}.png`);\n\n if (!(await fileExists(screenshotPath))) {\n return NextResponse.json(\n { success: false, error: `Missing screenshot: ${branch}.png` },\n { status: 400 },\n );\n }\n\n // 4. Copy into repo, stage, commit, and push\n const repoDir = join(process.cwd(), \".afterbefore\");\n const repoFile = join(repoDir, `${branch}.png`);\n\n try {\n await mkdir(repoDir, { recursive: true });\n await copyFile(screenshotPath, repoFile);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to copy screenshot into repo\", detail: String(err) },\n { status: 500 },\n );\n }\n\n try {\n await run(\"git\", [\"add\", repoFile]);\n await run(\"git\", [\n \"commit\",\n \"-m\",\n \"chore: add screenshot\",\n ]);\n } catch (err) {\n const msg = String(err);\n if (!msg.includes(\"nothing to commit\")) {\n return NextResponse.json(\n { success: false, error: \"Failed to commit screenshot\", detail: msg },\n { status: 500 },\n );\n }\n }\n\n try {\n await run(\"git\", [\"push\"]);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to push to remote\", detail: String(err) },\n { status: 500 },\n );\n }\n\n // 5. Build raw GitHub URL for the image\n const owner = pr.headRepository.owner.login;\n const repo = pr.headRepository.name;\n const rawBase = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;\n const imageUrl = `${rawBase}/.afterbefore/${branch}.png`;\n\n // Cache-bust with timestamp so GitHub doesn't serve stale images\n const ts = Date.now();\n const commentBody = `## Screenshot\\n\\n`;\n\n // 6. Post PR comment\n let commentUrl: string | undefined;\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"comment\",\n String(pr.number),\n \"--body\",\n commentBody,\n ]);\n commentUrl = stdout.trim() || undefined;\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to post PR comment\", detail: String(err) },\n { status: 500 },\n );\n }\n\n return NextResponse.json({\n success: true,\n pr: pr.number,\n prUrl: pr.url,\n commentUrl,\n });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getSaveDir } from \"./config\";\n\ninterface OpenRequestBody {\n repo?: string;\n branch?: string;\n}\n\nfunction isSafeName(name: string): boolean {\n return /^[a-zA-Z0-9._\\-]+$/.test(name);\n}\n\nfunction isSafeBranchName(name: string): boolean {\n return /^[a-zA-Z0-9._\\-/]+$/.test(name) && !name.includes(\"..\") && !name.startsWith(\"/\") && !name.endsWith(\"/\");\n}\n\nexport async function handleOpen(req: NextRequest): Promise<NextResponse> {\n let body: OpenRequestBody | null = null;\n try {\n body = (await req.json()) as OpenRequestBody;\n } catch {\n body = null;\n }\n\n let dir: string;\n if (body?.repo || body?.branch) {\n if (\n typeof body.repo !== \"string\" ||\n typeof body.branch !== \"string\" ||\n !isSafeName(body.repo) ||\n !isSafeBranchName(body.branch)\n ) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n dir = join(homedir(), \".afterbefore\", body.repo, body.branch);\n await mkdir(dir, { recursive: true });\n } else {\n dir = await getSaveDir();\n }\n\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"explorer\"\n : \"xdg-open\";\n\n execFile(cmd, [dir]);\n\n return NextResponse.json({ success: true });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { access, readdir, readFile, rename, unlink } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getBranch, getRepoName } from \"./git\";\n\nconst ARCHIVE_DIR = join(homedir(), \".afterbefore\");\nconst MAX_SCREENSHOTS = 50;\n\nfunction isSafeName(name: string): boolean {\n return /^[a-zA-Z0-9._\\-]+$/.test(name);\n}\n\n/** Branch names can contain slashes (e.g. \"fix/something\"). Reject \"..\" and leading/trailing slashes. */\nfunction isSafeBranchName(name: string): boolean {\n return /^[a-zA-Z0-9._\\-/]+$/.test(name) && !name.includes(\"..\") && !name.startsWith(\"/\") && !name.endsWith(\"/\");\n}\n\nasync function listDirs(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();\n } catch {\n return [];\n }\n}\n\n/**\n * Recursively find branch paths under a repo directory.\n * A branch path is any relative path that contains .png files.\n * e.g. \"main\", \"fix/capture-mode-toolbar\"\n */\nasync function listBranches(repoDir: string): Promise<string[]> {\n const branches: string[] = [];\n\n async function walk(dir: string, prefix: string) {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n const hasPngs = entries.some((e) => e.isFile() && e.name.endsWith(\".png\"));\n if (hasPngs && prefix) {\n branches.push(prefix);\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n await walk(join(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name);\n }\n }\n } catch {\n // directory doesn't exist or can't be read\n }\n }\n\n await walk(repoDir, \"\");\n return branches.sort();\n}\n\nasync function listPngs(dir: string): Promise<{ filename: string; timestamp: string }[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".png\") && !e.name.endsWith(\".viewport.png\"))\n .map((e) => ({\n filename: e.name,\n timestamp: e.name.replace(/\\.png$/, \"\"),\n }))\n .sort((a, b) => b.filename.localeCompare(a.filename))\n .slice(0, MAX_SCREENSHOTS);\n } catch {\n return [];\n }\n}\n\nexport async function handleHistoryList(req: NextRequest): Promise<NextResponse> {\n const url = req.nextUrl;\n const repoParam = url.searchParams.get(\"repo\");\n const branchParam = url.searchParams.get(\"branch\");\n\n const [currentRepo, currentBranch] = await Promise.all([\n getRepoName(),\n getBranch(),\n ]);\n\n const repos = await listDirs(ARCHIVE_DIR);\n\n let branches: string[] = [];\n let screenshots: { filename: string; timestamp: string }[] = [];\n\n const selectedRepo = repoParam || currentRepo;\n if (selectedRepo && isSafeName(selectedRepo)) {\n branches = await listBranches(join(ARCHIVE_DIR, selectedRepo));\n\n const selectedBranch = branchParam || currentBranch;\n if (selectedBranch && isSafeBranchName(selectedBranch)) {\n screenshots = await listPngs(join(ARCHIVE_DIR, selectedRepo, selectedBranch));\n }\n }\n\n return NextResponse.json({\n repos,\n currentRepo,\n branches,\n currentBranch,\n screenshots,\n });\n}\n\nexport async function handleHistoryRename(req: NextRequest): Promise<NextResponse> {\n let body: { repo: string; branch: string; oldName: string; newName: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { repo, branch, oldName, newName } = body;\n if (!repo || !branch || !oldName || !newName) {\n return NextResponse.json({ error: \"Missing fields\" }, { status: 400 });\n }\n\n // Ensure newName ends with .png\n const safeName = newName.endsWith(\".png\") ? newName : `${newName}.png`;\n\n if (!isSafeName(repo) || !isSafeBranchName(branch) || !isSafeName(oldName) || !isSafeName(safeName)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n const dir = resolve(ARCHIVE_DIR, repo, branch);\n const oldPath = join(dir, oldName);\n const newPath = join(dir, safeName);\n\n if (!oldPath.startsWith(ARCHIVE_DIR) || !newPath.startsWith(ARCHIVE_DIR)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n if (safeName !== oldName) {\n try {\n await access(newPath);\n return NextResponse.json({ error: \"File already exists\" }, { status: 409 });\n } catch {\n // Target does not exist, continue.\n }\n }\n\n try {\n await rename(oldPath, newPath);\n // Also rename viewport companion if it exists\n const oldVp = oldPath.replace(/\\.png$/, \".viewport.png\");\n const newVp = newPath.replace(/\\.png$/, \".viewport.png\");\n try { await rename(oldVp, newVp); } catch { /* may not exist */ }\n return NextResponse.json({ success: true, filename: safeName });\n } catch {\n return NextResponse.json({ error: \"Rename failed\" }, { status: 500 });\n }\n}\n\nexport async function handleHistoryDelete(req: NextRequest): Promise<NextResponse> {\n let body: { repo: string; branch: string; file: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { repo, branch, file } = body;\n if (!repo || !branch || !file) {\n return NextResponse.json({ error: \"Missing fields\" }, { status: 400 });\n }\n\n if (!isSafeName(repo) || !isSafeBranchName(branch) || !isSafeName(file)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n const filepath = resolve(ARCHIVE_DIR, repo, branch, file);\n if (!filepath.startsWith(ARCHIVE_DIR)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n try {\n await unlink(filepath);\n // Also delete viewport companion if it exists\n const viewportPath = filepath.replace(/\\.png$/, \".viewport.png\");\n try { await unlink(viewportPath); } catch { /* may not exist */ }\n return NextResponse.json({ success: true });\n } catch {\n return NextResponse.json({ error: \"Delete failed\" }, { status: 500 });\n }\n}\n\nexport async function handleHistoryImage(req: NextRequest): Promise<NextResponse> {\n const url = req.nextUrl;\n const repo = url.searchParams.get(\"repo\");\n const branch = url.searchParams.get(\"branch\");\n let file = url.searchParams.get(\"file\");\n const variant = url.searchParams.get(\"variant\");\n\n if (!repo || !branch || !file) {\n return NextResponse.json({ error: \"Missing repo, branch, or file param\" }, { status: 400 });\n }\n\n if (variant === \"viewport\") {\n file = file.replace(/\\.png$/, \".viewport.png\");\n }\n\n if (!isSafeName(repo) || !isSafeBranchName(branch) || !isSafeName(file)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n // Extra safety: ensure resolved path stays within the archive directory\n const filepath = resolve(ARCHIVE_DIR, repo, branch, file);\n if (!filepath.startsWith(ARCHIVE_DIR)) {\n return NextResponse.json({ error: \"Invalid parameter\" }, { status: 400 });\n }\n\n try {\n const buffer = await readFile(filepath);\n return new NextResponse(buffer, {\n headers: {\n \"Content-Type\": \"image/png\",\n \"Cache-Control\": \"private, max-age=3600\",\n },\n });\n } catch {\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n}\n"],"mappings":"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","names":["NextResponse","writeFile","mkdir","join","homedir","execFile","promisify","execFileAsync","join","homedir","mkdir","writeFile","NextResponse","NextResponse","execFile","mkdir","join","promisify","execFileAsync","promisify","execFile","NextResponse","join","mkdir","NextResponse","execFile","mkdir","join","homedir","NextResponse","join","homedir","mkdir","execFile","NextResponse","access","readFile","join","homedir","join","homedir","isSafeName","isSafeBranchName","NextResponse","access","readFile"]}
|