Files
netrunner-landing/scripts/seed-docs.mjs
T
nineap f02124eb1d Наполнить /docs реальным контентом вместо визуальной заглушки
Раздел документации на сайте (documents_ru/documents_en в PocketBase)
содержал только два обрубленных стаб-документа. Добавлен полный набор
из 12 документов на русском и английском (Core/Security/Network/Legal),
технически сверенных с реальной реализацией протокола (NRXP, ChaCha20-
Poly1305, X25519, TLS-маскировка под JA3/JA4) и с моделью сессий
(HttpOnly-cookie, ротация refresh-токенов) — не маркетинговые обещания,
а описание того, что фактически работает в коде.

Юридические документы (Privacy/Terms/Refund) содержат явные плейсхолдеры
для реквизитов оператора сервиса — сервис ещё не зарегистрирован ни в
одной юрисдикции, поэтому не полагаться на них как на итоговый текст
без замены плейсхолдеров.

scripts/seed-docs.mjs — идемпотентный скрипт наполнения PocketBase
(upsert по title, с alias-картой под старые названия стабов); ничего не
записывает без --apply и без PB_ADMIN_EMAIL/PB_ADMIN_PASSWORD в
окружении — админ-доступ к CMS нигде не хардкожен.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 20:25:10 +07:00

98 lines
3.9 KiB
JavaScript

// Наполняет коллекции `documents_ru`/`documents_en` в PocketBase реальным
// контентом раздела /docs (сейчас там только два "заглушечных" документа с
// обрубленным текстом — этот скрипт заменяет их полным набором и добавляет
// остальные документы).
//
// Не хранит и не запрашивает секреты нигде, кроме переменных окружения самого
// оператора — админ-доступ к PocketBase не должен попадать ни в код, ни в чат.
//
// Запуск:
// PB_URL=https://netrunner-vpn.com/cms-api \
// PB_ADMIN_EMAIL=you@example.com \
// PB_ADMIN_PASSWORD='...' \
// node scripts/seed-docs.mjs [--lang=ru|en|all] [--apply]
//
// По умолчанию — dry-run для обоих языков (только печатает, что будет
// сделано). Чтобы реально записать в PocketBase, добавь флаг --apply.
import PocketBase from "pocketbase";
import { DOCS_RU } from "./docs-content.ru.mjs";
import { DOCS_EN } from "./docs-content.en.mjs";
const PB_URL = process.env.PB_URL || "https://netrunner-vpn.com/cms-api";
const APPLY = process.argv.includes("--apply");
const langArg = process.argv.find((a) => a.startsWith("--lang="));
const LANGS = langArg
? langArg.split("=")[1] === "all"
? ["ru", "en"]
: [langArg.split("=")[1]]
: ["ru", "en"];
// Старые "заглушечные" записи в проде названы иначе, чем новые полноценные
// документы, которые их заменяют, — без этой карты скрипт создал бы дубликаты
// вместо замены обрубленных стаб-текстов.
const LEGACY_TITLE_ALIASES = {
ru: {
"Политика конфиденциальности": "Политика конфиденциальности (Privacy Policy)",
"Условия использования": "Условия использования и оплаты (Terms of Use)",
},
en: {
"Privacy Policy": "Privacy Policy",
"Terms of Use": "Terms of Use & Payment",
},
};
const DOCS_BY_LANG = { ru: DOCS_RU, en: DOCS_EN };
async function seedLang(pb, lang) {
const docs = DOCS_BY_LANG[lang];
const aliases = LEGACY_TITLE_ALIASES[lang];
const collection = pb.collection(`documents_${lang}`);
const existing = await collection.getFullList({ requestKey: null });
const byTitle = new Map(existing.map((r) => [r.title, r]));
console.log(`\n=== documents_${lang} ===`);
for (const doc of docs) {
const match = byTitle.get(doc.title) || byTitle.get(aliases[doc.title]);
if (match) {
console.log(`UPDATE "${doc.title}" (id=${match.id})`);
if (APPLY) await collection.update(match.id, doc);
} else {
console.log(`CREATE "${doc.title}"`);
if (APPLY) await collection.create(doc);
}
}
console.log(`Всего документов: ${docs.length}`);
}
async function main() {
const pb = new PocketBase(PB_URL);
if (APPLY) {
const email = process.env.PB_ADMIN_EMAIL;
const password = process.env.PB_ADMIN_PASSWORD;
if (!email || !password) {
console.error(
"Нужны PB_ADMIN_EMAIL и PB_ADMIN_PASSWORD в окружении для записи (--apply).",
);
process.exit(1);
}
await pb.collection("_superusers").authWithPassword(email, password);
} else {
console.log(
"[dry-run] Ничего не записываю. Проверь вывод ниже, затем перезапусти с --apply.",
);
}
for (const lang of LANGS) {
await seedLang(pb, lang);
}
if (!APPLY) console.log("\nЭто был dry-run — добавь --apply, чтобы записать.");
}
main().catch((err) => {
console.error(err);
process.exit(1);
});