itube-specs 0.0.1003 → 0.0.1005

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.
@@ -0,0 +1,46 @@
1
+ # Что сделать в сайтах после обновления слоя
2
+
3
+ Только то, что каждый сайт должен сделать у себя после `npm run spec`: объявить новую сущность, поправить
4
+ свою логику, удалить файлы, переехавшие в слой. Описание изменений слоя — в истории git, не здесь.
5
+
6
+ Сайт после `npm run spec` видит записи между своей прошлой и новой версией:
7
+ `node node_modules/itube-specs/scripts/site-updates.mjs`.
8
+
9
+ Пишет тот, кто меняет слой, в том же коммите. Новые записи — сверху, в секцию `## Unreleased` (одна на все
10
+ коммиты до бампа); `npm run patch` сам проставит ей номер версии. Формат пункта: что сделать и где,
11
+ кому именно (всем / сайтам с N), что будет, если не сделать.
12
+
13
+ ## 0.0.1005 — 2026-10-06
14
+
15
+ - **Всем:** подключить этот файл к сайту, иначе пункты отсюда сайт не увидит.
16
+ - `package.json`, скрипт `spec`: дописать в конец
17
+ `&& (test ! -f node_modules/itube-specs/scripts/site-updates.mjs || node node_modules/itube-specs/scripts/site-updates.mjs)`.
18
+ Тогда `npm run spec` после установки печатает новые пункты и дописывает их в `SITE_TODO.md` в корне сайта —
19
+ файл остаётся, даже если `spec` запускал человек в своём терминале.
20
+ - `CLAUDE.md` сайта: правило «есть `SITE_TODO.md` — выполни пункты (или спроси пользователя, если нужен его
21
+ выбор), удали файл, коммит; меняешь слой сам — запись в `SITE_UPDATES.md` пишешь ты, см. `CLAUDE.md` слоя
22
+ § Site updates».
23
+ - Чтобы агент видел `SITE_TODO.md` без напоминаний — хук Claude Code `UserPromptSubmit`, который выводит этот
24
+ файл, если он есть (по желанию, настраивается у себя в `~/.claude/settings.json`).
25
+ - Пропустили прошлые версии — `node node_modules/itube-specs/scripts/site-updates.mjs <версия-до-обновления>`.
26
+
27
+ ## 0.0.1001 — 2026-10-06
28
+
29
+ - **Всем:** удалить свои `public/img/model-placeholder-{portrait,square}.{webp,avif}` и
30
+ `model-placeholder-female-*`, если есть. Заглушки моделей теперь в слое
31
+ (`public/img/model-placeholder/<niche>-<theme>-<shape>`), старые пути слой больше не запрашивает.
32
+ Свой вариант картинки — файлом с тем же новым путём в `public/` сайта.
33
+
34
+ ## 0.0.1000 — 2026-10-06
35
+
36
+ - **Сайтам с несколькими нишами, у которых ниша в URL не равна её коду** (`/gays` вместо `/gay`): одна
37
+ константа слагов → `nicheSlugs` в `app.config.ts` и `slugs` в `addNicheAliases` (`NEW_SITE_CHECKLIST.md` §3a).
38
+ Остальным — ничего.
39
+
40
+ ## 0.0.999 — 2026-10-06
41
+
42
+ - **Всем:** флага нет в `config/feature-flags.config.ts` — фича выключена, дефолтов у слоя нет. Перечислить
43
+ все флаги явно по карте в `NEW_SITE_CHECKLIST.md` §4. Заглушки без бекенда (`FeatureFollowEnabled`,
44
+ `FeatureHistoryEnabled`, `FeatureFavoritesEnabled`, `FeatureWatchLaterEnabled`, `FeatureLiveEnabled`) — на
45
+ боевом сайте включать только осознанно; при выключенном флаге их страницы отдают 404.
46
+ - **Всем:** `FeatureMomentsEnabled` и `SponsoredEnabled` слой не читает — можно убрать.
package/config/niches.ts CHANGED
@@ -78,7 +78,7 @@ function isUnderRoot(path: string, roots: readonly string[]): boolean {
78
78
  }
79
79
 
