84 lines
5.0 KiB
JavaScript
84 lines
5.0 KiB
JavaScript
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
import { homedir } from "node:os";
|
|
import { join, resolve } from "node:path";
|
|
import { createServer } from "vite";
|
|
|
|
const host = "127.0.0.1";
|
|
const port = Number(process.env.DADA_MANUAL_PREVIEW_PORT ?? 43123);
|
|
const projectId = "00000000-0000-4000-8000-000000000802";
|
|
const sourceRoot = process.env.DADA_STATIC_STICKER_ROOT ?? join(homedir(), "Desktop", "贴纸素材");
|
|
const stickerPaths = new Map();
|
|
for (let part = 1, index = 1; part <= 25; part += 1) {
|
|
const partRoot = join(sourceRoot, `sticker_part${part}`);
|
|
if (!existsSync(partRoot)) throw new Error(`Missing sticker source part ${part}.`);
|
|
const files = readdirSync(partRoot).filter((name) => name.toLowerCase().endsWith(".png")).sort();
|
|
for (const file of files) {
|
|
const id = `STK${String(index).padStart(index < 1_000 ? 3 : 4, "0")}`;
|
|
stickerPaths.set(id, join(partRoot, file));
|
|
index += 1;
|
|
}
|
|
}
|
|
if (stickerPaths.size !== 1_407) throw new Error(`Expected 1,407 stickers, found ${stickerPaths.size}.`);
|
|
|
|
const session = {
|
|
audience: "user", authenticated: true, credits: { available_balance: 10, reserved_balance: 0 },
|
|
csrf_token: "csrf-wp5-02-manual-000000000000000000000000000000", expires_at: "2026-09-03T08:00:00.000Z",
|
|
user: { creator_name: "Dada Creator", role: "user", social_id: "@dada", status: "active", user_id: "00000000-0000-4000-8000-000000000802" },
|
|
};
|
|
const backgroundId = "00000000-0000-4000-8000-000000000803";
|
|
let stateVersion = 1;
|
|
let canvasState = {
|
|
background: { adjustments: { brightness: 0, contrast: 0, crop: null, filter: "none", fit: "fill", saturation: 0, sharpness: 0, temperature: 0 }, asset_id: backgroundId },
|
|
elements: [], pixel_height: 1440, pixel_width: 1080, ratio: "3:4", schema_version: 1,
|
|
};
|
|
const backgroundSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="1080" height="1440"><rect width="1080" height="1440" fill="#d8e8f2"/><rect x="0" y="0" width="1080" height="720" fill="#b3d8ea"/><rect x="0" y="720" width="1080" height="720" fill="#f4e7cf"/></svg>`;
|
|
|
|
function send(response, status, body, contentType) {
|
|
response.statusCode = status;
|
|
response.setHeader("Content-Type", contentType);
|
|
response.end(body);
|
|
}
|
|
function sendJson(response, value, status = 200) { send(response, status, JSON.stringify(value), "application/json; charset=utf-8"); }
|
|
function readJson(request) {
|
|
return new Promise((resolveBody, reject) => {
|
|
const chunks = [];
|
|
request.on("data", (chunk) => chunks.push(chunk));
|
|
request.on("end", () => { try { resolveBody(JSON.parse(Buffer.concat(chunks).toString("utf8"))); } catch (error) { reject(error); } });
|
|
request.on("error", reject);
|
|
});
|
|
}
|
|
|
|
const mockApi = {
|
|
name: "wp5-02-manual-preview-api",
|
|
configureServer(server) {
|
|
server.middlewares.use((request, response, next) => {
|
|
const url = new URL(request.url ?? "/", `http://${host}:${port}`);
|
|
if (request.method === "GET" && url.pathname === "/api/v1/auth/session") return sendJson(response, session);
|
|
if (request.method === "GET" && url.pathname === "/api/v1/assets/recent") return sendJson(response, { items: [] });
|
|
if (request.method === "GET" && url.pathname === `/api/v1/projects/${projectId}`) return sendJson(response, {
|
|
canvas_state: canvasState, created_at: "2026-08-03T08:00:00.000Z", current_image_id: backgroundId,
|
|
images: [{ created_at: "2026-08-03T08:00:00.000Z", generation_id: "00000000-0000-4000-8000-000000000804", image_id: backgroundId }],
|
|
name: "普通贴纸目录人工检查", pixel_height: 1440, pixel_width: 1080, project_id: projectId, ratio: "3:4", state_version: stateVersion,
|
|
});
|
|
if (request.method === "PUT" && url.pathname === `/api/v1/projects/${projectId}/state`) {
|
|
void readJson(request).then((body) => { canvasState = body.canvas_state; stateVersion += 1; sendJson(response, { save_status: "saved", state_version: stateVersion }); }).catch(() => sendJson(response, { error: "invalid_state" }, 400));
|
|
return;
|
|
}
|
|
if (request.method === "GET" && url.pathname === `/api/v1/private-assets/projects/${projectId}/images/${backgroundId}`) return send(response, 200, backgroundSvg, "image/svg+xml");
|
|
const publicMatch = url.pathname.match(/^\/api\/v1\/assets\/public\/([^/]+)\/([^/]+)$/);
|
|
if (request.method === "GET" && publicMatch) {
|
|
const assetId = decodeURIComponent(publicMatch[2]);
|
|
const path = stickerPaths.get(assetId);
|
|
if (!path) return sendJson(response, { error: "not_found" }, 404);
|
|
return send(response, 200, readFileSync(path), "image/png");
|
|
}
|
|
next();
|
|
});
|
|
},
|
|
};
|
|
|
|
const vite = await createServer({ configFile: resolve("apps/web/vite.config.ts"), plugins: [mockApi], root: resolve("apps/web"), server: { host, port, strictPort: true } });
|
|
await vite.listen();
|
|
console.log(`WP5-02 manual preview: http://${host}:${port}/app/projects/${projectId}/editor`);
|
|
for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => { void vite.close().finally(() => process.exit(0)); });
|