@webnumseoagent/next 0.7.3 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +6 -0
  2. package/bin/cli.mjs +35 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -105,6 +105,12 @@ Vercel и `git push`. **Проверь `git diff`** перед коммитом
105
105
  контент = git-коммит → редеплой пересобирает страницы.
106
106
  - Тема оформления (фирменный цвет) и канонический URL-префикс берутся из `content/blog/.blogfs.json`.
107
107
  - Sitemap блога добавляется автоматически (раздел `sitemap/blog.xml`).
108
+ - Роуты карты сайта/`robots`/merchant — `force-dynamic` (не `revalidate`): статический путь Vercel
109
+ пре-рендерит на сборке и раздаёт из edge-кэша, из-за чего при смене данных на платформе (напр. появился
110
+ блог) индекс `/sitemap.xml` «застревает» и не обновляется, а `revalidateTag` пре-рендер не сбрасывает.
111
+ `force-dynamic` убирает пре-рендер; внутренний fetch к платформе остаётся кэшированным (300с + тег
112
+ `seo-<SITE>`), поэтому нагрузка почти не растёт. `init`/`blog` проставляют это идемпотентно (и на
113
+ авто-обновлении), так что старые сайты чинятся сами.
108
114
  - `init`/`blog` **сами** прописывают в `next.config` `outputFileTracingIncludes` для `content/blog` —
109
115
  без этого на Vercel файлы блога не попадают в serverless-бандл, и рантайм-чтение (ISR-ревалидация
110
116
  страниц + route-handler карты сайта) находит пусто → блог исчезает с сайта и из sitemap. Идемпотентно;
package/bin/cli.mjs CHANGED
@@ -143,6 +143,35 @@ async function ensureContentTracing(contentDir = "content/blog") {
143
143
  ok(`${rel} (outputFileTracingIncludes → content/blog в бандле)`);
144
144
  }
145
145
 
146
+ // Делает наши платформенные роуты ДИНАМИЧЕСКИМИ (force-dynamic) вместо ISR (revalidate 300).
147
+ // ЗАЧЕМ: /sitemap.xml (и robots/merchant) — статический путь, Vercel пре-рендерит его на сборке и
148
+ // раздаёт из edge-кэша. При смене данных на платформе (напр. появился блог) такой роут «застревает»:
149
+ // фоновая ре-валидация ненадёжна, а revalidateTag пре-рендер не сбрасывает — и карта отдаёт старое,
150
+ // пока сайт не пересоберут. force-dynamic убирает пре-рендер: роут исполняется на каждый запрос и всегда
151
+ // отражает платформу (внутренний fetch остаётся кэшированным на 300с + тег seo-<SITE>, так что нагрузка
152
+ // почти не растёт, а сброс по revalidateTag работает мгновенно). Идемпотентно; правит ТОЛЬКО наши роуты.
153
+ // Запускается и на self-update (`npx … blog --force`) — поэтому чинит все сайты сам, без разработчика.
154
+ async function ensureDynamicRoutes(appDir) {
155
+ const ext = (await exists(path.join(root, "tsconfig.json"))) ? "ts" : "js";
156
+ const targets = [
157
+ `sitemap.xml/route.${ext}`,
158
+ `sitemap/[name]/route.${ext}`,
159
+ `robots.txt/route.${ext}`,
160
+ `seoagent-merchant-feed.xml/route.${ext}`,
161
+ ];
162
+ for (const rel of targets) {
163
+ const p = path.join(root, appDir, rel);
164
+ const src = await fs.readFile(p, "utf8").catch(() => null);
165
+ if (src == null) continue;
166
+ if (!/seoSitemapXml|seoWrapSitemap|seoRobotsTxt|seoMerchantFeedXml/.test(src)) continue; // не наш роут
167
+ if (/dynamic\s*=\s*["']force-dynamic["']/.test(src)) { skip(`${appDir}/${rel} — уже force-dynamic`); continue; }
168
+ const patched = src.replace(/export const revalidate\s*=\s*300\s*;?/, 'export const dynamic = "force-dynamic";');
169
+ if (patched === src) continue; // нет revalidate=300 — незнакомая форма, не трогаем
170
+ await fs.writeFile(p, patched);
171
+ ok(`${appDir}/${rel} → force-dynamic (не застревает в edge-кэше Vercel)`);
172
+ }
173
+ }
174
+
146
175
  async function init() {
147
176
  log("\n\x1b[1m@webnumseoagent/next — установка\x1b[0m\n");
148
177
  // Проверяем чистоту git ДО создания файлов (чтобы весь дифф установки был обозрим).
@@ -486,6 +515,9 @@ async function init() {
486
515
  await ensureContentTracing();
487
516
  }
488
517
 
518
+ // Наши sitemap/robots/merchant-роуты → force-dynamic (не застревают в edge-кэше Vercel).
519
+ await ensureDynamicRoutes(appDir);
520
+
489
521
  log("\n\x1b[1mЗатем:\x1b[0m задай эти же env-переменные в Vercel (Settings → Environment Variables) и сделай git push.\n");
490
522
  }
491
523
 
@@ -779,6 +811,9 @@ async function blogPage() {
779
811
  // Файлы блога должны попасть в serverless-бандл Vercel (ISR-ревалидация + карта сайта читают их в
780
812
  // рантайме). Идемпотентно — запускается и на self-update (`npx … blog --force`), авто-чиня сайт.
781
813
  await ensureContentTracing();
814
+ // Наши sitemap/robots/merchant-роуты → force-dynamic (иначе индекс карты застревает в кэше Vercel).
815
+ // Тоже гоняется на self-update — фикс сам доезжает до всех сайтов без правок разработчика.
816
+ await ensureDynamicRoutes(appDir);
782
817
 
783
818
  log(`\n \x1b[32m✓\x1b[0m Готово. Проверь \x1b[36mgit diff\x1b[0m, затем commit + push. Блог: \x1b[1m${localeDir ? `/${param}/blog` : "/blog"}\x1b[0m — дизайн/шапка с сайта, список 4-в-ряд, статический рендер из файлов.\n`);
784
819
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webnumseoagent/next",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Runtime SEO adapter + installer for Next.js App Router sites (SEO Agent platform)",
5
5
  "main": "dist/client.js",
6
6
  "types": "dist/client.d.ts",