Add CYD browser flasher with Next.js, i18n, and Web Serial install.
Replace the starter app with a public/local flasher that discovers sibling firmwares, supports en/zh, and documents HTTPS deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
37
app/api/firmware/[project]/[variant]/[file]/route.ts
Normal file
37
app/api/firmware/[project]/[variant]/[file]/route.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { NextResponse } from "next/server";
|
||||
import { REQUIRED_BINS, resolveFirmwareDir } from "@/lib/firmware";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ project: string; variant: string; file: string }>;
|
||||
};
|
||||
|
||||
export async function GET(_req: Request, { params }: Params) {
|
||||
const { project, variant, file } = await params;
|
||||
if (!(REQUIRED_BINS as readonly string[]).includes(file)) {
|
||||
return NextResponse.json({ error: "invalid file" }, { status: 400 });
|
||||
}
|
||||
|
||||
const dir = resolveFirmwareDir(project, variant);
|
||||
if (!dir) {
|
||||
return NextResponse.json({ error: "not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const abs = path.join(dir, file);
|
||||
if (!fs.existsSync(abs)) {
|
||||
return NextResponse.json({ error: "not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const buf = fs.readFileSync(abs);
|
||||
return new NextResponse(buf, {
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": String(buf.length),
|
||||
"Cache-Control": "no-store",
|
||||
"Content-Disposition": `attachment; filename="${file}"`,
|
||||
},
|
||||
});
|
||||
}
|
||||
39
app/api/firmware/[project]/[variant]/manifest.json/route.ts
Normal file
39
app/api/firmware/[project]/[variant]/manifest.json/route.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
FLASH_PARTS,
|
||||
readFirmwareMeta,
|
||||
resolveFirmwareDir,
|
||||
} from "@/lib/firmware";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
type Params = { params: Promise<{ project: string; variant: string }> };
|
||||
|
||||
export async function GET(_req: Request, { params }: Params) {
|
||||
const { project, variant } = await params;
|
||||
const dir = resolveFirmwareDir(project, variant);
|
||||
if (!dir) {
|
||||
return NextResponse.json({ error: "firmware not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const meta = readFirmwareMeta(dir);
|
||||
const name = meta.name || `${project} (${variant})`;
|
||||
const version =
|
||||
[meta.date, meta.git].filter(Boolean).join(" / ") || "local";
|
||||
|
||||
const base = `/api/firmware/${encodeURIComponent(project)}/${encodeURIComponent(variant)}`;
|
||||
return NextResponse.json({
|
||||
name,
|
||||
version,
|
||||
new_install_prompt_erase: true,
|
||||
builds: [
|
||||
{
|
||||
chipFamily: "ESP32",
|
||||
parts: FLASH_PARTS.map((p) => ({
|
||||
path: `${base}/${p.file}`,
|
||||
offset: p.offset,
|
||||
})),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
13
app/api/firmware/route.ts
Normal file
13
app/api/firmware/route.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { discoverFirmware } from "@/lib/firmware";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
const firmwares = discoverFirmware();
|
||||
return NextResponse.json({
|
||||
chipFamily: "ESP32",
|
||||
count: firmwares.length,
|
||||
firmwares,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user