Files
2026-08-01 14:01:17 +02:00

95 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
/*
* scripts/mirror-ee.js — runs at predev/prebuild.
*
* Next.js Pages Router only routes files physically inside pages/. Premium pages/APIs
* live in ee/pages/** so they can be stripped from the public build, but they must be
* COPIED into pages/** for Next to see them during dev/build in the private repo.
*
* This script copies ee/pages/** → pages/** and records every file it wrote in
* pages/.ee-mirror-manifest.json. It also writes a generated pages/.gitignore listing
* every mirrored path — git reads nested .gitignore files natively, so the copies are
* never tracked in either repo and pages/ stays clean in git. Source of truth is ee/pages.
*
* When ee/ is absent (public build), this is a no-op. See docs/OPEN_CORE.md.
*
* Everything else in ee/ (lib code) is imported in place via @/ee — NOT mirrored.
*/
const fs = require("fs");
const path = require("path");
const ROOT = path.resolve(__dirname, "..");
const EE_PAGES = path.join(ROOT, "ee", "pages");
const PAGES = path.join(ROOT, "pages");
const MANIFEST = path.join(PAGES, ".ee-mirror-manifest.json");
const NESTED_IGNORE = path.join(PAGES, ".gitignore");
function cleanPrevious() {
// Remove files written by a previous mirror run so renames/deletions in ee/pages
// don't leave stale routes behind.
if (!fs.existsSync(MANIFEST)) return;
try {
const prev = JSON.parse(fs.readFileSync(MANIFEST, "utf8"));
for (const rel of prev.files ?? []) {
const p = path.join(PAGES, rel);
if (fs.existsSync(p)) fs.rmSync(p);
}
fs.rmSync(MANIFEST);
if (fs.existsSync(NESTED_IGNORE)) fs.rmSync(NESTED_IGNORE);
} catch {
/* ignore a corrupt manifest — fresh mirror below overwrites cleanly */
}
}
function walk(dir, base = dir) {
const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const abs = path.join(dir, entry.name);
if (entry.isDirectory()) out.push(...walk(abs, base));
else out.push(path.relative(base, abs));
}
return out;
}
function main() {
cleanPrevious();
if (!fs.existsSync(EE_PAGES)) {
console.log("[mirror-ee] no ee/pages (public build or none yet) — nothing to mirror");
return;
}
const files = walk(EE_PAGES);
for (const rel of files) {
const src = path.join(EE_PAGES, rel);
const dst = path.join(PAGES, rel);
fs.mkdirSync(path.dirname(dst), { recursive: true });
fs.copyFileSync(src, dst);
}
fs.writeFileSync(
MANIFEST,
JSON.stringify({ generatedAt: new Date().toISOString(), files }, null, 2)
);
// Nested .gitignore so the mirrored copies are never tracked. Git reads this natively.
// Paths are POSIX-style and relative to pages/. The manifest + this file ignore themselves.
// IMPORTANT: gitignore treats [ ] * ? as glob metacharacters, so Next's dynamic-route
// segments like [replyId] must be backslash-escaped or the pattern won't match the literal
// directory (leaving the mirrored copy tracked). Escape them.
const esc = (p) => p.replace(/([[\]*?])/g, "\\$1");
const ignoreBody = [
"# GENERATED by scripts/mirror-ee.js — do not edit. Lists premium pages mirrored",
"# from ee/pages/. Source of truth is ee/pages/**. See docs/OPEN_CORE.md.",
".gitignore",
".ee-mirror-manifest.json",
...files.map((f) => "/" + esc(f.split(path.sep).join("/"))),
"",
].join("\n");
fs.writeFileSync(NESTED_IGNORE, ignoreBody);
console.log(`[mirror-ee] mirrored ${files.length} premium page(s) into pages/`);
}
main();