80
80
  /**
81
- * Клонирует контентные разделы под нишевые префиксы — алиасом той же записи роута:
81
+ * Клонирует Контентные разделы под нишевые префиксы — алиасом той же записи роута:
82
82
  * `/videos/:slug` начинает отвечать и на `/gay/videos/:slug`. Алиасы статичные, по одному на нишу:
83
83
  * у алиаса vue-router требует те же параметры, что у оригинала, поэтому параметр `:niche` сюда нельзя.
84
84
  * Сайту с одной нишей ничего не добавляет. Мутирует переданный список — так устроен хук `pages:extend`.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.1003",
4
+ "version": "0.0.1005",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
8
8
  "prepublishOnly": "npm install && npx nuxi prepare",
9
9
  "patch": "npm version patch",
10
+ "version": "node scripts/site-updates-release.mjs && git add SITE_UPDATES.md",
10
11
  "lint": "eslint . --max-warnings=0",
11
12
  "lint:fix": "eslint . --fix",
12
13
  "lint:css": "stylelint \"**/*.{scss,vue}\" --max-warnings=0 --allow-empty-input",
@@ -80,6 +81,8 @@
80
81
  "i18n/locales/",
81
82
  "scripts/i18n-check.mjs",
82
83
  "scripts/i18n-sheet.mjs",
84
+ "scripts/site-updates.mjs",
85
+ "SITE_UPDATES.md",
83
86
  "nuxt.config.ts",
84
87
  "DOCS/"
85
88
  ],
@@ -0,0 +1,57 @@
1
+ // Для сайта, после `npm run spec`: печатает записи SITE_UPDATES.md слоя, вышедшие после версии,
2
+ // которая стояла в закоммиченном package.json сайта, и дописывает их в SITE_TODO.md сайта.
3
+ // Запуск из корня сайта.
4
+ // Явно: `node node_modules/itube-specs/scripts/site-updates.mjs <старая-версия>`.
5
+
6
+ import { execSync } from 'node:child_process';
7
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
8
+
9
+ const FILE = 'node_modules/itube-specs/SITE_UPDATES.md';
10
+ const TODO_FILE = 'SITE_TODO.md';
11
+ const TODO_HEADER = '# Пункты слоя, которые этот сайт ещё не выполнил\n\nИз `itube-specs/SITE_UPDATES.md`. Выполнил всё — удали файл.';
12
+
13
+ const toParts = version => version.replace(/^[^\d]*/, '').split('.').map(Number);
14
+ const isNewer = (a, b) => {
15
+ const [x, y] = [toParts(a), toParts(b)];
16
+ for (let i = 0; i < 3; i++) if ((x[i] || 0) !== (y[i] || 0)) return (x[i] || 0) > (y[i] || 0);
17
+ return false;
18
+ };
19
+
20
+ function previousVersion() {
21
+ if (process.argv[2]) return process.argv[2];
22
+ try {
23
+ const pkg = JSON.parse(execSync('git show HEAD:package.json', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }));
24
+ return pkg.dependencies?.['itube-specs'] || pkg.devDependencies?.['itube-specs'] || '';
25
+ }
26
+ catch {
27
+ return '';
28
+ }
29
+ }
30
+
31
+ if (!existsSync(FILE)) process.exit(0);
32
+
33
+ const from = previousVersion();
34
+ const installed = JSON.parse(readFileSync('node_modules/itube-specs/package.json', 'utf8')).version;
35
+
36
+ const sections = readFileSync(FILE, 'utf8').split(/^(?=## )/m).filter(part => part.startsWith('## '));
37
+ const pending = sections.filter((section) => {
38
+ const version = section.match(/^## (\d+\.\d+\.\d+)/)?.[1];
39
+ return version && (!from || isNewer(version, from)) && !isNewer(version, installed);
40
+ });
41
+
42
+ if (!pending.length) {
43
+ console.log(`site-updates: ${from || '?'} → ${installed}, действий для сайта нет.`);
44
+ process.exit(0);
45
+ }
46
+
47
+ const items = pending.reverse().map(section => section.trim());
48
+
49
+ // Файл в корне сайта — пункты не теряются, кто бы ни запускал spec; хук агента подхватывает его
50
+ // в контекст, выполненное агент удаляет вместе с файлом.
51
+ const existing = existsSync(TODO_FILE) ? readFileSync(TODO_FILE, 'utf8') : `${TODO_HEADER}\n`;
52
+ const fresh = items.filter(item => !existing.includes(item.split('\n')[0]));
53
+ if (fresh.length) writeFileSync(TODO_FILE, `${existing.trimEnd()}\n\n${fresh.join('\n\n')}\n`);
54
+
55
+ console.log(`\nsite-updates: ${from || '?'} → ${installed}. Что сделать в этом сайте (от старых к новым), записано в ${TODO_FILE}:\n`);
56
+ console.log(items.join('\n\n'));
57
+ console.log('');