core-maugli 1.2.66 → 1.2.67
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.
- package/package.json +1 -1
- package/scripts/update-components.js +39 -0
- package/src/middleware.ts +21 -0
- package/src/pages/[...id].astro +8 -0
- package/src/pages/sw.js.astro +8 -0
- package/scripts/check-version-old.js +0 -346
- package/scripts/copy-content-images.cjs +0 -66
- package/scripts/copy-netlify-config-simple.js +0 -58
- package/scripts/generate-previews-build.js +0 -104
- package/scripts/test-package-update.js +0 -64
- package/scripts/test-version-update.js +0 -54
package/package.json
CHANGED
|
@@ -119,6 +119,9 @@ async function updateConfigVersion() {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// Создаем файл sw.js.astro для исправления PWA маршрутизации
|
|
123
|
+
await createPWAServiceWorkerFile();
|
|
124
|
+
|
|
122
125
|
if (updated) {
|
|
123
126
|
await fs.writeFile(userPackageJsonPath, JSON.stringify(userPackageData, null, 2) + '\n', 'utf-8');
|
|
124
127
|
console.log(`📦 Updated package.json with version ^${newVersion}`);
|
|
@@ -137,6 +140,42 @@ async function updateConfigVersion() {
|
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
async function createPWAServiceWorkerFile() {
|
|
144
|
+
try {
|
|
145
|
+
const swPath = path.join(userRoot, 'src/pages/sw.js.astro');
|
|
146
|
+
|
|
147
|
+
// Проверяем, существует ли уже файл
|
|
148
|
+
try {
|
|
149
|
+
await fs.stat(swPath);
|
|
150
|
+
console.log('🔧 PWA service worker file already exists, skipping...');
|
|
151
|
+
return;
|
|
152
|
+
} catch {
|
|
153
|
+
// Файл не существует, создаем его
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const swContent = `---
|
|
157
|
+
// Astro page для обработки service worker запросов PWA
|
|
158
|
+
// Это исправляет предупреждения маршрутизации в dev режиме
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
<script>
|
|
162
|
+
// Перенаправляем на актуальный service worker
|
|
163
|
+
if (typeof window !== 'undefined') {
|
|
164
|
+
window.location.href = '/dev-dist/sw.js';
|
|
165
|
+
}
|
|
166
|
+
</script>`;
|
|
167
|
+
|
|
168
|
+
// Создаем папку если её нет
|
|
169
|
+
await fs.mkdir(path.dirname(swPath), { recursive: true });
|
|
170
|
+
|
|
171
|
+
// Создаем файл
|
|
172
|
+
await fs.writeFile(swPath, swContent, 'utf-8');
|
|
173
|
+
console.log('🔧 Created PWA service worker file: src/pages/sw.js.astro');
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.warn('Warning: Could not create PWA service worker file:', error.message);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
140
179
|
async function copyDirectory(src, dest) {
|
|
141
180
|
try {
|
|
142
181
|
await fs.mkdir(dest, { recursive: true });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineMiddleware } from 'astro:middleware';
|
|
2
|
+
|
|
3
|
+
export const onRequest = defineMiddleware(async (context, next) => {
|
|
4
|
+
// Список системных файлов PWA, которые не должны обрабатываться динамическими маршрутами
|
|
5
|
+
const pwaFiles = [
|
|
6
|
+
'/sw.js',
|
|
7
|
+
'/manifest.json',
|
|
8
|
+
'/manifest.webmanifest',
|
|
9
|
+
'/workbox-',
|
|
10
|
+
'/service-worker.js'
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// Проверяем, является ли запрос системным файлом PWA
|
|
14
|
+
if (pwaFiles.some(file => context.url.pathname.startsWith(file))) {
|
|
15
|
+
// Если это системный файл, пропускаем обработку Astro и позволяем Vite/PWA плагину обработать его
|
|
16
|
+
return next();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Для всех остальных запросов продолжаем обычную обработку
|
|
20
|
+
return next();
|
|
21
|
+
});
|
package/src/pages/[...id].astro
CHANGED
|
@@ -7,6 +7,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
|
|
7
7
|
|
|
8
8
|
export async function getStaticPaths() {
|
|
9
9
|
const pages = await getCollection('pages');
|
|
10
|
+
|
|
10
11
|
return pages.map((page) => {
|
|
11
12
|
return {
|
|
12
13
|
params: { id: page.id },
|
|
@@ -18,6 +19,13 @@ export async function getStaticPaths() {
|
|
|
18
19
|
type Props = { page: CollectionEntry<'pages'> };
|
|
19
20
|
|
|
20
21
|
const { page } = Astro.props;
|
|
22
|
+
|
|
23
|
+
// Блокируем обработку системных файлов PWA
|
|
24
|
+
const pwaFiles = ['sw.js', 'manifest.json', 'workbox-', 'service-worker.js'];
|
|
25
|
+
if (pwaFiles.some(file => Astro.url.pathname.includes(file))) {
|
|
26
|
+
return new Response(null, { status: 404 });
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
const { title, seo } = page.data;
|
|
22
30
|
const { Content } = await render(page);
|
|
23
31
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Этот файл блокирует обработку /sw.js через динамический маршрут [...]
|
|
3
|
+
// Фактический service worker генерируется VitePWA плагином
|
|
4
|
+
---
|
|
5
|
+
<script>
|
|
6
|
+
// Redirect to actual service worker generated by VitePWA
|
|
7
|
+
window.location.href = '/dev-dist/sw.js';
|
|
8
|
+
</script>
|
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { execSync } from 'child_process';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
|
|
11
|
-
// Colors for console output
|
|
12
|
-
const colors = {
|
|
13
|
-
red: '\x1b[31m',
|
|
14
|
-
green: '\x1b[32m',
|
|
15
|
-
yellow: '\x1b[33m',
|
|
16
|
-
blue: '\x1b[34m',
|
|
17
|
-
magenta: '\x1b[35m',
|
|
18
|
-
cyan: '\x1b[36m',
|
|
19
|
-
white: '\x1b[37m',
|
|
20
|
-
reset: '\x1b[0m',
|
|
21
|
-
bold: '\x1b[1m'
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function colorize(text, color) {
|
|
25
|
-
return `${colors[color]}${text}${colors.reset}`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Handle CLI arguments and environment variables first
|
|
29
|
-
const args = process.argv.slice(2);
|
|
30
|
-
if (args.includes('--skip-check') ||
|
|
31
|
-
process.env.SKIP_VERSION_CHECK === 'true' ||
|
|
32
|
-
process.env.DISABLE_AUTO_UPDATE === 'true') {
|
|
33
|
-
console.log(colorize('⏭️ Version check skipped', 'yellow'));
|
|
34
|
-
process.exit(0);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function getMaugliConfig() {
|
|
38
|
-
try {
|
|
39
|
-
const configPath = path.join(process.cwd(), 'src/config/maugli.config.ts');
|
|
40
|
-
if (!fs.existsSync(configPath)) {
|
|
41
|
-
console.log(colorize('⚠️ maugli.config.ts not found at src/config/maugli.config.ts', 'yellow'));
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Простое чтение конфига через регулярные выражения
|
|
46
|
-
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
47
|
-
console.log(colorize('🔍 Reading maugli.config.ts...', 'cyan'));
|
|
48
|
-
|
|
49
|
-
// Убираем комментарии и лишние пробелы для более точного парсинга
|
|
50
|
-
const cleanContent = configContent
|
|
51
|
-
.replace(/\/\*[\s\S]*?\*\//g, '') // убираем /* */ комментарии
|
|
52
|
-
.replace(/\/\/.*$/gm, '') // убираем // комментарии
|
|
53
|
-
.replace(/\s+/g, ' '); // заменяем множественные пробелы на одинарные
|
|
54
|
-
|
|
55
|
-
// Ищем forceUpdate разными способами
|
|
56
|
-
let forceUpdate = false;
|
|
57
|
-
|
|
58
|
-
// Способ 1: В секции automation
|
|
59
|
-
const automationMatch = cleanContent.match(/automation\s*:\s*\{([^}]*)\}/);
|
|
60
|
-
if (automationMatch) {
|
|
61
|
-
const automationSection = automationMatch[1];
|
|
62
|
-
const forceUpdateMatch = automationSection.match(/forceUpdate\s*:\s*(true|false)/);
|
|
63
|
-
if (forceUpdateMatch) {
|
|
64
|
-
forceUpdate = forceUpdateMatch[1] === 'true';
|
|
65
|
-
console.log(colorize(`📋 Found in automation section - forceUpdate: ${forceUpdate}`, 'cyan'));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Способ 2: Прямой поиск forceUpdate в файле (fallback)
|
|
70
|
-
if (!automationMatch) {
|
|
71
|
-
const directMatch = cleanContent.match(/forceUpdate\s*:\s*(true|false)/);
|
|
72
|
-
if (directMatch) {
|
|
73
|
-
forceUpdate = directMatch[1] === 'true';
|
|
74
|
-
console.log(colorize(`📋 Found direct forceUpdate - value: ${forceUpdate}`, 'cyan'));
|
|
75
|
-
} else {
|
|
76
|
-
console.log(colorize('⚠️ No forceUpdate setting found in config', 'yellow'));
|
|
77
|
-
console.log(colorize('� Make sure your config has: automation: { forceUpdate: true }', 'cyan'));
|
|
78
|
-
|
|
79
|
-
// Показываем часть конфига для диагностики
|
|
80
|
-
const configSnippet = configContent.slice(0, 200).replace(/\n/g, '\\n');
|
|
81
|
-
console.log(colorize(`🔍 Config preview: ${configSnippet}...`, 'gray'));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
automation: {
|
|
87
|
-
forceUpdate: forceUpdate
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.warn(colorize('⚠️ Could not read maugli.config.ts: ' + error.message, 'yellow'));
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async function getCurrentVersion() {
|
|
97
|
-
try {
|
|
98
|
-
const packagePath = path.join(process.cwd(), 'package.json');
|
|
99
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
100
|
-
return packageJson.dependencies?.['core-maugli'] || packageJson.version;
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.warn(colorize('⚠️ Could not read package.json', 'yellow'));
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function getLatestVersion() {
|
|
108
|
-
try {
|
|
109
|
-
const result = execSync('npm view core-maugli version', { encoding: 'utf8' });
|
|
110
|
-
return result.trim();
|
|
111
|
-
} catch (error) {
|
|
112
|
-
console.warn(colorize('⚠️ Could not fetch latest version from npm', 'yellow'));
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isCriticalUpdate(current, latest) {
|
|
118
|
-
// Определяем критические обновления (major version или серьезные security fixes)
|
|
119
|
-
const currentParts = current.replace(/^[\^~]/, '').split('.').map(Number);
|
|
120
|
-
const latestParts = latest.split('.').map(Number);
|
|
121
|
-
|
|
122
|
-
// Разница в major версии - критическое обновление
|
|
123
|
-
if (latestParts[0] > currentParts[0]) return true;
|
|
124
|
-
|
|
125
|
-
// Разница в minor версии больше 2 - критическое
|
|
126
|
-
if (latestParts[1] - currentParts[1] > 2) return true;
|
|
127
|
-
|
|
128
|
-
// Разница в patch версии больше 10 - критическое
|
|
129
|
-
if (latestParts[1] === currentParts[1] && latestParts[2] - currentParts[2] > 10) return true;
|
|
130
|
-
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function compareVersions(current, latest) {
|
|
135
|
-
if (!current || !latest) return false;
|
|
136
|
-
|
|
137
|
-
// Remove ^ or ~ from version if present
|
|
138
|
-
current = current.replace(/^[\^~]/, '');
|
|
139
|
-
|
|
140
|
-
const currentParts = current.split('.').map(Number);
|
|
141
|
-
const latestParts = latest.split('.').map(Number);
|
|
142
|
-
|
|
143
|
-
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
|
|
144
|
-
const currentPart = currentParts[i] || 0;
|
|
145
|
-
const latestPart = latestParts[i] || 0;
|
|
146
|
-
|
|
147
|
-
if (latestPart > currentPart) return true;
|
|
148
|
-
if (latestPart < currentPart) return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async function getUpdateContent(version) {
|
|
155
|
-
try {
|
|
156
|
-
// Try to get changelog or release notes
|
|
157
|
-
const result = execSync(`npm view core-maugli@${version} description`, { encoding: 'utf8' });
|
|
158
|
-
return result.trim();
|
|
159
|
-
} catch (error) {
|
|
160
|
-
return "New version available with improvements and bug fixes.";
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
async function promptUpdate() {
|
|
165
|
-
return new Promise((resolve) => {
|
|
166
|
-
// Check for CI/CD environments
|
|
167
|
-
const isCI = process.env.CI === 'true' ||
|
|
168
|
-
process.env.NETLIFY === 'true' ||
|
|
169
|
-
process.env.VERCEL === '1' ||
|
|
170
|
-
process.env.GITHUB_ACTIONS === 'true' ||
|
|
171
|
-
process.env.BUILD_ID || // Netlify
|
|
172
|
-
process.env.VERCEL_ENV || // Vercel
|
|
173
|
-
!process.stdin.isTTY; // Non-interactive terminal
|
|
174
|
-
|
|
175
|
-
if (isCI) {
|
|
176
|
-
console.log(colorize('\n🤖 CI/CD environment detected. Auto-updating...', 'cyan'));
|
|
177
|
-
resolve(true);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Simple input handling that works across all environments
|
|
182
|
-
process.stdin.resume();
|
|
183
|
-
process.stdin.setEncoding('utf8');
|
|
184
|
-
|
|
185
|
-
const handleInput = (data) => {
|
|
186
|
-
const input = data.toString().trim().toLowerCase();
|
|
187
|
-
process.stdin.pause();
|
|
188
|
-
process.stdin.removeListener('data', handleInput);
|
|
189
|
-
|
|
190
|
-
if (input === 'y' || input === 'yes' || input === '') {
|
|
191
|
-
resolve(true);
|
|
192
|
-
} else if (input === 'n' || input === 'no') {
|
|
193
|
-
resolve(false);
|
|
194
|
-
} else {
|
|
195
|
-
console.log(colorize('\nPlease enter Y for yes or N for no:', 'yellow'));
|
|
196
|
-
process.stdout.write(colorize('🔄 Would you like to update now? (Y/n): ', 'bold'));
|
|
197
|
-
process.stdin.resume();
|
|
198
|
-
process.stdin.once('data', handleInput);
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
process.stdin.once('data', handleInput);
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async function performUpdate() {
|
|
207
|
-
console.log(colorize('\n🔄 Updating core-maugli...', 'blue'));
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// Check if update script exists
|
|
211
|
-
const updateScriptPath = path.join(process.cwd(), 'scripts', 'update-all-blogs.js');
|
|
212
|
-
if (fs.existsSync(updateScriptPath)) {
|
|
213
|
-
console.log(colorize('📦 Running update script...', 'cyan'));
|
|
214
|
-
execSync(`node ${updateScriptPath} ${process.cwd()}`, { stdio: 'inherit' });
|
|
215
|
-
} else {
|
|
216
|
-
// Fallback to simple npm update
|
|
217
|
-
console.log(colorize('📦 Running npm update...', 'cyan'));
|
|
218
|
-
execSync('npm update core-maugli', { stdio: 'inherit' });
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
console.log(colorize('✅ Update completed successfully!', 'green'));
|
|
222
|
-
return true;
|
|
223
|
-
} catch (error) {
|
|
224
|
-
console.error(colorize('❌ Update failed:', 'red'), error.message);
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function main() {
|
|
230
|
-
console.log(colorize('\n🔍 Checking for core-maugli updates...', 'cyan'));
|
|
231
|
-
|
|
232
|
-
const currentVersion = await getCurrentVersion();
|
|
233
|
-
const latestVersion = await getLatestVersion();
|
|
234
|
-
const maugliConfig = await getMaugliConfig();
|
|
235
|
-
|
|
236
|
-
if (!currentVersion || !latestVersion) {
|
|
237
|
-
console.log(colorize('⚠️ Could not check version. Continuing with build...', 'yellow'));
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
console.log(colorize(`📦 Current version: ${currentVersion}`, 'white'));
|
|
242
|
-
console.log(colorize(`📦 Latest version: ${latestVersion}`, 'white'));
|
|
243
|
-
|
|
244
|
-
if (!compareVersions(currentVersion, latestVersion)) {
|
|
245
|
-
console.log(colorize('✅ You are using the latest version!', 'green'));
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// New version available
|
|
250
|
-
console.log(colorize('\n🎉 A new version of core-maugli is available!', 'magenta'));
|
|
251
|
-
console.log(colorize('═'.repeat(60), 'magenta'));
|
|
252
|
-
|
|
253
|
-
const updateContent = await getUpdateContent(latestVersion);
|
|
254
|
-
console.log(colorize(`\n📋 What's new in v${latestVersion}:`, 'bold'));
|
|
255
|
-
console.log(colorize(updateContent, 'white'));
|
|
256
|
-
|
|
257
|
-
console.log(colorize('\n🚀 New features include:', 'bold'));
|
|
258
|
-
console.log(colorize('• Enhanced image optimization pipeline', 'green'));
|
|
259
|
-
console.log(colorize('• Improved build performance', 'green'));
|
|
260
|
-
console.log(colorize('• Better asset management', 'green'));
|
|
261
|
-
console.log(colorize('• Centralized update system', 'green'));
|
|
262
|
-
console.log(colorize('• Bug fixes and stability improvements', 'green'));
|
|
263
|
-
|
|
264
|
-
console.log(colorize('\n💡 Benefits of updating:', 'bold'));
|
|
265
|
-
console.log(colorize('• Faster build times with flatten-images optimization', 'cyan'));
|
|
266
|
-
console.log(colorize('• Better Netlify compatibility', 'cyan'));
|
|
267
|
-
console.log(colorize('• Enhanced security and bug fixes', 'cyan'));
|
|
268
|
-
console.log(colorize('• Access to latest features and improvements', 'cyan'));
|
|
269
|
-
|
|
270
|
-
console.log(colorize('\n═'.repeat(60), 'magenta'));
|
|
271
|
-
|
|
272
|
-
// Проверяем, является ли обновление критическим
|
|
273
|
-
const isCritical = isCriticalUpdate(currentVersion, latestVersion);
|
|
274
|
-
|
|
275
|
-
if (isCritical) {
|
|
276
|
-
console.log(colorize(`\n🚨 CRITICAL UPDATE REQUIRED!`, 'red'));
|
|
277
|
-
console.log(colorize(`Your version (${currentVersion}) is significantly outdated.`, 'red'));
|
|
278
|
-
console.log(colorize('This update contains important security fixes and breaking changes.', 'red'));
|
|
279
|
-
console.log(colorize('Building with outdated version may cause errors.', 'red'));
|
|
280
|
-
} else {
|
|
281
|
-
console.log(colorize(`\n⚠️ Your current version (${currentVersion}) is outdated.`, 'yellow'));
|
|
282
|
-
console.log(colorize('To ensure optimal performance and security, updating is recommended.', 'yellow'));
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Check for CI/CD environments and forceUpdate setting
|
|
286
|
-
const isCI = process.env.CI === 'true' ||
|
|
287
|
-
process.env.NETLIFY === 'true' ||
|
|
288
|
-
process.env.VERCEL === '1' ||
|
|
289
|
-
process.env.GITHUB_ACTIONS === 'true' ||
|
|
290
|
-
process.env.BUILD_ID || // Netlify
|
|
291
|
-
process.env.VERCEL_ENV || // Vercel
|
|
292
|
-
!process.stdin.isTTY; // Non-interactive terminal
|
|
293
|
-
|
|
294
|
-
// Check forceUpdate setting from maugli.config.ts
|
|
295
|
-
const forceUpdate = maugliConfig?.automation?.forceUpdate || false;
|
|
296
|
-
|
|
297
|
-
console.log(colorize(`\n🔧 Configuration check:`, 'cyan'));
|
|
298
|
-
console.log(colorize(` • maugli.config.ts found: ${maugliConfig ? 'Yes' : 'No'}`, 'white'));
|
|
299
|
-
console.log(colorize(` • forceUpdate setting: ${forceUpdate}`, 'white'));
|
|
300
|
-
console.log(colorize(` • CI/CD detected: ${isCI}`, 'white'));
|
|
301
|
-
|
|
302
|
-
// Если конфиг не найден, предложим создать его
|
|
303
|
-
if (!maugliConfig) {
|
|
304
|
-
console.log(colorize('\n💡 To enable automatic updates, create src/config/maugli.config.ts with:', 'cyan'));
|
|
305
|
-
console.log(colorize(' automation: { forceUpdate: true }', 'white'));
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (isCI) {
|
|
309
|
-
console.log(colorize('\n🤖 CI/CD environment detected. Updating automatically...', 'cyan'));
|
|
310
|
-
const success = await performUpdate();
|
|
311
|
-
if (!success) {
|
|
312
|
-
console.log(colorize('\n❌ Auto-update failed in CI/CD environment. Build cancelled.', 'red'));
|
|
313
|
-
process.exit(1);
|
|
314
|
-
}
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (forceUpdate) {
|
|
319
|
-
console.log(colorize('\n🤖 Force update enabled in config. Updating automatically...', 'cyan'));
|
|
320
|
-
const success = await performUpdate();
|
|
321
|
-
if (!success) {
|
|
322
|
-
console.log(colorize('\n❌ Auto-update failed. Continuing with build...', 'yellow'));
|
|
323
|
-
}
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// If forceUpdate is false, show update notification without prompts
|
|
328
|
-
console.log(colorize('\n💡 To update core-maugli, run:', 'cyan'));
|
|
329
|
-
console.log(colorize(' npm run update', 'white'));
|
|
330
|
-
console.log(colorize(' # или', 'gray'));
|
|
331
|
-
console.log(colorize(' npm update core-maugli', 'white'));
|
|
332
|
-
|
|
333
|
-
if (isCritical) {
|
|
334
|
-
console.log(colorize('\n🚨 WARNING: This is a critical update!', 'red'));
|
|
335
|
-
console.log(colorize('Building with this version may cause errors.', 'red'));
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
console.log(colorize('\n✅ Proceeding with build...\n', 'green'));
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
main().catch(error => {
|
|
343
|
-
console.error(colorize('❌ Version check failed:', 'red'), error.message);
|
|
344
|
-
console.log(colorize('⚠️ Continuing with build...', 'yellow'));
|
|
345
|
-
process.exit(0);
|
|
346
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// copy-content-images.cjs - Move all images from public/img subfolders to public/img root
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const sourceDir = './public/img';
|
|
6
|
-
const targetDir = './public/img';
|
|
7
|
-
|
|
8
|
-
// Function to recursively find and copy images from subfolders
|
|
9
|
-
async function flattenImages(sourceDir, targetDir) {
|
|
10
|
-
if (!fs.existsSync(sourceDir)) {
|
|
11
|
-
console.log(`📁 Folder ${sourceDir} does not exist, skipping`);
|
|
12
|
-
return 0;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const items = fs.readdirSync(sourceDir);
|
|
16
|
-
let copiedCount = 0;
|
|
17
|
-
|
|
18
|
-
for (const item of items) {
|
|
19
|
-
const sourcePath = path.join(sourceDir, item);
|
|
20
|
-
const stat = fs.statSync(sourcePath);
|
|
21
|
-
|
|
22
|
-
if (stat.isDirectory()) {
|
|
23
|
-
// Recursively process subfolders
|
|
24
|
-
const copied = await flattenImages(sourcePath, targetDir);
|
|
25
|
-
copiedCount += copied;
|
|
26
|
-
} else if (stat.isFile()) {
|
|
27
|
-
const ext = path.extname(item).toLowerCase();
|
|
28
|
-
|
|
29
|
-
// Check if it's an image and it's in a subfolder (not in root)
|
|
30
|
-
if (['.jpg', '.jpeg', '.png', '.webp', '.gif', '.svg'].includes(ext)) {
|
|
31
|
-
const relativePath = path.relative(sourceDir, sourcePath);
|
|
32
|
-
|
|
33
|
-
// If file is not in public/img root, copy it to root
|
|
34
|
-
if (relativePath.includes(path.sep)) {
|
|
35
|
-
const targetPath = path.join(targetDir, item);
|
|
36
|
-
|
|
37
|
-
// Check that file with this name doesn't exist in root
|
|
38
|
-
if (!fs.existsSync(targetPath)) {
|
|
39
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
40
|
-
console.log(`📋 Moved: ${relativePath} → ${item}`);
|
|
41
|
-
copiedCount++;
|
|
42
|
-
} else {
|
|
43
|
-
console.log(`⚠️ Skipped (already exists): ${item}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return copiedCount;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function main() {
|
|
54
|
-
console.log('🚀 Starting image flattening from public/img subfolders to public/img root...');
|
|
55
|
-
|
|
56
|
-
// Move all images from subfolders to root
|
|
57
|
-
const totalCopied = await flattenImages(sourceDir, targetDir);
|
|
58
|
-
|
|
59
|
-
console.log('');
|
|
60
|
-
console.log(`✅ Flattening completed! Copied ${totalCopied} images to public/img/ root`);
|
|
61
|
-
console.log('🔄 Netlify Image Optimization can now process them more easily');
|
|
62
|
-
console.log('⚡ Sharp optimization will also be applied to files in root');
|
|
63
|
-
console.log('📁 All images are now available directly from /img/filename.webp');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
main().catch(console.error);
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Простое копирование netlify.toml из пакета core-maugli
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import { fileURLToPath } from 'url';
|
|
10
|
-
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const __dirname = path.dirname(__filename);
|
|
13
|
-
|
|
14
|
-
function main() {
|
|
15
|
-
try {
|
|
16
|
-
const targetPath = path.join(process.cwd(), 'netlify.toml');
|
|
17
|
-
|
|
18
|
-
// Проверяем, есть ли уже netlify.toml с маркером "CUSTOMIZED"
|
|
19
|
-
if (fs.existsSync(targetPath)) {
|
|
20
|
-
const existingContent = fs.readFileSync(targetPath, 'utf8');
|
|
21
|
-
|
|
22
|
-
if (existingContent.includes('# CUSTOMIZED')) {
|
|
23
|
-
console.log('📋 Found "# CUSTOMIZED" marker - preserving entire file');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Создаем бэкап
|
|
28
|
-
fs.copyFileSync(targetPath, targetPath + '.backup');
|
|
29
|
-
console.log('📦 Created backup: netlify.toml.backup');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Ищем исходный файл в пакете
|
|
33
|
-
let sourcePath;
|
|
34
|
-
const nodeModulesPath = path.join(process.cwd(), 'node_modules', 'core-maugli', 'netlify.toml');
|
|
35
|
-
if (fs.existsSync(nodeModulesPath)) {
|
|
36
|
-
sourcePath = nodeModulesPath;
|
|
37
|
-
} else {
|
|
38
|
-
sourcePath = path.join(__dirname, '..', 'netlify.toml');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!fs.existsSync(sourcePath)) {
|
|
42
|
-
console.log('⚠️ netlify.toml template not found');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Просто копируем файл
|
|
47
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
48
|
-
console.log('✅ netlify.toml copied successfully');
|
|
49
|
-
|
|
50
|
-
console.log('');
|
|
51
|
-
console.log('💡 Add "# CUSTOMIZED" comment to prevent auto-updates');
|
|
52
|
-
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error('❌ Error copying netlify.toml:', error.message);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
main();
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import sharp from 'sharp';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
|
|
9
|
-
// Универсальное определение корня проекта
|
|
10
|
-
const rootDir = __dirname.includes('node_modules')
|
|
11
|
-
? path.join(__dirname, '../../..')
|
|
12
|
-
: path.join(__dirname, '..');
|
|
13
|
-
|
|
14
|
-
// Размеры для разных типов контента
|
|
15
|
-
const blogPreviewWidth = 400;
|
|
16
|
-
const blogPreviewHeight = 210;
|
|
17
|
-
const rubricPreviewWidth = 210;
|
|
18
|
-
const rubricPreviewHeight = 214;
|
|
19
|
-
|
|
20
|
-
// Генерируем в dist вместо public
|
|
21
|
-
const outputDir = path.join(rootDir, 'dist');
|
|
22
|
-
|
|
23
|
-
// Функция для создания превью в dist
|
|
24
|
-
async function createPreviewForBuild(sourcePath, outputPath, width, height) {
|
|
25
|
-
const previewDir = path.dirname(outputPath);
|
|
26
|
-
if (!fs.existsSync(previewDir)) {
|
|
27
|
-
fs.mkdirSync(previewDir, { recursive: true });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (fs.existsSync(outputPath)) {
|
|
31
|
-
return; // Превью уже существует
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await sharp(sourcePath)
|
|
36
|
-
.resize(width, height, { fit: 'cover' })
|
|
37
|
-
.toFile(outputPath);
|
|
38
|
-
console.log(`✅ Превью создано: ${path.relative(rootDir, outputPath)}`);
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error(`❌ Ошибка при создании превью ${outputPath}:`, error.message);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Функция для обработки папки
|
|
45
|
-
async function processDirectory(sourceDir, outputSubDir) {
|
|
46
|
-
if (!fs.existsSync(sourceDir)) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const items = fs.readdirSync(sourceDir);
|
|
51
|
-
|
|
52
|
-
for (const item of items) {
|
|
53
|
-
const sourcePath = path.join(sourceDir, item);
|
|
54
|
-
const stat = fs.statSync(sourcePath);
|
|
55
|
-
|
|
56
|
-
if (stat.isDirectory()) {
|
|
57
|
-
if (item === 'previews') continue; // Пропускаем папки превью
|
|
58
|
-
await processDirectory(sourcePath, path.join(outputSubDir, item));
|
|
59
|
-
} else if (item.match(/\.(webp|jpg|jpeg|png)$/i)) {
|
|
60
|
-
const ext = path.extname(item);
|
|
61
|
-
const name = path.basename(item, ext);
|
|
62
|
-
|
|
63
|
-
// Пропускаем файлы, которые уже содержат размер
|
|
64
|
-
const hasResizeSuffix = [400, 800, 1200].some(size => name.includes(`-${size}`));
|
|
65
|
-
if (hasResizeSuffix) continue;
|
|
66
|
-
|
|
67
|
-
// Определяем размер превью
|
|
68
|
-
let previewWidth, previewHeight;
|
|
69
|
-
if (sourcePath.includes('/img/default/') && (name.includes('rubric') || name.includes('tag'))) {
|
|
70
|
-
previewWidth = rubricPreviewWidth;
|
|
71
|
-
previewHeight = rubricPreviewHeight;
|
|
72
|
-
} else {
|
|
73
|
-
previewWidth = blogPreviewWidth;
|
|
74
|
-
previewHeight = blogPreviewHeight;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Создаем превью
|
|
78
|
-
const outputDir = path.join(rootDir, 'dist', outputSubDir, 'previews');
|
|
79
|
-
const outputPath = path.join(outputDir, `${name}${ext}`);
|
|
80
|
-
|
|
81
|
-
console.log(`🎭 Создаем превью для сборки: ${name}`);
|
|
82
|
-
await createPreviewForBuild(sourcePath, outputPath, previewWidth, previewHeight);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Main function
|
|
88
|
-
async function generatePreviewsForBuild() {
|
|
89
|
-
console.log('🚀 Starting preview generation for build...');
|
|
90
|
-
|
|
91
|
-
// Process system folders
|
|
92
|
-
await processDirectory(path.join(rootDir, 'public/img/default'), 'img/default');
|
|
93
|
-
await processDirectory(path.join(rootDir, 'public/img/examples'), 'img/examples');
|
|
94
|
-
|
|
95
|
-
// Process user images if they exist
|
|
96
|
-
const pageImagesDir = path.join(rootDir, 'public/img/page-images');
|
|
97
|
-
if (fs.existsSync(pageImagesDir)) {
|
|
98
|
-
await processDirectory(pageImagesDir, 'img/page-images');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
console.log('✅ Preview generation for build completed!');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
generatePreviewsForBuild().catch(console.error);
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
|
|
10
|
-
async function testPackageJsonUpdate() {
|
|
11
|
-
console.log('🧪 Testing package.json version update...');
|
|
12
|
-
|
|
13
|
-
// Создаем тестовый package.json
|
|
14
|
-
const testPackageJson = {
|
|
15
|
-
"name": "test-blog",
|
|
16
|
-
"version": "1.0.0",
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"core-maugli": "^1.2.3",
|
|
19
|
-
"astro": "^5.5.6"
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const testPath = path.join(__dirname, 'test-package.json');
|
|
24
|
-
await fs.writeFile(testPath, JSON.stringify(testPackageJson, null, 2), 'utf-8');
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// Получаем текущую версию из основного package.json
|
|
28
|
-
const packageJsonPath = path.join(__dirname, '../package.json');
|
|
29
|
-
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
|
|
30
|
-
const packageData = JSON.parse(packageJsonContent);
|
|
31
|
-
const newVersion = packageData.version;
|
|
32
|
-
|
|
33
|
-
// Читаем тестовый package.json
|
|
34
|
-
const testPackageContent = await fs.readFile(testPath, 'utf-8');
|
|
35
|
-
const testPackageData = JSON.parse(testPackageContent);
|
|
36
|
-
|
|
37
|
-
console.log(`📦 Current test dependency: core-maugli@${testPackageData.dependencies['core-maugli']}`);
|
|
38
|
-
console.log(`📦 New version: ${newVersion}`);
|
|
39
|
-
|
|
40
|
-
// Обновляем версию
|
|
41
|
-
if (testPackageData.dependencies && testPackageData.dependencies['core-maugli']) {
|
|
42
|
-
const currentVersion = testPackageData.dependencies['core-maugli'];
|
|
43
|
-
if (currentVersion !== `^${newVersion}`) {
|
|
44
|
-
testPackageData.dependencies['core-maugli'] = `^${newVersion}`;
|
|
45
|
-
|
|
46
|
-
await fs.writeFile(testPath, JSON.stringify(testPackageData, null, 2) + '\n', 'utf-8');
|
|
47
|
-
console.log(`✅ Updated dependency: ${currentVersion} → ^${newVersion}`);
|
|
48
|
-
} else {
|
|
49
|
-
console.log(`✅ Dependency already up to date: ^${newVersion}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Показываем результат
|
|
54
|
-
const updatedContent = await fs.readFile(testPath, 'utf-8');
|
|
55
|
-
console.log('\n📋 Updated test package.json:');
|
|
56
|
-
console.log(updatedContent);
|
|
57
|
-
|
|
58
|
-
} finally {
|
|
59
|
-
// Удаляем тестовый файл
|
|
60
|
-
await fs.unlink(testPath);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
testPackageJsonUpdate();
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
|
|
10
|
-
async function testVersionUpdate() {
|
|
11
|
-
console.log('🧪 Testing version update function...');
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
// Получаем версию из package.json
|
|
15
|
-
const packageJsonPath = path.join(__dirname, '../package.json');
|
|
16
|
-
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
|
|
17
|
-
const packageData = JSON.parse(packageJsonContent);
|
|
18
|
-
const newVersion = packageData.version;
|
|
19
|
-
|
|
20
|
-
// Путь к конфигу
|
|
21
|
-
const configPath = path.join(__dirname, '../src/config/maugli.config.ts');
|
|
22
|
-
|
|
23
|
-
// Читаем конфиг
|
|
24
|
-
const configContent = await fs.readFile(configPath, 'utf-8');
|
|
25
|
-
|
|
26
|
-
// Ищем строку с MAUGLI_CONFIG_VERSION
|
|
27
|
-
const versionRegex = /export const MAUGLI_CONFIG_VERSION = ['"`]([^'"`]+)['"`];/;
|
|
28
|
-
const match = configContent.match(versionRegex);
|
|
29
|
-
|
|
30
|
-
if (match) {
|
|
31
|
-
const currentVersion = match[1];
|
|
32
|
-
console.log(`📦 Current config version: ${currentVersion}`);
|
|
33
|
-
console.log(`📦 Package version: ${newVersion}`);
|
|
34
|
-
|
|
35
|
-
if (currentVersion !== newVersion) {
|
|
36
|
-
const updatedContent = configContent.replace(
|
|
37
|
-
versionRegex,
|
|
38
|
-
`export const MAUGLI_CONFIG_VERSION = '${newVersion}';`
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
await fs.writeFile(configPath, updatedContent, 'utf-8');
|
|
42
|
-
console.log(`✅ Updated config version: ${currentVersion} → ${newVersion}`);
|
|
43
|
-
} else {
|
|
44
|
-
console.log(`✅ Config version already up to date: ${newVersion}`);
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
47
|
-
console.log('❌ Config version line not found');
|
|
48
|
-
}
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error('❌ Test failed:', error.message);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
testVersionUpdate();
|