From 653a31ce631a311170341384151154fd9be4fbd7 Mon Sep 17 00:00:00 2001 From: ISA Date: Thu, 4 Sep 2025 10:54:37 +0200 Subject: [PATCH] feat: local-cpl-sim.mjs --- .env.development | 2 +- .env.production | 2 +- CHANGELOG.md | 5 ++ package-lock.json | 4 +- package.json | 3 +- scripts/local-cpl-sim.mjs | 137 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 scripts/local-cpl-sim.mjs diff --git a/.env.development b/.env.development index 60804eb..a304b44 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.832 +NEXT_PUBLIC_APP_VERSION=1.6.833 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index f45a01d..93ceb9c 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.832 +NEXT_PUBLIC_APP_VERSION=1.6.833 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 34181c5..c596ac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [1.6.833] – 2025-09-04 + +- test: npx playwright test erfolgreich + +--- ## [1.6.832] – 2025-09-03 - refactoring: test files diff --git a/package-lock.json b/package-lock.json index f1e461a..7fece6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.832", + "version": "1.6.833", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.832", + "version": "1.6.833", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", diff --git a/package.json b/package.json index 2732aef..6684f22 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "cpl-v4", - "version": "1.6.832", + "version": "1.6.833", "private": true, "scripts": { "dev": "next dev -p 3000", "clean": "rimraf .next out", "build": "npm run clean && cross-env EXPORT_STATIC=true next build", "postbuild": "copy LICENSE_ICONIFY.txt out\\LICENSE_ICONIFY.txt", + "serve:sim": "node ./scripts/local-cpl-sim.mjs", "start": "next start", "typecheck": "tsc --noEmit", "check": "npm run lint && npm run typecheck", diff --git a/scripts/local-cpl-sim.mjs b/scripts/local-cpl-sim.mjs new file mode 100644 index 0000000..f142bdc --- /dev/null +++ b/scripts/local-cpl-sim.mjs @@ -0,0 +1,137 @@ +// Minimal local simulator for testing SAN01 replacement only. +// - Serves the exported "out" folder. +// - For text files (.html, .js, .json, .css, .txt) replaces <%=SAN01%> -> "ismail" on the fly. +// - Supports mapping /CPL?/path to /path in the export. + +import http from "http"; +import fs from "fs"; +import path from "path"; + +const PORT = process.env.PORT ? Number(process.env.PORT) : 3030; +const ROOT = path.join(process.cwd(), "out"); + +function exists(p) { + try { + fs.accessSync(p, fs.constants.F_OK); + return true; + } catch { + return false; + } +} + +function contentTypeByExt(ext) { + switch (ext) { + case ".html": + return "text/html; charset=utf-8"; + case ".js": + return "application/javascript; charset=utf-8"; + case ".json": + return "application/json; charset=utf-8"; + case ".css": + return "text/css; charset=utf-8"; + case ".txt": + return "text/plain; charset=utf-8"; + case ".svg": + return "image/svg+xml"; + case ".png": + return "image/png"; + case ".jpg": + case ".jpeg": + return "image/jpeg"; + case ".ico": + return "image/x-icon"; + default: + return "application/octet-stream"; + } +} + +function isTextExt(ext) { + return [".html", ".js", ".json", ".css", ".txt", ".svg"].includes(ext); +} + +function sendFileWithSAN01Replace(res, filePath) { + const ext = path.extname(filePath).toLowerCase(); + const type = contentTypeByExt(ext); + if (isTextExt(ext)) { + try { + let content = fs.readFileSync(filePath, "utf8"); + content = content.replace(/<%=SAN01%>/g, "ismail"); + res.writeHead(200, { "Content-Type": type }); + res.end(content); + return; + } catch { + // fall through to stream as binary if read fails + } + } + res.writeHead(200, { "Content-Type": type }); + fs.createReadStream(filePath).pipe(res); +} + +function notFound(res) { + res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" }); + res.end("Not Found"); +} + +const server = http.createServer((req, res) => { + try { + const url = new URL(req.url, `http://localhost:${PORT}`); + const pathname = decodeURIComponent(url.pathname); + const rawQuery = req.url.includes("?") ? req.url.split("?")[1] : ""; + + // Minimal CPL? mapping: /CPL?/CPL/... -> /CPL/... + if (pathname === "/CPL" && rawQuery) { + const q = decodeURIComponent(rawQuery); + if (q.startsWith("/")) { + const rel = q.replace(/^\/+/, ""); + const target = path.join(ROOT, rel); + if (exists(target) && fs.statSync(target).isFile()) { + return sendFileWithSAN01Replace(res, target); + } + if (exists(target) && fs.statSync(target).isDirectory()) { + const indexFile = path.join(target, "index.html"); + if (exists(indexFile)) + return sendFileWithSAN01Replace(res, indexFile); + } + return notFound(res); + } + // Non-file commands: just 200 OK + res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" }); + res.end("OK"); + return; + } + + // Static serving from export + let filePath = path.join(ROOT, pathname); + + if (pathname.endsWith("/")) { + filePath = path.join(filePath, "index.html"); + if (exists(filePath)) return sendFileWithSAN01Replace(res, filePath); + } + + if (exists(filePath) && fs.statSync(filePath).isFile()) { + return sendFileWithSAN01Replace(res, filePath); + } + + const htmlVariant = filePath + ".html"; + if (exists(htmlVariant)) { + return sendFileWithSAN01Replace(res, htmlVariant); + } + + // Fallback: out/index.html + const fallback = path.join(ROOT, "index.html"); + if (exists(fallback)) return sendFileWithSAN01Replace(res, fallback); + + return notFound(res); + } catch (err) { + res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" }); + res.end( + "Internal Server Error\n" + (err && err.stack ? err.stack : String(err)) + ); + } +}); + +server.listen(PORT, () => { + console.log(`Local CPL simulator running on http://localhost:${PORT}`); + console.log(`Serving from: ${ROOT}`); + console.log("Replacing <%=SAN01%> -> ismail in text responses"); +});