@djangocfg/nextjs 2.1.41 → 2.1.43
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/dist/ai/cli.mjs.map +1 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/config/index.mjs +261 -263
- package/dist/config/index.mjs.map +1 -1
- package/dist/health/index.mjs.map +1 -1
- package/dist/index.mjs +580 -582
- package/dist/index.mjs.map +1 -1
- package/dist/og-image/index.mjs +468 -468
- package/dist/og-image/index.mjs.map +1 -1
- package/dist/og-image/utils/index.mjs.map +1 -1
- package/dist/pwa/server/index.mjs +1 -1
- package/dist/pwa/server/index.mjs.map +1 -1
- package/dist/pwa/server/routes.mjs +1 -1
- package/dist/pwa/server/routes.mjs.map +1 -1
- package/dist/pwa/worker/index.mjs +1 -1
- package/dist/pwa/worker/index.mjs.map +1 -1
- package/dist/scripts/index.mjs +75 -73
- package/dist/scripts/index.mjs.map +1 -1
- package/dist/sitemap/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/ai/cli.ts +2 -1
- package/src/ai/client.ts +2 -6
- package/src/config/createNextConfig.ts +5 -5
- package/src/config/packages/checker.ts +3 -2
- package/src/config/packages/installer.ts +6 -5
- package/src/config/packages/updater.ts +5 -4
- package/src/config/plugins/devStartup.ts +3 -2
- package/src/config/utils/version.ts +4 -3
- package/src/health/route.ts +1 -0
- package/src/og-image/route.tsx +4 -2
- package/src/og-image/utils/metadata.ts +1 -1
- package/src/pwa/server/push.ts +1 -1
- package/src/pwa/server/routes.ts +1 -0
- package/src/pwa/worker/index.ts +2 -1
- package/src/scripts/check-links.ts +4 -4
- package/src/sitemap/route.ts +3 -1
package/dist/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var require_package = __commonJS({
|
|
|
14
14
|
"package.json"(exports, module) {
|
|
15
15
|
module.exports = {
|
|
16
16
|
name: "@djangocfg/nextjs",
|
|
17
|
-
version: "2.1.
|
|
17
|
+
version: "2.1.43",
|
|
18
18
|
description: "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
|
|
19
19
|
keywords: [
|
|
20
20
|
"nextjs",
|
|
@@ -289,309 +289,6 @@ function createHealthHandler(config = {}) {
|
|
|
289
289
|
import { ImageResponse } from "next/og";
|
|
290
290
|
import { NextRequest } from "next/server";
|
|
291
291
|
|
|
292
|
-
// src/og-image/utils/fonts.ts
|
|
293
|
-
async function loadGoogleFont(font, text, weight = 700) {
|
|
294
|
-
let url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weight}`;
|
|
295
|
-
if (text) {
|
|
296
|
-
url += `&text=${encodeURIComponent(text)}`;
|
|
297
|
-
}
|
|
298
|
-
try {
|
|
299
|
-
const css = await fetch(url, {
|
|
300
|
-
headers: {
|
|
301
|
-
// Required to get TTF format instead of WOFF2
|
|
302
|
-
"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
|
|
303
|
-
}
|
|
304
|
-
}).then((res) => res.text());
|
|
305
|
-
const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
|
|
306
|
-
if (!resource || !resource[1]) {
|
|
307
|
-
throw new Error(`Failed to parse font URL from CSS for font: ${font}`);
|
|
308
|
-
}
|
|
309
|
-
const response = await fetch(resource[1]);
|
|
310
|
-
if (response.status !== 200) {
|
|
311
|
-
throw new Error(`Failed to fetch font data: HTTP ${response.status}`);
|
|
312
|
-
}
|
|
313
|
-
return await response.arrayBuffer();
|
|
314
|
-
} catch (error) {
|
|
315
|
-
console.error(`Error loading Google Font "${font}":`, error);
|
|
316
|
-
throw new Error(`Failed to load font "${font}": ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
async function loadGoogleFonts(fonts) {
|
|
320
|
-
const fontConfigs = await Promise.all(
|
|
321
|
-
fonts.map(async ({ family, weight = 700, style = "normal", text }) => {
|
|
322
|
-
const data = await loadGoogleFont(family, text, weight);
|
|
323
|
-
return {
|
|
324
|
-
name: family,
|
|
325
|
-
weight,
|
|
326
|
-
style,
|
|
327
|
-
data
|
|
328
|
-
};
|
|
329
|
-
})
|
|
330
|
-
);
|
|
331
|
-
return fontConfigs;
|
|
332
|
-
}
|
|
333
|
-
function createFontLoader() {
|
|
334
|
-
const cache = /* @__PURE__ */ new Map();
|
|
335
|
-
return {
|
|
336
|
-
/**
|
|
337
|
-
* Load a font with caching
|
|
338
|
-
*/
|
|
339
|
-
async load(family, weight = 700, text) {
|
|
340
|
-
const cacheKey = `${family}-${weight}-${text || "all"}`;
|
|
341
|
-
if (!cache.has(cacheKey)) {
|
|
342
|
-
cache.set(cacheKey, loadGoogleFont(family, text, weight));
|
|
343
|
-
}
|
|
344
|
-
return cache.get(cacheKey);
|
|
345
|
-
},
|
|
346
|
-
/**
|
|
347
|
-
* Clear the cache
|
|
348
|
-
*/
|
|
349
|
-
clear() {
|
|
350
|
-
cache.clear();
|
|
351
|
-
},
|
|
352
|
-
/**
|
|
353
|
-
* Get cache size
|
|
354
|
-
*/
|
|
355
|
-
size() {
|
|
356
|
-
return cache.size;
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// src/og-image/utils/url.ts
|
|
362
|
-
var DEFAULT_OG_IMAGE_BASE_URL = "https://djangocfg.com/api/og";
|
|
363
|
-
function encodeBase64(str) {
|
|
364
|
-
if (typeof Buffer !== "undefined") {
|
|
365
|
-
return Buffer.from(str, "utf-8").toString("base64");
|
|
366
|
-
}
|
|
367
|
-
return btoa(unescape(encodeURIComponent(str)));
|
|
368
|
-
}
|
|
369
|
-
function decodeBase64(str) {
|
|
370
|
-
if (typeof Buffer !== "undefined") {
|
|
371
|
-
return Buffer.from(str, "base64").toString("utf-8");
|
|
372
|
-
}
|
|
373
|
-
try {
|
|
374
|
-
const binaryString = atob(str);
|
|
375
|
-
return decodeURIComponent(
|
|
376
|
-
binaryString.split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
|
|
377
|
-
);
|
|
378
|
-
} catch (error) {
|
|
379
|
-
return decodeURIComponent(escape(atob(str)));
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
function generateOgImageUrl(params, options = {}) {
|
|
383
|
-
const {
|
|
384
|
-
baseUrl = DEFAULT_OG_IMAGE_BASE_URL,
|
|
385
|
-
useBase64 = true
|
|
386
|
-
} = options;
|
|
387
|
-
if (useBase64) {
|
|
388
|
-
const cleanParams = {};
|
|
389
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
390
|
-
if (value !== void 0 && value !== null && value !== "") {
|
|
391
|
-
cleanParams[key] = value;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
const jsonString = JSON.stringify(cleanParams);
|
|
395
|
-
const base64Data = encodeBase64(jsonString);
|
|
396
|
-
return `${baseUrl}/${base64Data}`;
|
|
397
|
-
} else {
|
|
398
|
-
const searchParams = new URLSearchParams();
|
|
399
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
400
|
-
if (value !== void 0 && value !== null && value !== "") {
|
|
401
|
-
searchParams.append(key, String(value));
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
const query = searchParams.toString();
|
|
405
|
-
return query ? `${baseUrl}?${query}` : baseUrl;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function getAbsoluteOgImageUrl(relativePath, siteUrl) {
|
|
409
|
-
if (relativePath.startsWith("http://") || relativePath.startsWith("https://")) {
|
|
410
|
-
return relativePath;
|
|
411
|
-
}
|
|
412
|
-
const cleanSiteUrl = siteUrl.replace(/\/$/, "");
|
|
413
|
-
const cleanPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
414
|
-
return `${cleanSiteUrl}${cleanPath}`;
|
|
415
|
-
}
|
|
416
|
-
function createOgImageUrlBuilder(defaults = {}, options = {}) {
|
|
417
|
-
return (params) => {
|
|
418
|
-
return generateOgImageUrl(
|
|
419
|
-
{ ...defaults, ...params },
|
|
420
|
-
options
|
|
421
|
-
);
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
function parseOgImageUrl(url) {
|
|
425
|
-
try {
|
|
426
|
-
const urlObj = new URL(url, "http://dummy.com");
|
|
427
|
-
const params = {};
|
|
428
|
-
urlObj.searchParams.forEach((value, key) => {
|
|
429
|
-
params[key] = value;
|
|
430
|
-
});
|
|
431
|
-
return params;
|
|
432
|
-
} catch {
|
|
433
|
-
return {};
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
function parseOgImageData(searchParams) {
|
|
437
|
-
try {
|
|
438
|
-
let params;
|
|
439
|
-
if (searchParams instanceof URLSearchParams) {
|
|
440
|
-
params = {};
|
|
441
|
-
for (const [key, value] of searchParams.entries()) {
|
|
442
|
-
params[key] = value;
|
|
443
|
-
}
|
|
444
|
-
} else {
|
|
445
|
-
params = searchParams;
|
|
446
|
-
}
|
|
447
|
-
if (process.env.NODE_ENV === "development") {
|
|
448
|
-
console.log("[parseOgImageData] Input params keys:", Object.keys(params));
|
|
449
|
-
console.log("[parseOgImageData] Input params:", params);
|
|
450
|
-
}
|
|
451
|
-
const dataParam = params.data;
|
|
452
|
-
if (dataParam && typeof dataParam === "string" && dataParam.trim() !== "") {
|
|
453
|
-
if (process.env.NODE_ENV === "development") {
|
|
454
|
-
console.log("[parseOgImageData] Found data param, length:", dataParam.length);
|
|
455
|
-
}
|
|
456
|
-
try {
|
|
457
|
-
const decoded = decodeBase64(dataParam);
|
|
458
|
-
if (process.env.NODE_ENV === "development") {
|
|
459
|
-
console.log("[parseOgImageData] Decoded string:", decoded.substring(0, 100));
|
|
460
|
-
}
|
|
461
|
-
const parsed = JSON.parse(decoded);
|
|
462
|
-
if (process.env.NODE_ENV === "development") {
|
|
463
|
-
console.log("[parseOgImageData] Parsed JSON:", parsed);
|
|
464
|
-
}
|
|
465
|
-
const result2 = {};
|
|
466
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
467
|
-
if (value !== void 0 && value !== null) {
|
|
468
|
-
result2[key] = String(value);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
if (process.env.NODE_ENV === "development") {
|
|
472
|
-
console.log("[parseOgImageData] Result:", result2);
|
|
473
|
-
}
|
|
474
|
-
return result2;
|
|
475
|
-
} catch (decodeError) {
|
|
476
|
-
console.error("[parseOgImageData] Error decoding/parsing data param:", decodeError);
|
|
477
|
-
if (decodeError instanceof Error) {
|
|
478
|
-
console.error("[parseOgImageData] Error message:", decodeError.message);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
} else {
|
|
482
|
-
if (process.env.NODE_ENV === "development") {
|
|
483
|
-
console.log("[parseOgImageData] No data param found or empty");
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
const result = {};
|
|
487
|
-
for (const [key, value] of Object.entries(params)) {
|
|
488
|
-
if (key !== "data" && value !== void 0 && value !== null) {
|
|
489
|
-
result[key] = Array.isArray(value) ? value[0] : String(value);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
if (process.env.NODE_ENV === "development") {
|
|
493
|
-
console.log("[parseOgImageData] Fallback result:", result);
|
|
494
|
-
}
|
|
495
|
-
return result;
|
|
496
|
-
} catch (error) {
|
|
497
|
-
console.error("[parseOgImageData] Unexpected error:", error);
|
|
498
|
-
return {};
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// src/og-image/utils/metadata.ts
|
|
503
|
-
function extractTitle(metadata) {
|
|
504
|
-
if (typeof metadata.title === "string") {
|
|
505
|
-
return metadata.title;
|
|
506
|
-
}
|
|
507
|
-
if (metadata.title) {
|
|
508
|
-
if ("default" in metadata.title) {
|
|
509
|
-
return metadata.title.default;
|
|
510
|
-
}
|
|
511
|
-
if ("absolute" in metadata.title) {
|
|
512
|
-
return metadata.title.absolute;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return "";
|
|
516
|
-
}
|
|
517
|
-
function extractDescription(metadata) {
|
|
518
|
-
if (typeof metadata.description === "string") {
|
|
519
|
-
return metadata.description;
|
|
520
|
-
}
|
|
521
|
-
return "";
|
|
522
|
-
}
|
|
523
|
-
function getSiteUrl() {
|
|
524
|
-
if (typeof process !== "undefined" && process.env.NEXT_PUBLIC_SITE_URL) {
|
|
525
|
-
return process.env.NEXT_PUBLIC_SITE_URL;
|
|
526
|
-
}
|
|
527
|
-
return "";
|
|
528
|
-
}
|
|
529
|
-
function generateOgImageMetadata(metadata, ogImageParams, options = {}) {
|
|
530
|
-
const {
|
|
531
|
-
ogImageBaseUrl = "https://djangocfg.com/api/og",
|
|
532
|
-
siteUrl: providedSiteUrl,
|
|
533
|
-
defaultParams = {},
|
|
534
|
-
useBase64 = true
|
|
535
|
-
} = options;
|
|
536
|
-
const siteUrl = providedSiteUrl && providedSiteUrl !== "undefined" ? providedSiteUrl : getSiteUrl();
|
|
537
|
-
const extractedTitle = extractTitle(metadata);
|
|
538
|
-
const extractedDescription = extractDescription(metadata);
|
|
539
|
-
const finalOgImageParams = {
|
|
540
|
-
...defaultParams,
|
|
541
|
-
title: ogImageParams?.title || extractedTitle || defaultParams.title || "",
|
|
542
|
-
description: ogImageParams?.description || extractedDescription || defaultParams.description || "",
|
|
543
|
-
...ogImageParams
|
|
544
|
-
};
|
|
545
|
-
const imageAlt = finalOgImageParams.title || finalOgImageParams.siteName;
|
|
546
|
-
const relativeOgImageUrl = generateOgImageUrl(
|
|
547
|
-
finalOgImageParams,
|
|
548
|
-
{ baseUrl: ogImageBaseUrl, useBase64 }
|
|
549
|
-
);
|
|
550
|
-
const ogImageUrl = siteUrl ? getAbsoluteOgImageUrl(relativeOgImageUrl, siteUrl) : relativeOgImageUrl;
|
|
551
|
-
const existingOgImages = metadata.openGraph?.images ? Array.isArray(metadata.openGraph.images) ? metadata.openGraph.images : [metadata.openGraph.images] : [];
|
|
552
|
-
const existingTwitterImages = metadata.twitter?.images ? Array.isArray(metadata.twitter.images) ? metadata.twitter.images : [metadata.twitter.images] : [];
|
|
553
|
-
const finalMetadata = {
|
|
554
|
-
...metadata,
|
|
555
|
-
openGraph: {
|
|
556
|
-
...metadata.openGraph,
|
|
557
|
-
images: [
|
|
558
|
-
...existingOgImages,
|
|
559
|
-
{
|
|
560
|
-
url: ogImageUrl,
|
|
561
|
-
width: 1200,
|
|
562
|
-
height: 630,
|
|
563
|
-
alt: imageAlt
|
|
564
|
-
}
|
|
565
|
-
]
|
|
566
|
-
},
|
|
567
|
-
twitter: {
|
|
568
|
-
...metadata.twitter,
|
|
569
|
-
card: "summary_large_image",
|
|
570
|
-
images: [
|
|
571
|
-
...existingTwitterImages,
|
|
572
|
-
{
|
|
573
|
-
url: ogImageUrl,
|
|
574
|
-
alt: imageAlt
|
|
575
|
-
}
|
|
576
|
-
]
|
|
577
|
-
}
|
|
578
|
-
};
|
|
579
|
-
if (!finalMetadata.metadataBase && siteUrl) {
|
|
580
|
-
if (siteUrl.startsWith("http://") || siteUrl.startsWith("https://")) {
|
|
581
|
-
try {
|
|
582
|
-
finalMetadata.metadataBase = new URL(siteUrl);
|
|
583
|
-
} catch (e) {
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
return finalMetadata;
|
|
588
|
-
}
|
|
589
|
-
function createOgImageMetadataGenerator(options) {
|
|
590
|
-
return (metadata, ogImageParams) => {
|
|
591
|
-
return generateOgImageMetadata(metadata, ogImageParams, options);
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
|
|
595
292
|
// src/og-image/components/DefaultTemplate.tsx
|
|
596
293
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
597
294
|
function DefaultTemplate({
|
|
@@ -923,7 +620,310 @@ function LightTemplate({
|
|
|
923
620
|
)
|
|
924
621
|
]
|
|
925
622
|
}
|
|
926
|
-
);
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/og-image/utils/fonts.ts
|
|
627
|
+
async function loadGoogleFont(font, text, weight = 700) {
|
|
628
|
+
let url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weight}`;
|
|
629
|
+
if (text) {
|
|
630
|
+
url += `&text=${encodeURIComponent(text)}`;
|
|
631
|
+
}
|
|
632
|
+
try {
|
|
633
|
+
const css = await fetch(url, {
|
|
634
|
+
headers: {
|
|
635
|
+
// Required to get TTF format instead of WOFF2
|
|
636
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
|
|
637
|
+
}
|
|
638
|
+
}).then((res) => res.text());
|
|
639
|
+
const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
|
|
640
|
+
if (!resource || !resource[1]) {
|
|
641
|
+
throw new Error(`Failed to parse font URL from CSS for font: ${font}`);
|
|
642
|
+
}
|
|
643
|
+
const response = await fetch(resource[1]);
|
|
644
|
+
if (response.status !== 200) {
|
|
645
|
+
throw new Error(`Failed to fetch font data: HTTP ${response.status}`);
|
|
646
|
+
}
|
|
647
|
+
return await response.arrayBuffer();
|
|
648
|
+
} catch (error) {
|
|
649
|
+
console.error(`Error loading Google Font "${font}":`, error);
|
|
650
|
+
throw new Error(`Failed to load font "${font}": ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
async function loadGoogleFonts(fonts) {
|
|
654
|
+
const fontConfigs = await Promise.all(
|
|
655
|
+
fonts.map(async ({ family, weight = 700, style = "normal", text }) => {
|
|
656
|
+
const data = await loadGoogleFont(family, text, weight);
|
|
657
|
+
return {
|
|
658
|
+
name: family,
|
|
659
|
+
weight,
|
|
660
|
+
style,
|
|
661
|
+
data
|
|
662
|
+
};
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
return fontConfigs;
|
|
666
|
+
}
|
|
667
|
+
function createFontLoader() {
|
|
668
|
+
const cache = /* @__PURE__ */ new Map();
|
|
669
|
+
return {
|
|
670
|
+
/**
|
|
671
|
+
* Load a font with caching
|
|
672
|
+
*/
|
|
673
|
+
async load(family, weight = 700, text) {
|
|
674
|
+
const cacheKey = `${family}-${weight}-${text || "all"}`;
|
|
675
|
+
if (!cache.has(cacheKey)) {
|
|
676
|
+
cache.set(cacheKey, loadGoogleFont(family, text, weight));
|
|
677
|
+
}
|
|
678
|
+
return cache.get(cacheKey);
|
|
679
|
+
},
|
|
680
|
+
/**
|
|
681
|
+
* Clear the cache
|
|
682
|
+
*/
|
|
683
|
+
clear() {
|
|
684
|
+
cache.clear();
|
|
685
|
+
},
|
|
686
|
+
/**
|
|
687
|
+
* Get cache size
|
|
688
|
+
*/
|
|
689
|
+
size() {
|
|
690
|
+
return cache.size;
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// src/og-image/utils/url.ts
|
|
696
|
+
var DEFAULT_OG_IMAGE_BASE_URL = "https://djangocfg.com/api/og";
|
|
697
|
+
function encodeBase64(str) {
|
|
698
|
+
if (typeof Buffer !== "undefined") {
|
|
699
|
+
return Buffer.from(str, "utf-8").toString("base64");
|
|
700
|
+
}
|
|
701
|
+
return btoa(unescape(encodeURIComponent(str)));
|
|
702
|
+
}
|
|
703
|
+
function decodeBase64(str) {
|
|
704
|
+
if (typeof Buffer !== "undefined") {
|
|
705
|
+
return Buffer.from(str, "base64").toString("utf-8");
|
|
706
|
+
}
|
|
707
|
+
try {
|
|
708
|
+
const binaryString = atob(str);
|
|
709
|
+
return decodeURIComponent(
|
|
710
|
+
binaryString.split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
|
|
711
|
+
);
|
|
712
|
+
} catch (error) {
|
|
713
|
+
return decodeURIComponent(escape(atob(str)));
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
function generateOgImageUrl(params, options = {}) {
|
|
717
|
+
const {
|
|
718
|
+
baseUrl = DEFAULT_OG_IMAGE_BASE_URL,
|
|
719
|
+
useBase64 = true
|
|
720
|
+
} = options;
|
|
721
|
+
if (useBase64) {
|
|
722
|
+
const cleanParams = {};
|
|
723
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
724
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
725
|
+
cleanParams[key] = value;
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
const jsonString = JSON.stringify(cleanParams);
|
|
729
|
+
const base64Data = encodeBase64(jsonString);
|
|
730
|
+
return `${baseUrl}/${base64Data}`;
|
|
731
|
+
} else {
|
|
732
|
+
const searchParams = new URLSearchParams();
|
|
733
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
734
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
735
|
+
searchParams.append(key, String(value));
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
const query = searchParams.toString();
|
|
739
|
+
return query ? `${baseUrl}?${query}` : baseUrl;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function getAbsoluteOgImageUrl(relativePath, siteUrl) {
|
|
743
|
+
if (relativePath.startsWith("http://") || relativePath.startsWith("https://")) {
|
|
744
|
+
return relativePath;
|
|
745
|
+
}
|
|
746
|
+
const cleanSiteUrl = siteUrl.replace(/\/$/, "");
|
|
747
|
+
const cleanPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
748
|
+
return `${cleanSiteUrl}${cleanPath}`;
|
|
749
|
+
}
|
|
750
|
+
function createOgImageUrlBuilder(defaults = {}, options = {}) {
|
|
751
|
+
return (params) => {
|
|
752
|
+
return generateOgImageUrl(
|
|
753
|
+
{ ...defaults, ...params },
|
|
754
|
+
options
|
|
755
|
+
);
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function parseOgImageUrl(url) {
|
|
759
|
+
try {
|
|
760
|
+
const urlObj = new URL(url, "http://dummy.com");
|
|
761
|
+
const params = {};
|
|
762
|
+
urlObj.searchParams.forEach((value, key) => {
|
|
763
|
+
params[key] = value;
|
|
764
|
+
});
|
|
765
|
+
return params;
|
|
766
|
+
} catch {
|
|
767
|
+
return {};
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function parseOgImageData(searchParams) {
|
|
771
|
+
try {
|
|
772
|
+
let params;
|
|
773
|
+
if (searchParams instanceof URLSearchParams) {
|
|
774
|
+
params = {};
|
|
775
|
+
for (const [key, value] of searchParams.entries()) {
|
|
776
|
+
params[key] = value;
|
|
777
|
+
}
|
|
778
|
+
} else {
|
|
779
|
+
params = searchParams;
|
|
780
|
+
}
|
|
781
|
+
if (process.env.NODE_ENV === "development") {
|
|
782
|
+
console.log("[parseOgImageData] Input params keys:", Object.keys(params));
|
|
783
|
+
console.log("[parseOgImageData] Input params:", params);
|
|
784
|
+
}
|
|
785
|
+
const dataParam = params.data;
|
|
786
|
+
if (dataParam && typeof dataParam === "string" && dataParam.trim() !== "") {
|
|
787
|
+
if (process.env.NODE_ENV === "development") {
|
|
788
|
+
console.log("[parseOgImageData] Found data param, length:", dataParam.length);
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
const decoded = decodeBase64(dataParam);
|
|
792
|
+
if (process.env.NODE_ENV === "development") {
|
|
793
|
+
console.log("[parseOgImageData] Decoded string:", decoded.substring(0, 100));
|
|
794
|
+
}
|
|
795
|
+
const parsed = JSON.parse(decoded);
|
|
796
|
+
if (process.env.NODE_ENV === "development") {
|
|
797
|
+
console.log("[parseOgImageData] Parsed JSON:", parsed);
|
|
798
|
+
}
|
|
799
|
+
const result2 = {};
|
|
800
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
801
|
+
if (value !== void 0 && value !== null) {
|
|
802
|
+
result2[key] = String(value);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (process.env.NODE_ENV === "development") {
|
|
806
|
+
console.log("[parseOgImageData] Result:", result2);
|
|
807
|
+
}
|
|
808
|
+
return result2;
|
|
809
|
+
} catch (decodeError) {
|
|
810
|
+
console.error("[parseOgImageData] Error decoding/parsing data param:", decodeError);
|
|
811
|
+
if (decodeError instanceof Error) {
|
|
812
|
+
console.error("[parseOgImageData] Error message:", decodeError.message);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
} else {
|
|
816
|
+
if (process.env.NODE_ENV === "development") {
|
|
817
|
+
console.log("[parseOgImageData] No data param found or empty");
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
const result = {};
|
|
821
|
+
for (const [key, value] of Object.entries(params)) {
|
|
822
|
+
if (key !== "data" && value !== void 0 && value !== null) {
|
|
823
|
+
result[key] = Array.isArray(value) ? value[0] : String(value);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (process.env.NODE_ENV === "development") {
|
|
827
|
+
console.log("[parseOgImageData] Fallback result:", result);
|
|
828
|
+
}
|
|
829
|
+
return result;
|
|
830
|
+
} catch (error) {
|
|
831
|
+
console.error("[parseOgImageData] Unexpected error:", error);
|
|
832
|
+
return {};
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// src/og-image/utils/metadata.ts
|
|
837
|
+
function extractTitle(metadata) {
|
|
838
|
+
if (typeof metadata.title === "string") {
|
|
839
|
+
return metadata.title;
|
|
840
|
+
}
|
|
841
|
+
if (metadata.title) {
|
|
842
|
+
if ("default" in metadata.title) {
|
|
843
|
+
return metadata.title.default;
|
|
844
|
+
}
|
|
845
|
+
if ("absolute" in metadata.title) {
|
|
846
|
+
return metadata.title.absolute;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return "";
|
|
850
|
+
}
|
|
851
|
+
function extractDescription(metadata) {
|
|
852
|
+
if (typeof metadata.description === "string") {
|
|
853
|
+
return metadata.description;
|
|
854
|
+
}
|
|
855
|
+
return "";
|
|
856
|
+
}
|
|
857
|
+
function getSiteUrl() {
|
|
858
|
+
if (typeof process !== "undefined" && process.env.NEXT_PUBLIC_SITE_URL) {
|
|
859
|
+
return process.env.NEXT_PUBLIC_SITE_URL;
|
|
860
|
+
}
|
|
861
|
+
return "";
|
|
862
|
+
}
|
|
863
|
+
function generateOgImageMetadata(metadata, ogImageParams, options = {}) {
|
|
864
|
+
const {
|
|
865
|
+
ogImageBaseUrl = "https://djangocfg.com/api/og",
|
|
866
|
+
siteUrl: providedSiteUrl,
|
|
867
|
+
defaultParams = {},
|
|
868
|
+
useBase64 = true
|
|
869
|
+
} = options;
|
|
870
|
+
const siteUrl = providedSiteUrl && providedSiteUrl !== "undefined" ? providedSiteUrl : getSiteUrl();
|
|
871
|
+
const extractedTitle = extractTitle(metadata);
|
|
872
|
+
const extractedDescription = extractDescription(metadata);
|
|
873
|
+
const finalOgImageParams = {
|
|
874
|
+
...defaultParams,
|
|
875
|
+
title: ogImageParams?.title || extractedTitle || defaultParams.title || "",
|
|
876
|
+
description: ogImageParams?.description || extractedDescription || defaultParams.description || "",
|
|
877
|
+
...ogImageParams
|
|
878
|
+
};
|
|
879
|
+
const imageAlt = finalOgImageParams.title || finalOgImageParams.siteName;
|
|
880
|
+
const relativeOgImageUrl = generateOgImageUrl(
|
|
881
|
+
finalOgImageParams,
|
|
882
|
+
{ baseUrl: ogImageBaseUrl, useBase64 }
|
|
883
|
+
);
|
|
884
|
+
const ogImageUrl = siteUrl ? getAbsoluteOgImageUrl(relativeOgImageUrl, siteUrl) : relativeOgImageUrl;
|
|
885
|
+
const existingOgImages = metadata.openGraph?.images ? Array.isArray(metadata.openGraph.images) ? metadata.openGraph.images : [metadata.openGraph.images] : [];
|
|
886
|
+
const existingTwitterImages = metadata.twitter?.images ? Array.isArray(metadata.twitter.images) ? metadata.twitter.images : [metadata.twitter.images] : [];
|
|
887
|
+
const finalMetadata = {
|
|
888
|
+
...metadata,
|
|
889
|
+
openGraph: {
|
|
890
|
+
...metadata.openGraph,
|
|
891
|
+
images: [
|
|
892
|
+
...existingOgImages,
|
|
893
|
+
{
|
|
894
|
+
url: ogImageUrl,
|
|
895
|
+
width: 1200,
|
|
896
|
+
height: 630,
|
|
897
|
+
alt: imageAlt
|
|
898
|
+
}
|
|
899
|
+
]
|
|
900
|
+
},
|
|
901
|
+
twitter: {
|
|
902
|
+
...metadata.twitter,
|
|
903
|
+
card: "summary_large_image",
|
|
904
|
+
images: [
|
|
905
|
+
...existingTwitterImages,
|
|
906
|
+
{
|
|
907
|
+
url: ogImageUrl,
|
|
908
|
+
alt: imageAlt
|
|
909
|
+
}
|
|
910
|
+
]
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
if (!finalMetadata.metadataBase && siteUrl) {
|
|
914
|
+
if (siteUrl.startsWith("http://") || siteUrl.startsWith("https://")) {
|
|
915
|
+
try {
|
|
916
|
+
finalMetadata.metadataBase = new URL(siteUrl);
|
|
917
|
+
} catch (e) {
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return finalMetadata;
|
|
922
|
+
}
|
|
923
|
+
function createOgImageMetadataGenerator(options) {
|
|
924
|
+
return (metadata, ogImageParams) => {
|
|
925
|
+
return generateOgImageMetadata(metadata, ogImageParams, options);
|
|
926
|
+
};
|
|
927
927
|
}
|
|
928
928
|
|
|
929
929
|
// src/og-image/route.tsx
|
|
@@ -1157,6 +1157,37 @@ function routesToMenuItems(routes, groupName) {
|
|
|
1157
1157
|
}));
|
|
1158
1158
|
}
|
|
1159
1159
|
|
|
1160
|
+
// src/pwa/plugin.ts
|
|
1161
|
+
import { consola } from "consola";
|
|
1162
|
+
function withPWA(nextConfig, options = {}) {
|
|
1163
|
+
const isDev2 = process.env.NODE_ENV === "development";
|
|
1164
|
+
const isStaticBuild2 = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
|
|
1165
|
+
const shouldDisable = options.disable !== void 0 ? options.disable : isDev2 || isStaticBuild2;
|
|
1166
|
+
const defaultOptions = {
|
|
1167
|
+
swSrc: "app/sw.ts",
|
|
1168
|
+
swDest: "public/sw.js",
|
|
1169
|
+
disable: shouldDisable,
|
|
1170
|
+
cacheOnNavigation: true,
|
|
1171
|
+
reloadOnOnline: true,
|
|
1172
|
+
...options
|
|
1173
|
+
};
|
|
1174
|
+
try {
|
|
1175
|
+
const withSerwistInit = __require("@serwist/next").default;
|
|
1176
|
+
const withSerwist = withSerwistInit({
|
|
1177
|
+
swSrc: defaultOptions.swSrc,
|
|
1178
|
+
swDest: defaultOptions.swDest,
|
|
1179
|
+
disable: defaultOptions.disable,
|
|
1180
|
+
cacheOnNavigation: defaultOptions.cacheOnNavigation,
|
|
1181
|
+
reloadOnOnline: defaultOptions.reloadOnOnline,
|
|
1182
|
+
...defaultOptions.serwistOptions
|
|
1183
|
+
});
|
|
1184
|
+
return withSerwist(nextConfig);
|
|
1185
|
+
} catch (error) {
|
|
1186
|
+
consola.error("Failed to configure Serwist:", error);
|
|
1187
|
+
return nextConfig;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1160
1191
|
// src/config/constants.ts
|
|
1161
1192
|
var PACKAGE_NAME = "@djangocfg/nextjs";
|
|
1162
1193
|
var VERSION_CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -1193,26 +1224,9 @@ var DEFAULT_OPTIMIZE_PACKAGES = [
|
|
|
1193
1224
|
"recharts"
|
|
1194
1225
|
];
|
|
1195
1226
|
|
|
1196
|
-
// src/config/
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
for (const key in source) {
|
|
1200
|
-
if (source[key] === void 0) continue;
|
|
1201
|
-
if (Array.isArray(source[key])) {
|
|
1202
|
-
output[key] = source[key];
|
|
1203
|
-
} else if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
1204
|
-
const targetValue = output[key];
|
|
1205
|
-
if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
1206
|
-
output[key] = deepMerge(targetValue, source[key]);
|
|
1207
|
-
} else {
|
|
1208
|
-
output[key] = source[key];
|
|
1209
|
-
}
|
|
1210
|
-
} else {
|
|
1211
|
-
output[key] = source[key];
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
return output;
|
|
1215
|
-
}
|
|
1227
|
+
// src/config/packages/checker.ts
|
|
1228
|
+
import { createRequire } from "module";
|
|
1229
|
+
import { join } from "path";
|
|
1216
1230
|
|
|
1217
1231
|
// src/config/utils/env.ts
|
|
1218
1232
|
var isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
|
|
@@ -1230,124 +1244,6 @@ function getSiteUrl2() {
|
|
|
1230
1244
|
return isStaticBuild ? "" : process.env.NEXT_PUBLIC_SITE_URL || "";
|
|
1231
1245
|
}
|
|
1232
1246
|
|
|
1233
|
-
// src/config/plugins/devStartup.ts
|
|
1234
|
-
import chalk4 from "chalk";
|
|
1235
|
-
|
|
1236
|
-
// src/ai/constants.ts
|
|
1237
|
-
var MCP_BASE_URL = "https://mcp.djangocfg.com";
|
|
1238
|
-
var MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
|
|
1239
|
-
var MCP_API_URL = `${MCP_BASE_URL}/api/search`;
|
|
1240
|
-
var API_SEARCH_ENDPOINT = "/api/search";
|
|
1241
|
-
var API_INFO_ENDPOINT = "/api/info";
|
|
1242
|
-
var DEFAULT_TIMEOUT = 1e4;
|
|
1243
|
-
var AI_DOCS_HINT = `\u{1F916} AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search "query"`;
|
|
1244
|
-
var AI_HINT = `
|
|
1245
|
-
DjangoCFG Documentation is available via MCP server.
|
|
1246
|
-
|
|
1247
|
-
To get help with DjangoCFG configuration:
|
|
1248
|
-
1. Use the MCP server: ${MCP_SERVER_URL}
|
|
1249
|
-
2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5
|
|
1250
|
-
|
|
1251
|
-
Example queries:
|
|
1252
|
-
- "How to configure PostgreSQL database?"
|
|
1253
|
-
- "What is DatabaseConfig?"
|
|
1254
|
-
- "How to setup Redis cache?"
|
|
1255
|
-
- "Email configuration with SMTP"
|
|
1256
|
-
`;
|
|
1257
|
-
|
|
1258
|
-
// src/config/utils/version.ts
|
|
1259
|
-
import chalk from "chalk";
|
|
1260
|
-
import semver from "semver";
|
|
1261
|
-
import consola from "consola";
|
|
1262
|
-
import Conf from "conf";
|
|
1263
|
-
var versionCache = new Conf({
|
|
1264
|
-
projectName: "djangocfg-nextjs",
|
|
1265
|
-
projectVersion: "1.0.0"
|
|
1266
|
-
});
|
|
1267
|
-
function getCurrentVersion() {
|
|
1268
|
-
try {
|
|
1269
|
-
const packageJson = require_package();
|
|
1270
|
-
return packageJson.version || null;
|
|
1271
|
-
} catch {
|
|
1272
|
-
return null;
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
async function fetchLatestVersion() {
|
|
1276
|
-
const lastCheck = versionCache.get("lastCheck") || 0;
|
|
1277
|
-
const cachedVersion = versionCache.get("latestVersion");
|
|
1278
|
-
if (cachedVersion && Date.now() - lastCheck < VERSION_CACHE_TTL_MS) {
|
|
1279
|
-
return cachedVersion;
|
|
1280
|
-
}
|
|
1281
|
-
try {
|
|
1282
|
-
const https = await import("https");
|
|
1283
|
-
return new Promise((resolve) => {
|
|
1284
|
-
const req = https.get(
|
|
1285
|
-
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
1286
|
-
{ timeout: 5e3 },
|
|
1287
|
-
(res) => {
|
|
1288
|
-
let data = "";
|
|
1289
|
-
res.on("data", (chunk) => {
|
|
1290
|
-
data += chunk;
|
|
1291
|
-
});
|
|
1292
|
-
res.on("end", () => {
|
|
1293
|
-
try {
|
|
1294
|
-
const json = JSON.parse(data);
|
|
1295
|
-
const version = json.version || null;
|
|
1296
|
-
if (version) {
|
|
1297
|
-
versionCache.set("latestVersion", version);
|
|
1298
|
-
versionCache.set("lastCheck", Date.now());
|
|
1299
|
-
}
|
|
1300
|
-
resolve(version);
|
|
1301
|
-
} catch {
|
|
1302
|
-
resolve(cachedVersion || null);
|
|
1303
|
-
}
|
|
1304
|
-
});
|
|
1305
|
-
}
|
|
1306
|
-
);
|
|
1307
|
-
req.on("error", () => resolve(cachedVersion || null));
|
|
1308
|
-
req.on("timeout", () => {
|
|
1309
|
-
req.destroy();
|
|
1310
|
-
resolve(cachedVersion || null);
|
|
1311
|
-
});
|
|
1312
|
-
});
|
|
1313
|
-
} catch {
|
|
1314
|
-
return cachedVersion || null;
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
async function checkForUpdate() {
|
|
1318
|
-
const currentVersion = getCurrentVersion();
|
|
1319
|
-
if (!currentVersion) {
|
|
1320
|
-
return { hasUpdate: false, currentVersion: null, latestVersion: null };
|
|
1321
|
-
}
|
|
1322
|
-
const latestVersion = await fetchLatestVersion();
|
|
1323
|
-
const hasUpdate = !!(latestVersion && semver.gt(latestVersion, currentVersion));
|
|
1324
|
-
return { hasUpdate, currentVersion, latestVersion };
|
|
1325
|
-
}
|
|
1326
|
-
function getUpdateCommand() {
|
|
1327
|
-
return `pnpm add ${DJANGOCFG_PACKAGES.map((p) => `${p}@latest`).join(" ")}`;
|
|
1328
|
-
}
|
|
1329
|
-
async function printVersionInfo() {
|
|
1330
|
-
const { hasUpdate, currentVersion, latestVersion } = await checkForUpdate();
|
|
1331
|
-
if (!currentVersion) return;
|
|
1332
|
-
consola.box(`\u{1F4E6} @djangocfg/nextjs v${currentVersion}`);
|
|
1333
|
-
if (hasUpdate && latestVersion) {
|
|
1334
|
-
consola.warn(`Update Available! ${chalk.red(currentVersion)} \u2192 ${chalk.green(latestVersion)}`);
|
|
1335
|
-
consola.info(`Run: ${chalk.cyan(getUpdateCommand())}`);
|
|
1336
|
-
console.log("");
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// src/config/packages/installer.ts
|
|
1341
|
-
import { execSync, spawn } from "child_process";
|
|
1342
|
-
import { createInterface } from "readline";
|
|
1343
|
-
import chalk2 from "chalk";
|
|
1344
|
-
import consola2 from "consola";
|
|
1345
|
-
import Conf2 from "conf";
|
|
1346
|
-
|
|
1347
|
-
// src/config/packages/checker.ts
|
|
1348
|
-
import { createRequire } from "module";
|
|
1349
|
-
import { join } from "path";
|
|
1350
|
-
|
|
1351
1247
|
// src/config/packages/definitions.ts
|
|
1352
1248
|
var OPTIONAL_PACKAGES = [
|
|
1353
1249
|
{
|
|
@@ -1426,23 +1322,105 @@ function checkPackages(packageNames) {
|
|
|
1426
1322
|
});
|
|
1427
1323
|
}
|
|
1428
1324
|
}
|
|
1429
|
-
return missing;
|
|
1325
|
+
return missing;
|
|
1326
|
+
}
|
|
1327
|
+
function getReasonText(pkg) {
|
|
1328
|
+
switch (pkg.condition) {
|
|
1329
|
+
case "static-build":
|
|
1330
|
+
return "Required for static build (NEXT_PUBLIC_STATIC_BUILD=true)";
|
|
1331
|
+
case "dev":
|
|
1332
|
+
return "Required for development mode";
|
|
1333
|
+
case "always":
|
|
1334
|
+
return "Required for all builds";
|
|
1335
|
+
default:
|
|
1336
|
+
return "Optional feature";
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// src/config/plugins/compression.ts
|
|
1341
|
+
var DEFAULT_OPTIONS = {
|
|
1342
|
+
gzip: true,
|
|
1343
|
+
brotli: true,
|
|
1344
|
+
threshold: 8192,
|
|
1345
|
+
minRatio: 0.8,
|
|
1346
|
+
brotliLevel: 8
|
|
1347
|
+
};
|
|
1348
|
+
function addCompressionPlugins(config, options = {}) {
|
|
1349
|
+
if (!isPackageInstalled("compression-webpack-plugin")) {
|
|
1350
|
+
return false;
|
|
1351
|
+
}
|
|
1352
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1353
|
+
try {
|
|
1354
|
+
const CompressionPlugin = __require("compression-webpack-plugin");
|
|
1355
|
+
if (!config.plugins) {
|
|
1356
|
+
config.plugins = [];
|
|
1357
|
+
}
|
|
1358
|
+
if (opts.gzip) {
|
|
1359
|
+
config.plugins.push(
|
|
1360
|
+
new CompressionPlugin({
|
|
1361
|
+
filename: "[path][base].gz",
|
|
1362
|
+
algorithm: "gzip",
|
|
1363
|
+
test: /\.(js|css|html|svg|json)$/,
|
|
1364
|
+
threshold: opts.threshold,
|
|
1365
|
+
minRatio: opts.minRatio
|
|
1366
|
+
})
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
if (opts.brotli) {
|
|
1370
|
+
config.plugins.push(
|
|
1371
|
+
new CompressionPlugin({
|
|
1372
|
+
filename: "[path][base].br",
|
|
1373
|
+
algorithm: "brotliCompress",
|
|
1374
|
+
test: /\.(js|css|html|svg|json)$/,
|
|
1375
|
+
threshold: opts.threshold,
|
|
1376
|
+
minRatio: opts.minRatio,
|
|
1377
|
+
compressionOptions: {
|
|
1378
|
+
level: opts.brotliLevel
|
|
1379
|
+
}
|
|
1380
|
+
})
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
return true;
|
|
1384
|
+
} catch (error) {
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1430
1387
|
}
|
|
1431
|
-
function
|
|
1432
|
-
|
|
1433
|
-
case "static-build":
|
|
1434
|
-
return "Required for static build (NEXT_PUBLIC_STATIC_BUILD=true)";
|
|
1435
|
-
case "dev":
|
|
1436
|
-
return "Required for development mode";
|
|
1437
|
-
case "always":
|
|
1438
|
-
return "Required for all builds";
|
|
1439
|
-
default:
|
|
1440
|
-
return "Optional feature";
|
|
1441
|
-
}
|
|
1388
|
+
function isCompressionAvailable() {
|
|
1389
|
+
return isPackageInstalled("compression-webpack-plugin");
|
|
1442
1390
|
}
|
|
1443
1391
|
|
|
1392
|
+
// src/config/plugins/devStartup.ts
|
|
1393
|
+
import chalk4 from "chalk";
|
|
1394
|
+
|
|
1395
|
+
// src/ai/constants.ts
|
|
1396
|
+
var MCP_BASE_URL = "https://mcp.djangocfg.com";
|
|
1397
|
+
var MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
|
|
1398
|
+
var MCP_API_URL = `${MCP_BASE_URL}/api/search`;
|
|
1399
|
+
var API_SEARCH_ENDPOINT = "/api/search";
|
|
1400
|
+
var API_INFO_ENDPOINT = "/api/info";
|
|
1401
|
+
var DEFAULT_TIMEOUT = 1e4;
|
|
1402
|
+
var AI_DOCS_HINT = `\u{1F916} AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search "query"`;
|
|
1403
|
+
var AI_HINT = `
|
|
1404
|
+
DjangoCFG Documentation is available via MCP server.
|
|
1405
|
+
|
|
1406
|
+
To get help with DjangoCFG configuration:
|
|
1407
|
+
1. Use the MCP server: ${MCP_SERVER_URL}
|
|
1408
|
+
2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5
|
|
1409
|
+
|
|
1410
|
+
Example queries:
|
|
1411
|
+
- "How to configure PostgreSQL database?"
|
|
1412
|
+
- "What is DatabaseConfig?"
|
|
1413
|
+
- "How to setup Redis cache?"
|
|
1414
|
+
- "Email configuration with SMTP"
|
|
1415
|
+
`;
|
|
1416
|
+
|
|
1444
1417
|
// src/config/packages/installer.ts
|
|
1445
|
-
|
|
1418
|
+
import chalk from "chalk";
|
|
1419
|
+
import { execSync, spawn } from "child_process";
|
|
1420
|
+
import Conf from "conf";
|
|
1421
|
+
import consola2 from "consola";
|
|
1422
|
+
import { createInterface } from "readline";
|
|
1423
|
+
var installerCache = new Conf({
|
|
1446
1424
|
projectName: "djangocfg-nextjs-installer",
|
|
1447
1425
|
projectVersion: "1.0.0"
|
|
1448
1426
|
});
|
|
@@ -1536,7 +1514,7 @@ function createSpinner(text) {
|
|
|
1536
1514
|
let currentText = text;
|
|
1537
1515
|
const render = () => {
|
|
1538
1516
|
const frame = SPINNER_FRAMES[frameIndex];
|
|
1539
|
-
process.stdout.write(`\r${
|
|
1517
|
+
process.stdout.write(`\r${chalk.cyan(frame)} ${currentText}`);
|
|
1540
1518
|
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
1541
1519
|
};
|
|
1542
1520
|
return {
|
|
@@ -1559,20 +1537,20 @@ function createSpinner(text) {
|
|
|
1559
1537
|
succeed(text2) {
|
|
1560
1538
|
if (interval) clearInterval(interval);
|
|
1561
1539
|
if (process.stdout.isTTY) {
|
|
1562
|
-
process.stdout.write(`\r${
|
|
1540
|
+
process.stdout.write(`\r${chalk.green("\u2713")} ${text2 || currentText}
|
|
1563
1541
|
`);
|
|
1564
1542
|
} else {
|
|
1565
|
-
console.log(` ${
|
|
1543
|
+
console.log(` ${chalk.green("\u2713")} ${text2 || currentText}`);
|
|
1566
1544
|
}
|
|
1567
1545
|
return this;
|
|
1568
1546
|
},
|
|
1569
1547
|
fail(text2) {
|
|
1570
1548
|
if (interval) clearInterval(interval);
|
|
1571
1549
|
if (process.stdout.isTTY) {
|
|
1572
|
-
process.stdout.write(`\r${
|
|
1550
|
+
process.stdout.write(`\r${chalk.red("\u2717")} ${text2 || currentText}
|
|
1573
1551
|
`);
|
|
1574
1552
|
} else {
|
|
1575
|
-
console.log(` ${
|
|
1553
|
+
console.log(` ${chalk.red("\u2717")} ${text2 || currentText}`);
|
|
1576
1554
|
}
|
|
1577
1555
|
return this;
|
|
1578
1556
|
},
|
|
@@ -1588,7 +1566,7 @@ function createSpinner(text) {
|
|
|
1588
1566
|
async function installSinglePackage(pkg, pm, index, total) {
|
|
1589
1567
|
const command = buildSingleInstallCommand(pkg.name, pkg.devDependency, pm);
|
|
1590
1568
|
const progress = `[${index + 1}/${total}]`;
|
|
1591
|
-
const spinner = createSpinner(`${
|
|
1569
|
+
const spinner = createSpinner(`${chalk.dim(progress)} Installing ${chalk.cyan(pkg.name)}...`);
|
|
1592
1570
|
spinner.start();
|
|
1593
1571
|
return new Promise((resolve) => {
|
|
1594
1572
|
const [cmd, ...args] = command.split(" ");
|
|
@@ -1603,18 +1581,18 @@ async function installSinglePackage(pkg, pm, index, total) {
|
|
|
1603
1581
|
});
|
|
1604
1582
|
proc.on("close", (code) => {
|
|
1605
1583
|
if (code === 0) {
|
|
1606
|
-
spinner.succeed(`${
|
|
1584
|
+
spinner.succeed(`${chalk.dim(progress)} ${chalk.cyan(pkg.name)} ${chalk.green("installed")}`);
|
|
1607
1585
|
resolve(true);
|
|
1608
1586
|
} else {
|
|
1609
|
-
spinner.fail(`${
|
|
1587
|
+
spinner.fail(`${chalk.dim(progress)} ${chalk.cyan(pkg.name)} ${chalk.red("failed")}`);
|
|
1610
1588
|
if (stderr) {
|
|
1611
|
-
console.log(
|
|
1589
|
+
console.log(chalk.dim(` ${stderr.split("\n")[0]}`));
|
|
1612
1590
|
}
|
|
1613
1591
|
resolve(false);
|
|
1614
1592
|
}
|
|
1615
1593
|
});
|
|
1616
1594
|
proc.on("error", () => {
|
|
1617
|
-
spinner.fail(`${
|
|
1595
|
+
spinner.fail(`${chalk.dim(progress)} ${chalk.cyan(pkg.name)} ${chalk.red("failed")}`);
|
|
1618
1596
|
resolve(false);
|
|
1619
1597
|
});
|
|
1620
1598
|
});
|
|
@@ -1624,7 +1602,7 @@ async function installPackagesWithProgress(packages) {
|
|
|
1624
1602
|
const pm = detectPackageManager();
|
|
1625
1603
|
const total = packages.length;
|
|
1626
1604
|
console.log("");
|
|
1627
|
-
console.log(
|
|
1605
|
+
console.log(chalk.bold(` Installing ${total} package${total > 1 ? "s" : ""}...`));
|
|
1628
1606
|
console.log("");
|
|
1629
1607
|
let successCount = 0;
|
|
1630
1608
|
let failedPackages = [];
|
|
@@ -1655,7 +1633,7 @@ async function installPackages(packages) {
|
|
|
1655
1633
|
if (packages.length === 0) return true;
|
|
1656
1634
|
const pm = detectPackageManager();
|
|
1657
1635
|
const command = buildInstallCommand(packages, pm);
|
|
1658
|
-
consola2.info(`Installing: ${
|
|
1636
|
+
consola2.info(`Installing: ${chalk.cyan(packages.map((p) => p.name).join(", "))}`);
|
|
1659
1637
|
const spinner = createSpinner("Installing packages...");
|
|
1660
1638
|
spinner.start();
|
|
1661
1639
|
return new Promise((resolve) => {
|
|
@@ -1698,24 +1676,24 @@ async function checkAndInstallPackages(options = {}) {
|
|
|
1698
1676
|
consola2.box("\u{1F4E6} Missing Optional Packages");
|
|
1699
1677
|
console.log("");
|
|
1700
1678
|
for (const pkg of toInstall) {
|
|
1701
|
-
console.log(` ${
|
|
1702
|
-
console.log(` ${
|
|
1703
|
-
console.log(` ${
|
|
1679
|
+
console.log(` ${chalk.yellow("\u2022")} ${chalk.bold(pkg.name)}`);
|
|
1680
|
+
console.log(` ${chalk.dim(pkg.description)}`);
|
|
1681
|
+
console.log(` ${chalk.dim(pkg.reason)}`);
|
|
1704
1682
|
console.log("");
|
|
1705
1683
|
}
|
|
1706
1684
|
const pm = detectPackageManager();
|
|
1707
1685
|
const command = buildInstallCommand(toInstall, pm);
|
|
1708
|
-
console.log(` ${
|
|
1686
|
+
console.log(` ${chalk.cyan("Command:")} ${command}`);
|
|
1709
1687
|
console.log("");
|
|
1710
1688
|
installerCache.set("lastPrompt", Date.now());
|
|
1711
1689
|
const shouldInstall = await askConfirmation(
|
|
1712
|
-
`${
|
|
1690
|
+
`${chalk.green("?")} Install these packages now? ${chalk.dim("[Y/n]")} `
|
|
1713
1691
|
);
|
|
1714
1692
|
if (shouldInstall) {
|
|
1715
1693
|
const success = await installPackages(toInstall);
|
|
1716
1694
|
if (success) {
|
|
1717
1695
|
const enableAuto = await askConfirmation(
|
|
1718
|
-
`${
|
|
1696
|
+
`${chalk.green("?")} Enable auto-install for future? ${chalk.dim("[y/N]")} `
|
|
1719
1697
|
);
|
|
1720
1698
|
if (enableAuto) {
|
|
1721
1699
|
installerCache.set("autoInstall", true);
|
|
@@ -1725,7 +1703,7 @@ async function checkAndInstallPackages(options = {}) {
|
|
|
1725
1703
|
return success;
|
|
1726
1704
|
}
|
|
1727
1705
|
const skipPermanently = await askConfirmation(
|
|
1728
|
-
`${
|
|
1706
|
+
`${chalk.green("?")} Skip these packages in future prompts? ${chalk.dim("[y/N]")} `
|
|
1729
1707
|
);
|
|
1730
1708
|
if (skipPermanently) {
|
|
1731
1709
|
const currentSkip = installerCache.get("skipPackages") || [];
|
|
@@ -1739,7 +1717,7 @@ function printMissingPackagesInfo(packages) {
|
|
|
1739
1717
|
const pm = detectPackageManager();
|
|
1740
1718
|
const command = buildInstallCommand(packages, pm);
|
|
1741
1719
|
consola2.warn(`Missing optional packages: ${packages.map((p) => p.name).join(", ")}`);
|
|
1742
|
-
consola2.info(`Install with: ${
|
|
1720
|
+
consola2.info(`Install with: ${chalk.cyan(command)}`);
|
|
1743
1721
|
}
|
|
1744
1722
|
function resetInstallerPreferences() {
|
|
1745
1723
|
installerCache.clear();
|
|
@@ -1747,15 +1725,15 @@ function resetInstallerPreferences() {
|
|
|
1747
1725
|
}
|
|
1748
1726
|
|
|
1749
1727
|
// src/config/packages/updater.ts
|
|
1728
|
+
import chalk2 from "chalk";
|
|
1750
1729
|
import { spawn as spawn2 } from "child_process";
|
|
1751
|
-
import
|
|
1730
|
+
import Conf2 from "conf";
|
|
1731
|
+
import consola3 from "consola";
|
|
1752
1732
|
import { createRequire as createRequire2 } from "module";
|
|
1753
1733
|
import { join as join2 } from "path";
|
|
1754
|
-
import
|
|
1755
|
-
import
|
|
1756
|
-
|
|
1757
|
-
import semver2 from "semver";
|
|
1758
|
-
var updaterCache = new Conf3({
|
|
1734
|
+
import { createInterface as createInterface2 } from "readline";
|
|
1735
|
+
import semver from "semver";
|
|
1736
|
+
var updaterCache = new Conf2({
|
|
1759
1737
|
projectName: "djangocfg-nextjs-updater",
|
|
1760
1738
|
projectVersion: "1.0.0"
|
|
1761
1739
|
});
|
|
@@ -1802,7 +1780,7 @@ function getInstalledVersion(packageName) {
|
|
|
1802
1780
|
function shouldCheckUpdates(packageName) {
|
|
1803
1781
|
return !isWorkspacePackage(packageName);
|
|
1804
1782
|
}
|
|
1805
|
-
async function
|
|
1783
|
+
async function fetchLatestVersion(packageName) {
|
|
1806
1784
|
try {
|
|
1807
1785
|
const https = await import("https");
|
|
1808
1786
|
return new Promise((resolve) => {
|
|
@@ -1836,7 +1814,7 @@ async function fetchLatestVersion2(packageName) {
|
|
|
1836
1814
|
}
|
|
1837
1815
|
async function checkForUpdates(options = {}) {
|
|
1838
1816
|
const results = [];
|
|
1839
|
-
const masterLatest = await
|
|
1817
|
+
const masterLatest = await fetchLatestVersion(PACKAGE_NAME);
|
|
1840
1818
|
if (!masterLatest) {
|
|
1841
1819
|
return results;
|
|
1842
1820
|
}
|
|
@@ -1849,7 +1827,7 @@ async function checkForUpdates(options = {}) {
|
|
|
1849
1827
|
if (!current) {
|
|
1850
1828
|
return null;
|
|
1851
1829
|
}
|
|
1852
|
-
const hasUpdate = !!(masterLatest && current &&
|
|
1830
|
+
const hasUpdate = !!(masterLatest && current && semver.gt(masterLatest, current));
|
|
1853
1831
|
return { name, current, latest: masterLatest, hasUpdate };
|
|
1854
1832
|
});
|
|
1855
1833
|
const checkResults = await Promise.all(checks);
|
|
@@ -1875,7 +1853,7 @@ function createSpinner2(text) {
|
|
|
1875
1853
|
let currentText = text;
|
|
1876
1854
|
const render = () => {
|
|
1877
1855
|
const frame = SPINNER_FRAMES2[frameIndex];
|
|
1878
|
-
process.stdout.write(`\r${
|
|
1856
|
+
process.stdout.write(`\r${chalk2.cyan(frame)} ${currentText}`);
|
|
1879
1857
|
frameIndex = (frameIndex + 1) % SPINNER_FRAMES2.length;
|
|
1880
1858
|
};
|
|
1881
1859
|
return {
|
|
@@ -1895,20 +1873,20 @@ function createSpinner2(text) {
|
|
|
1895
1873
|
succeed(text2) {
|
|
1896
1874
|
if (interval) clearInterval(interval);
|
|
1897
1875
|
if (process.stdout.isTTY) {
|
|
1898
|
-
process.stdout.write(`\r${
|
|
1876
|
+
process.stdout.write(`\r${chalk2.green("\u2713")} ${text2 || currentText}
|
|
1899
1877
|
`);
|
|
1900
1878
|
} else {
|
|
1901
|
-
console.log(` ${
|
|
1879
|
+
console.log(` ${chalk2.green("\u2713")} ${text2 || currentText}`);
|
|
1902
1880
|
}
|
|
1903
1881
|
return this;
|
|
1904
1882
|
},
|
|
1905
1883
|
fail(text2) {
|
|
1906
1884
|
if (interval) clearInterval(interval);
|
|
1907
1885
|
if (process.stdout.isTTY) {
|
|
1908
|
-
process.stdout.write(`\r${
|
|
1886
|
+
process.stdout.write(`\r${chalk2.red("\u2717")} ${text2 || currentText}
|
|
1909
1887
|
`);
|
|
1910
1888
|
} else {
|
|
1911
|
-
console.log(` ${
|
|
1889
|
+
console.log(` ${chalk2.red("\u2717")} ${text2 || currentText}`);
|
|
1912
1890
|
}
|
|
1913
1891
|
return this;
|
|
1914
1892
|
},
|
|
@@ -1939,9 +1917,9 @@ async function askConfirmation2(question) {
|
|
|
1939
1917
|
}
|
|
1940
1918
|
async function updateSinglePackage(pkg, pm, index, total) {
|
|
1941
1919
|
const progress = `[${index + 1}/${total}]`;
|
|
1942
|
-
const versionInfo = `${
|
|
1920
|
+
const versionInfo = `${chalk2.red(pkg.current)} \u2192 ${chalk2.green(pkg.latest)}`;
|
|
1943
1921
|
const spinner = createSpinner2(
|
|
1944
|
-
`${
|
|
1922
|
+
`${chalk2.dim(progress)} Updating ${chalk2.cyan(pkg.name)} ${versionInfo}`
|
|
1945
1923
|
);
|
|
1946
1924
|
spinner.start();
|
|
1947
1925
|
const command = pm === "pnpm" ? `pnpm add ${pkg.name}@latest` : pm === "yarn" ? `yarn add ${pkg.name}@latest` : `npm install ${pkg.name}@latest`;
|
|
@@ -1954,18 +1932,18 @@ async function updateSinglePackage(pkg, pm, index, total) {
|
|
|
1954
1932
|
proc.on("close", (code) => {
|
|
1955
1933
|
if (code === 0) {
|
|
1956
1934
|
spinner.succeed(
|
|
1957
|
-
`${
|
|
1935
|
+
`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.green(pkg.latest)}`
|
|
1958
1936
|
);
|
|
1959
1937
|
resolve(true);
|
|
1960
1938
|
} else {
|
|
1961
1939
|
spinner.fail(
|
|
1962
|
-
`${
|
|
1940
|
+
`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.red("failed")}`
|
|
1963
1941
|
);
|
|
1964
1942
|
resolve(false);
|
|
1965
1943
|
}
|
|
1966
1944
|
});
|
|
1967
1945
|
proc.on("error", () => {
|
|
1968
|
-
spinner.fail(`${
|
|
1946
|
+
spinner.fail(`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.red("failed")}`);
|
|
1969
1947
|
resolve(false);
|
|
1970
1948
|
});
|
|
1971
1949
|
});
|
|
@@ -1975,7 +1953,7 @@ async function updatePackagesWithProgress(packages) {
|
|
|
1975
1953
|
const pm = detectPackageManager();
|
|
1976
1954
|
const total = packages.length;
|
|
1977
1955
|
console.log("");
|
|
1978
|
-
console.log(
|
|
1956
|
+
console.log(chalk2.bold(` Updating ${total} package${total > 1 ? "s" : ""}...`));
|
|
1979
1957
|
console.log("");
|
|
1980
1958
|
let successCount = 0;
|
|
1981
1959
|
const failedPackages = [];
|
|
@@ -2011,9 +1989,9 @@ async function checkAndUpdatePackages(options = {}) {
|
|
|
2011
1989
|
forceCheckWorkspace: options.forceCheckWorkspace
|
|
2012
1990
|
});
|
|
2013
1991
|
spinner.stop();
|
|
2014
|
-
console.log(
|
|
1992
|
+
console.log(chalk2.dim(` Found ${outdated.length} outdated package(s)`));
|
|
2015
1993
|
if (outdated.length === 0) {
|
|
2016
|
-
console.log(
|
|
1994
|
+
console.log(chalk2.green(" \u2713 All packages are up to date"));
|
|
2017
1995
|
return true;
|
|
2018
1996
|
}
|
|
2019
1997
|
if (options.autoUpdate || updaterCache.get("autoUpdate")) {
|
|
@@ -2024,18 +2002,18 @@ async function checkAndUpdatePackages(options = {}) {
|
|
|
2024
2002
|
console.log("");
|
|
2025
2003
|
for (const pkg of outdated) {
|
|
2026
2004
|
console.log(
|
|
2027
|
-
` ${
|
|
2005
|
+
` ${chalk2.yellow("\u2022")} ${chalk2.bold(pkg.name)} ${chalk2.red(pkg.current)} \u2192 ${chalk2.green(pkg.latest)}`
|
|
2028
2006
|
);
|
|
2029
2007
|
}
|
|
2030
2008
|
console.log("");
|
|
2031
2009
|
const shouldUpdate = await askConfirmation2(
|
|
2032
|
-
`${
|
|
2010
|
+
`${chalk2.green("?")} Update these packages now? ${chalk2.dim("[Y/n]")} `
|
|
2033
2011
|
);
|
|
2034
2012
|
if (shouldUpdate) {
|
|
2035
2013
|
const success = await updatePackagesWithProgress(outdated);
|
|
2036
2014
|
if (success) {
|
|
2037
2015
|
const enableAuto = await askConfirmation2(
|
|
2038
|
-
`${
|
|
2016
|
+
`${chalk2.green("?")} Enable auto-update for future? ${chalk2.dim("[y/N]")} `
|
|
2039
2017
|
);
|
|
2040
2018
|
if (enableAuto) {
|
|
2041
2019
|
updaterCache.set("autoUpdate", true);
|
|
@@ -2045,7 +2023,7 @@ async function checkAndUpdatePackages(options = {}) {
|
|
|
2045
2023
|
return success;
|
|
2046
2024
|
}
|
|
2047
2025
|
const skipVersions = await askConfirmation2(
|
|
2048
|
-
`${
|
|
2026
|
+
`${chalk2.green("?")} Skip these versions in future? ${chalk2.dim("[y/N]")} `
|
|
2049
2027
|
);
|
|
2050
2028
|
if (skipVersions) {
|
|
2051
2029
|
const skipped = updaterCache.get("skippedVersions") || {};
|
|
@@ -2064,6 +2042,88 @@ function resetUpdaterPreferences() {
|
|
|
2064
2042
|
consola3.success("Updater preferences reset");
|
|
2065
2043
|
}
|
|
2066
2044
|
|
|
2045
|
+
// src/config/utils/version.ts
|
|
2046
|
+
import chalk3 from "chalk";
|
|
2047
|
+
import Conf3 from "conf";
|
|
2048
|
+
import consola4 from "consola";
|
|
2049
|
+
import semver2 from "semver";
|
|
2050
|
+
var versionCache = new Conf3({
|
|
2051
|
+
projectName: "djangocfg-nextjs",
|
|
2052
|
+
projectVersion: "1.0.0"
|
|
2053
|
+
});
|
|
2054
|
+
function getCurrentVersion() {
|
|
2055
|
+
try {
|
|
2056
|
+
const packageJson = require_package();
|
|
2057
|
+
return packageJson.version || null;
|
|
2058
|
+
} catch {
|
|
2059
|
+
return null;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
async function fetchLatestVersion2() {
|
|
2063
|
+
const lastCheck = versionCache.get("lastCheck") || 0;
|
|
2064
|
+
const cachedVersion = versionCache.get("latestVersion");
|
|
2065
|
+
if (cachedVersion && Date.now() - lastCheck < VERSION_CACHE_TTL_MS) {
|
|
2066
|
+
return cachedVersion;
|
|
2067
|
+
}
|
|
2068
|
+
try {
|
|
2069
|
+
const https = await import("https");
|
|
2070
|
+
return new Promise((resolve) => {
|
|
2071
|
+
const req = https.get(
|
|
2072
|
+
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
2073
|
+
{ timeout: 5e3 },
|
|
2074
|
+
(res) => {
|
|
2075
|
+
let data = "";
|
|
2076
|
+
res.on("data", (chunk) => {
|
|
2077
|
+
data += chunk;
|
|
2078
|
+
});
|
|
2079
|
+
res.on("end", () => {
|
|
2080
|
+
try {
|
|
2081
|
+
const json = JSON.parse(data);
|
|
2082
|
+
const version = json.version || null;
|
|
2083
|
+
if (version) {
|
|
2084
|
+
versionCache.set("latestVersion", version);
|
|
2085
|
+
versionCache.set("lastCheck", Date.now());
|
|
2086
|
+
}
|
|
2087
|
+
resolve(version);
|
|
2088
|
+
} catch {
|
|
2089
|
+
resolve(cachedVersion || null);
|
|
2090
|
+
}
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2094
|
+
req.on("error", () => resolve(cachedVersion || null));
|
|
2095
|
+
req.on("timeout", () => {
|
|
2096
|
+
req.destroy();
|
|
2097
|
+
resolve(cachedVersion || null);
|
|
2098
|
+
});
|
|
2099
|
+
});
|
|
2100
|
+
} catch {
|
|
2101
|
+
return cachedVersion || null;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
async function checkForUpdate() {
|
|
2105
|
+
const currentVersion = getCurrentVersion();
|
|
2106
|
+
if (!currentVersion) {
|
|
2107
|
+
return { hasUpdate: false, currentVersion: null, latestVersion: null };
|
|
2108
|
+
}
|
|
2109
|
+
const latestVersion = await fetchLatestVersion2();
|
|
2110
|
+
const hasUpdate = !!(latestVersion && semver2.gt(latestVersion, currentVersion));
|
|
2111
|
+
return { hasUpdate, currentVersion, latestVersion };
|
|
2112
|
+
}
|
|
2113
|
+
function getUpdateCommand() {
|
|
2114
|
+
return `pnpm add ${DJANGOCFG_PACKAGES.map((p) => `${p}@latest`).join(" ")}`;
|
|
2115
|
+
}
|
|
2116
|
+
async function printVersionInfo() {
|
|
2117
|
+
const { hasUpdate, currentVersion, latestVersion } = await checkForUpdate();
|
|
2118
|
+
if (!currentVersion) return;
|
|
2119
|
+
consola4.box(`\u{1F4E6} @djangocfg/nextjs v${currentVersion}`);
|
|
2120
|
+
if (hasUpdate && latestVersion) {
|
|
2121
|
+
consola4.warn(`Update Available! ${chalk3.red(currentVersion)} \u2192 ${chalk3.green(latestVersion)}`);
|
|
2122
|
+
consola4.info(`Run: ${chalk3.cyan(getUpdateCommand())}`);
|
|
2123
|
+
console.log("");
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2067
2127
|
// src/config/plugins/devStartup.ts
|
|
2068
2128
|
var startupDone = false;
|
|
2069
2129
|
var DevStartupPlugin = class {
|
|
@@ -2134,87 +2194,25 @@ function resetDevStartupState() {
|
|
|
2134
2194
|
startupDone = false;
|
|
2135
2195
|
}
|
|
2136
2196
|
|
|
2137
|
-
// src/config/
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
config.plugins = [];
|
|
2154
|
-
}
|
|
2155
|
-
if (opts.gzip) {
|
|
2156
|
-
config.plugins.push(
|
|
2157
|
-
new CompressionPlugin({
|
|
2158
|
-
filename: "[path][base].gz",
|
|
2159
|
-
algorithm: "gzip",
|
|
2160
|
-
test: /\.(js|css|html|svg|json)$/,
|
|
2161
|
-
threshold: opts.threshold,
|
|
2162
|
-
minRatio: opts.minRatio
|
|
2163
|
-
})
|
|
2164
|
-
);
|
|
2165
|
-
}
|
|
2166
|
-
if (opts.brotli) {
|
|
2167
|
-
config.plugins.push(
|
|
2168
|
-
new CompressionPlugin({
|
|
2169
|
-
filename: "[path][base].br",
|
|
2170
|
-
algorithm: "brotliCompress",
|
|
2171
|
-
test: /\.(js|css|html|svg|json)$/,
|
|
2172
|
-
threshold: opts.threshold,
|
|
2173
|
-
minRatio: opts.minRatio,
|
|
2174
|
-
compressionOptions: {
|
|
2175
|
-
level: opts.brotliLevel
|
|
2176
|
-
}
|
|
2177
|
-
})
|
|
2178
|
-
);
|
|
2197
|
+
// src/config/utils/deepMerge.ts
|
|
2198
|
+
function deepMerge(target, source) {
|
|
2199
|
+
const output = { ...target };
|
|
2200
|
+
for (const key in source) {
|
|
2201
|
+
if (source[key] === void 0) continue;
|
|
2202
|
+
if (Array.isArray(source[key])) {
|
|
2203
|
+
output[key] = source[key];
|
|
2204
|
+
} else if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
2205
|
+
const targetValue = output[key];
|
|
2206
|
+
if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
2207
|
+
output[key] = deepMerge(targetValue, source[key]);
|
|
2208
|
+
} else {
|
|
2209
|
+
output[key] = source[key];
|
|
2210
|
+
}
|
|
2211
|
+
} else {
|
|
2212
|
+
output[key] = source[key];
|
|
2179
2213
|
}
|
|
2180
|
-
return true;
|
|
2181
|
-
} catch (error) {
|
|
2182
|
-
return false;
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
function isCompressionAvailable() {
|
|
2186
|
-
return isPackageInstalled("compression-webpack-plugin");
|
|
2187
|
-
}
|
|
2188
|
-
|
|
2189
|
-
// src/pwa/plugin.ts
|
|
2190
|
-
import { consola as consola4 } from "consola";
|
|
2191
|
-
function withPWA(nextConfig, options = {}) {
|
|
2192
|
-
const isDev2 = process.env.NODE_ENV === "development";
|
|
2193
|
-
const isStaticBuild2 = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
|
|
2194
|
-
const shouldDisable = options.disable !== void 0 ? options.disable : isDev2 || isStaticBuild2;
|
|
2195
|
-
const defaultOptions = {
|
|
2196
|
-
swSrc: "app/sw.ts",
|
|
2197
|
-
swDest: "public/sw.js",
|
|
2198
|
-
disable: shouldDisable,
|
|
2199
|
-
cacheOnNavigation: true,
|
|
2200
|
-
reloadOnOnline: true,
|
|
2201
|
-
...options
|
|
2202
|
-
};
|
|
2203
|
-
try {
|
|
2204
|
-
const withSerwistInit = __require("@serwist/next").default;
|
|
2205
|
-
const withSerwist = withSerwistInit({
|
|
2206
|
-
swSrc: defaultOptions.swSrc,
|
|
2207
|
-
swDest: defaultOptions.swDest,
|
|
2208
|
-
disable: defaultOptions.disable,
|
|
2209
|
-
cacheOnNavigation: defaultOptions.cacheOnNavigation,
|
|
2210
|
-
reloadOnOnline: defaultOptions.reloadOnOnline,
|
|
2211
|
-
...defaultOptions.serwistOptions
|
|
2212
|
-
});
|
|
2213
|
-
return withSerwist(nextConfig);
|
|
2214
|
-
} catch (error) {
|
|
2215
|
-
consola4.error("Failed to configure Serwist:", error);
|
|
2216
|
-
return nextConfig;
|
|
2217
2214
|
}
|
|
2215
|
+
return output;
|
|
2218
2216
|
}
|
|
2219
2217
|
|
|
2220
2218
|
// src/config/createNextConfig.ts
|
|
@@ -2501,7 +2499,7 @@ export {
|
|
|
2501
2499
|
defineRoute,
|
|
2502
2500
|
detectPackageManager,
|
|
2503
2501
|
encodeBase64,
|
|
2504
|
-
fetchLatestVersion,
|
|
2502
|
+
fetchLatestVersion2 as fetchLatestVersion,
|
|
2505
2503
|
findRoute,
|
|
2506
2504
|
findRouteByPattern,
|
|
2507
2505
|
generateOgImageMetadata,
|