95 lines
3.4 KiB
JavaScript
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();
|