@djangocfg/nextjs 2.1.6 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +3 -3
  2. package/dist/ai/cli.d.mts +1 -0
  3. package/dist/ai/cli.mjs +173 -0
  4. package/dist/ai/cli.mjs.map +1 -0
  5. package/dist/ai/index.d.mts +81 -0
  6. package/dist/ai/index.mjs +139 -0
  7. package/dist/ai/index.mjs.map +1 -0
  8. package/dist/config/index.d.mts +360 -0
  9. package/dist/config/index.mjs +1363 -0
  10. package/dist/config/index.mjs.map +1 -0
  11. package/dist/constants-HezbftFb.d.mts +10 -0
  12. package/dist/contact/index.d.mts +47 -0
  13. package/dist/contact/index.mjs +98 -0
  14. package/dist/contact/index.mjs.map +1 -0
  15. package/dist/contact/route.d.mts +35 -0
  16. package/dist/contact/route.mjs +99 -0
  17. package/dist/contact/route.mjs.map +1 -0
  18. package/dist/health/index.d.mts +43 -0
  19. package/dist/health/index.mjs +38 -0
  20. package/dist/health/index.mjs.map +1 -0
  21. package/dist/index.d.mts +19 -0
  22. package/dist/index.mjs +2565 -0
  23. package/dist/index.mjs.map +1 -0
  24. package/dist/navigation/index.d.mts +89 -0
  25. package/dist/navigation/index.mjs +63 -0
  26. package/dist/navigation/index.mjs.map +1 -0
  27. package/dist/og-image/components/index.d.mts +59 -0
  28. package/dist/og-image/components/index.mjs +325 -0
  29. package/dist/og-image/components/index.mjs.map +1 -0
  30. package/dist/og-image/index.d.mts +112 -0
  31. package/dist/og-image/index.mjs +823 -0
  32. package/dist/og-image/index.mjs.map +1 -0
  33. package/dist/og-image/utils/index.d.mts +302 -0
  34. package/dist/og-image/utils/index.mjs +317 -0
  35. package/dist/og-image/utils/index.mjs.map +1 -0
  36. package/dist/sitemap/index.d.mts +66 -0
  37. package/dist/sitemap/index.mjs +76 -0
  38. package/dist/sitemap/index.mjs.map +1 -0
  39. package/dist/types-CwhXnEbK.d.mts +30 -0
  40. package/package.json +7 -6
  41. package/src/ai/cli.ts +29 -29
package/dist/index.mjs ADDED
@@ -0,0 +1,2565 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+
12
+ // package.json
13
+ var require_package = __commonJS({
14
+ "package.json"(exports, module) {
15
+ module.exports = {
16
+ name: "@djangocfg/nextjs",
17
+ version: "2.1.8",
18
+ description: "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
19
+ keywords: [
20
+ "nextjs",
21
+ "sitemap",
22
+ "health",
23
+ "og-image",
24
+ "contact",
25
+ "navigation",
26
+ "config",
27
+ "react",
28
+ "typescript"
29
+ ],
30
+ author: {
31
+ name: "DjangoCFG",
32
+ url: "https://djangocfg.com"
33
+ },
34
+ homepage: "https://djangocfg.com",
35
+ repository: {
36
+ type: "git",
37
+ url: "https://github.com/markolofsen/django-cfg.git",
38
+ directory: "packages/nextjs"
39
+ },
40
+ bugs: {
41
+ url: "https://github.com/markolofsen/django-cfg/issues"
42
+ },
43
+ license: "MIT",
44
+ main: "./src/index.ts",
45
+ types: "./src/index.ts",
46
+ exports: {
47
+ ".": {
48
+ types: "./src/index.ts",
49
+ import: "./src/index.ts",
50
+ default: "./src/index.ts"
51
+ },
52
+ "./sitemap": {
53
+ types: "./src/sitemap/index.ts",
54
+ import: "./src/sitemap/index.ts",
55
+ default: "./src/sitemap/index.ts"
56
+ },
57
+ "./health": {
58
+ types: "./src/health/index.ts",
59
+ import: "./src/health/index.ts",
60
+ default: "./src/health/index.ts"
61
+ },
62
+ "./og-image": {
63
+ types: "./src/og-image/index.ts",
64
+ import: "./src/og-image/index.ts",
65
+ default: "./src/og-image/index.ts"
66
+ },
67
+ "./og-image/utils": {
68
+ types: "./src/og-image/utils/index.ts",
69
+ import: "./src/og-image/utils/index.ts",
70
+ default: "./src/og-image/utils/index.ts"
71
+ },
72
+ "./og-image/components": {
73
+ types: "./src/og-image/components/index.ts",
74
+ import: "./src/og-image/components/index.ts",
75
+ default: "./src/og-image/components/index.ts"
76
+ },
77
+ "./contact": {
78
+ types: "./src/contact/index.ts",
79
+ import: "./src/contact/index.ts",
80
+ default: "./src/contact/index.ts"
81
+ },
82
+ "./navigation": {
83
+ types: "./src/navigation/index.ts",
84
+ import: "./src/navigation/index.ts",
85
+ default: "./src/navigation/index.ts"
86
+ },
87
+ "./config": {
88
+ types: "./src/config/index.ts",
89
+ import: "./src/config/index.ts",
90
+ default: "./src/config/index.ts"
91
+ },
92
+ "./scripts": {
93
+ types: "./src/scripts/index.ts",
94
+ import: "./src/scripts/index.ts",
95
+ default: "./src/scripts/index.ts"
96
+ },
97
+ "./ai": {
98
+ types: "./src/ai/index.ts",
99
+ import: "./src/ai/index.ts",
100
+ default: "./src/ai/index.ts"
101
+ }
102
+ },
103
+ files: [
104
+ "dist",
105
+ "src",
106
+ "README.md",
107
+ "LICENSE"
108
+ ],
109
+ bin: {
110
+ "djangocfg-docs": "./dist/ai/cli.mjs"
111
+ },
112
+ scripts: {
113
+ build: "tsup",
114
+ dev: "tsup --watch",
115
+ clean: "rm -rf dist",
116
+ lint: "eslint .",
117
+ check: "tsc --noEmit",
118
+ "check-links": "tsx src/scripts/check-links.ts",
119
+ "ai-docs": "tsx src/ai/cli.ts"
120
+ },
121
+ peerDependencies: {
122
+ "@djangocfg/api": "workspace:*",
123
+ next: "^15.5.7"
124
+ },
125
+ devDependencies: {
126
+ "@djangocfg/imgai": "workspace:*",
127
+ "@djangocfg/layouts": "workspace:*",
128
+ "@djangocfg/typescript-config": "workspace:*",
129
+ "@types/node": "^24.7.2",
130
+ "@types/react": "19.2.2",
131
+ "@types/react-dom": "19.2.1",
132
+ "@types/semver": "^7.7.1",
133
+ "@types/webpack": "^5.28.5",
134
+ "@vercel/og": "^0.8.5",
135
+ eslint: "^9.37.0",
136
+ linkinator: "^7.5.0",
137
+ "lucide-react": "^0.545.0",
138
+ picocolors: "^1.1.1",
139
+ prompts: "^2.4.2",
140
+ tsup: "^8.0.1",
141
+ tsx: "^4.19.2",
142
+ typescript: "^5.9.3"
143
+ },
144
+ publishConfig: {
145
+ access: "public"
146
+ },
147
+ dependencies: {
148
+ chalk: "^5.3.0",
149
+ conf: "^15.0.2",
150
+ consola: "^3.4.2",
151
+ semver: "^7.7.3"
152
+ }
153
+ };
154
+ }
155
+ });
156
+
157
+ // src/sitemap/route.ts
158
+ import { NextResponse } from "next/server";
159
+
160
+ // src/sitemap/generator.ts
161
+ function generateSitemapXml(urls) {
162
+ return `<?xml version="1.0" encoding="UTF-8"?>
163
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
164
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
165
+ xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
166
+ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
167
+ ${urls.map(
168
+ ({ loc, lastmod, changefreq, priority }) => ` <url>
169
+ <loc>${escapeXml(loc)}</loc>
170
+ ${lastmod ? `<lastmod>${formatDate(lastmod)}</lastmod>` : ""}
171
+ ${changefreq ? `<changefreq>${changefreq}</changefreq>` : ""}
172
+ ${priority !== void 0 ? `<priority>${priority.toFixed(1)}</priority>` : ""}
173
+ </url>`
174
+ ).join("\n")}
175
+ </urlset>`;
176
+ }
177
+ function formatDate(date) {
178
+ if (typeof date === "string") {
179
+ return date;
180
+ }
181
+ return date.toISOString().split("T")[0];
182
+ }
183
+ function escapeXml(unsafe) {
184
+ return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
185
+ }
186
+ function normalizeUrl(url, siteUrl) {
187
+ if (url.startsWith("http://") || url.startsWith("https://")) {
188
+ return url;
189
+ }
190
+ const baseUrl = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
191
+ const path = url.startsWith("/") ? url : `/${url}`;
192
+ return `${baseUrl}${path}`;
193
+ }
194
+
195
+ // src/sitemap/route.ts
196
+ function createSitemapHandler(options) {
197
+ const {
198
+ siteUrl,
199
+ staticPages = [],
200
+ dynamicPages = [],
201
+ cacheControl = "public, s-maxage=86400, stale-while-revalidate"
202
+ } = options;
203
+ return async function GET() {
204
+ const urls = [...staticPages];
205
+ if (dynamicPages) {
206
+ if (typeof dynamicPages === "function") {
207
+ const dynamicUrls = await dynamicPages();
208
+ urls.push(...dynamicUrls);
209
+ } else {
210
+ urls.push(...dynamicPages);
211
+ }
212
+ }
213
+ const normalizedUrls = urls.map((url) => ({
214
+ ...url,
215
+ loc: normalizeUrl(url.loc, siteUrl)
216
+ }));
217
+ const sitemap = generateSitemapXml(normalizedUrls);
218
+ return new NextResponse(sitemap, {
219
+ status: 200,
220
+ headers: {
221
+ "Content-Type": "application/xml",
222
+ "Cache-Control": cacheControl
223
+ }
224
+ });
225
+ };
226
+ }
227
+
228
+ // src/health/route.ts
229
+ import { NextResponse as NextResponse2 } from "next/server";
230
+ function createHealthHandler(config = {}) {
231
+ const { version, checks = [], customData = {} } = config;
232
+ return async function GET() {
233
+ const startTime = Date.now();
234
+ let status = "ok";
235
+ const checkResults = {};
236
+ if (checks.length > 0) {
237
+ for (const check of checks) {
238
+ try {
239
+ const result = await check.check();
240
+ checkResults[check.name] = result;
241
+ if (!result) {
242
+ status = "error";
243
+ }
244
+ } catch (error) {
245
+ checkResults[check.name] = false;
246
+ status = "error";
247
+ }
248
+ }
249
+ }
250
+ const response = {
251
+ status,
252
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
253
+ uptime: process.uptime(),
254
+ ...version && { version },
255
+ ...Object.keys(checkResults).length > 0 && { checks: checkResults },
256
+ ...customData
257
+ };
258
+ const statusCode = status === "ok" ? 200 : 503;
259
+ return NextResponse2.json(response, { status: statusCode });
260
+ };
261
+ }
262
+
263
+ // src/og-image/route.tsx
264
+ import { ImageResponse } from "next/og";
265
+ import { NextRequest } from "next/server";
266
+
267
+ // src/og-image/utils/fonts.ts
268
+ async function loadGoogleFont(font, text, weight = 700) {
269
+ let url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weight}`;
270
+ if (text) {
271
+ url += `&text=${encodeURIComponent(text)}`;
272
+ }
273
+ try {
274
+ const css = await fetch(url, {
275
+ headers: {
276
+ // Required to get TTF format instead of WOFF2
277
+ "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"
278
+ }
279
+ }).then((res) => res.text());
280
+ const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
281
+ if (!resource || !resource[1]) {
282
+ throw new Error(`Failed to parse font URL from CSS for font: ${font}`);
283
+ }
284
+ const response = await fetch(resource[1]);
285
+ if (response.status !== 200) {
286
+ throw new Error(`Failed to fetch font data: HTTP ${response.status}`);
287
+ }
288
+ return await response.arrayBuffer();
289
+ } catch (error) {
290
+ console.error(`Error loading Google Font "${font}":`, error);
291
+ throw new Error(`Failed to load font "${font}": ${error instanceof Error ? error.message : "Unknown error"}`);
292
+ }
293
+ }
294
+ async function loadGoogleFonts(fonts) {
295
+ const fontConfigs = await Promise.all(
296
+ fonts.map(async ({ family, weight = 700, style = "normal", text }) => {
297
+ const data = await loadGoogleFont(family, text, weight);
298
+ return {
299
+ name: family,
300
+ weight,
301
+ style,
302
+ data
303
+ };
304
+ })
305
+ );
306
+ return fontConfigs;
307
+ }
308
+ function createFontLoader() {
309
+ const cache = /* @__PURE__ */ new Map();
310
+ return {
311
+ /**
312
+ * Load a font with caching
313
+ */
314
+ async load(family, weight = 700, text) {
315
+ const cacheKey = `${family}-${weight}-${text || "all"}`;
316
+ if (!cache.has(cacheKey)) {
317
+ cache.set(cacheKey, loadGoogleFont(family, text, weight));
318
+ }
319
+ return cache.get(cacheKey);
320
+ },
321
+ /**
322
+ * Clear the cache
323
+ */
324
+ clear() {
325
+ cache.clear();
326
+ },
327
+ /**
328
+ * Get cache size
329
+ */
330
+ size() {
331
+ return cache.size;
332
+ }
333
+ };
334
+ }
335
+
336
+ // src/og-image/utils/url.ts
337
+ var DEFAULT_OG_IMAGE_BASE_URL = "https://djangocfg.com/api/og";
338
+ function encodeBase64(str) {
339
+ if (typeof Buffer !== "undefined") {
340
+ return Buffer.from(str, "utf-8").toString("base64");
341
+ }
342
+ return btoa(unescape(encodeURIComponent(str)));
343
+ }
344
+ function decodeBase64(str) {
345
+ if (typeof Buffer !== "undefined") {
346
+ return Buffer.from(str, "base64").toString("utf-8");
347
+ }
348
+ try {
349
+ const binaryString = atob(str);
350
+ return decodeURIComponent(
351
+ binaryString.split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
352
+ );
353
+ } catch (error) {
354
+ return decodeURIComponent(escape(atob(str)));
355
+ }
356
+ }
357
+ function generateOgImageUrl(params, options = {}) {
358
+ const {
359
+ baseUrl = DEFAULT_OG_IMAGE_BASE_URL,
360
+ useBase64 = true
361
+ } = options;
362
+ if (useBase64) {
363
+ const cleanParams = {};
364
+ Object.entries(params).forEach(([key, value]) => {
365
+ if (value !== void 0 && value !== null && value !== "") {
366
+ cleanParams[key] = value;
367
+ }
368
+ });
369
+ const jsonString = JSON.stringify(cleanParams);
370
+ const base64Data = encodeBase64(jsonString);
371
+ return `${baseUrl}/${base64Data}`;
372
+ } else {
373
+ const searchParams = new URLSearchParams();
374
+ Object.entries(params).forEach(([key, value]) => {
375
+ if (value !== void 0 && value !== null && value !== "") {
376
+ searchParams.append(key, String(value));
377
+ }
378
+ });
379
+ const query = searchParams.toString();
380
+ return query ? `${baseUrl}?${query}` : baseUrl;
381
+ }
382
+ }
383
+ function getAbsoluteOgImageUrl(relativePath, siteUrl) {
384
+ if (relativePath.startsWith("http://") || relativePath.startsWith("https://")) {
385
+ return relativePath;
386
+ }
387
+ const cleanSiteUrl = siteUrl.replace(/\/$/, "");
388
+ const cleanPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
389
+ return `${cleanSiteUrl}${cleanPath}`;
390
+ }
391
+ function createOgImageUrlBuilder(defaults = {}, options = {}) {
392
+ return (params) => {
393
+ return generateOgImageUrl(
394
+ { ...defaults, ...params },
395
+ options
396
+ );
397
+ };
398
+ }
399
+ function parseOgImageUrl(url) {
400
+ try {
401
+ const urlObj = new URL(url, "http://dummy.com");
402
+ const params = {};
403
+ urlObj.searchParams.forEach((value, key) => {
404
+ params[key] = value;
405
+ });
406
+ return params;
407
+ } catch {
408
+ return {};
409
+ }
410
+ }
411
+ function parseOgImageData(searchParams) {
412
+ try {
413
+ let params;
414
+ if (searchParams instanceof URLSearchParams) {
415
+ params = {};
416
+ for (const [key, value] of searchParams.entries()) {
417
+ params[key] = value;
418
+ }
419
+ } else {
420
+ params = searchParams;
421
+ }
422
+ if (process.env.NODE_ENV === "development") {
423
+ console.log("[parseOgImageData] Input params keys:", Object.keys(params));
424
+ console.log("[parseOgImageData] Input params:", params);
425
+ }
426
+ const dataParam = params.data;
427
+ if (dataParam && typeof dataParam === "string" && dataParam.trim() !== "") {
428
+ if (process.env.NODE_ENV === "development") {
429
+ console.log("[parseOgImageData] Found data param, length:", dataParam.length);
430
+ }
431
+ try {
432
+ const decoded = decodeBase64(dataParam);
433
+ if (process.env.NODE_ENV === "development") {
434
+ console.log("[parseOgImageData] Decoded string:", decoded.substring(0, 100));
435
+ }
436
+ const parsed = JSON.parse(decoded);
437
+ if (process.env.NODE_ENV === "development") {
438
+ console.log("[parseOgImageData] Parsed JSON:", parsed);
439
+ }
440
+ const result2 = {};
441
+ for (const [key, value] of Object.entries(parsed)) {
442
+ if (value !== void 0 && value !== null) {
443
+ result2[key] = String(value);
444
+ }
445
+ }
446
+ if (process.env.NODE_ENV === "development") {
447
+ console.log("[parseOgImageData] Result:", result2);
448
+ }
449
+ return result2;
450
+ } catch (decodeError) {
451
+ console.error("[parseOgImageData] Error decoding/parsing data param:", decodeError);
452
+ if (decodeError instanceof Error) {
453
+ console.error("[parseOgImageData] Error message:", decodeError.message);
454
+ }
455
+ }
456
+ } else {
457
+ if (process.env.NODE_ENV === "development") {
458
+ console.log("[parseOgImageData] No data param found or empty");
459
+ }
460
+ }
461
+ const result = {};
462
+ for (const [key, value] of Object.entries(params)) {
463
+ if (key !== "data" && value !== void 0 && value !== null) {
464
+ result[key] = Array.isArray(value) ? value[0] : String(value);
465
+ }
466
+ }
467
+ if (process.env.NODE_ENV === "development") {
468
+ console.log("[parseOgImageData] Fallback result:", result);
469
+ }
470
+ return result;
471
+ } catch (error) {
472
+ console.error("[parseOgImageData] Unexpected error:", error);
473
+ return {};
474
+ }
475
+ }
476
+
477
+ // src/og-image/utils/metadata.ts
478
+ function extractTitle(metadata) {
479
+ if (typeof metadata.title === "string") {
480
+ return metadata.title;
481
+ }
482
+ if (metadata.title) {
483
+ if ("default" in metadata.title) {
484
+ return metadata.title.default;
485
+ }
486
+ if ("absolute" in metadata.title) {
487
+ return metadata.title.absolute;
488
+ }
489
+ }
490
+ return "";
491
+ }
492
+ function extractDescription(metadata) {
493
+ if (typeof metadata.description === "string") {
494
+ return metadata.description;
495
+ }
496
+ return "";
497
+ }
498
+ function getSiteUrl() {
499
+ if (typeof process !== "undefined" && process.env.NEXT_PUBLIC_SITE_URL) {
500
+ return process.env.NEXT_PUBLIC_SITE_URL;
501
+ }
502
+ return "";
503
+ }
504
+ function generateOgImageMetadata(metadata, ogImageParams, options = {}) {
505
+ const {
506
+ ogImageBaseUrl = "https://djangocfg.com/api/og",
507
+ siteUrl: providedSiteUrl,
508
+ defaultParams = {},
509
+ useBase64 = true
510
+ } = options;
511
+ const siteUrl = providedSiteUrl && providedSiteUrl !== "undefined" ? providedSiteUrl : getSiteUrl();
512
+ const extractedTitle = extractTitle(metadata);
513
+ const extractedDescription = extractDescription(metadata);
514
+ const finalOgImageParams = {
515
+ ...defaultParams,
516
+ title: ogImageParams?.title || extractedTitle || defaultParams.title || "",
517
+ description: ogImageParams?.description || extractedDescription || defaultParams.description || "",
518
+ ...ogImageParams
519
+ };
520
+ const imageAlt = finalOgImageParams.title || finalOgImageParams.siteName;
521
+ const relativeOgImageUrl = generateOgImageUrl(
522
+ finalOgImageParams,
523
+ { baseUrl: ogImageBaseUrl, useBase64 }
524
+ );
525
+ const ogImageUrl = siteUrl ? getAbsoluteOgImageUrl(relativeOgImageUrl, siteUrl) : relativeOgImageUrl;
526
+ const existingOgImages = metadata.openGraph?.images ? Array.isArray(metadata.openGraph.images) ? metadata.openGraph.images : [metadata.openGraph.images] : [];
527
+ const existingTwitterImages = metadata.twitter?.images ? Array.isArray(metadata.twitter.images) ? metadata.twitter.images : [metadata.twitter.images] : [];
528
+ const finalMetadata = {
529
+ ...metadata,
530
+ openGraph: {
531
+ ...metadata.openGraph,
532
+ images: [
533
+ ...existingOgImages,
534
+ {
535
+ url: ogImageUrl,
536
+ width: 1200,
537
+ height: 630,
538
+ alt: imageAlt
539
+ }
540
+ ]
541
+ },
542
+ twitter: {
543
+ ...metadata.twitter,
544
+ card: "summary_large_image",
545
+ images: [
546
+ ...existingTwitterImages,
547
+ {
548
+ url: ogImageUrl,
549
+ alt: imageAlt
550
+ }
551
+ ]
552
+ }
553
+ };
554
+ if (!finalMetadata.metadataBase && siteUrl) {
555
+ if (siteUrl.startsWith("http://") || siteUrl.startsWith("https://")) {
556
+ try {
557
+ finalMetadata.metadataBase = new URL(siteUrl);
558
+ } catch (e) {
559
+ }
560
+ }
561
+ }
562
+ return finalMetadata;
563
+ }
564
+ function createOgImageMetadataGenerator(options) {
565
+ return (metadata, ogImageParams) => {
566
+ return generateOgImageMetadata(metadata, ogImageParams, options);
567
+ };
568
+ }
569
+
570
+ // src/og-image/components/DefaultTemplate.tsx
571
+ function DefaultTemplate({
572
+ title,
573
+ description,
574
+ siteName,
575
+ logo,
576
+ // Visibility flags
577
+ showLogo = true,
578
+ showSiteName = true,
579
+ // Background customization
580
+ backgroundType = "gradient",
581
+ gradientStart = "#667eea",
582
+ gradientEnd = "#764ba2",
583
+ backgroundColor = "#ffffff",
584
+ // Typography - Title
585
+ titleSize,
586
+ titleWeight = 800,
587
+ titleColor = "white",
588
+ // Typography - Description
589
+ descriptionSize = 32,
590
+ descriptionColor = "rgba(255, 255, 255, 0.85)",
591
+ // Typography - Site Name
592
+ siteNameSize = 28,
593
+ siteNameColor = "rgba(255, 255, 255, 0.95)",
594
+ // Layout
595
+ padding = 80,
596
+ logoSize = 48,
597
+ // Dev mode
598
+ devMode = false
599
+ }) {
600
+ const calculatedTitleSize = titleSize || (title.length > 60 ? 56 : 72);
601
+ const backgroundStyle = backgroundType === "gradient" ? `linear-gradient(135deg, ${gradientStart} 0%, ${gradientEnd} 100%)` : backgroundColor;
602
+ const gridOverlay = devMode ? /* @__PURE__ */ React.createElement(
603
+ "div",
604
+ {
605
+ style: {
606
+ position: "absolute",
607
+ top: 0,
608
+ left: 0,
609
+ right: 0,
610
+ bottom: 0,
611
+ backgroundImage: `
612
+ linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px),
613
+ linear-gradient(90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px)
614
+ `,
615
+ backgroundSize: "20px 20px",
616
+ pointerEvents: "none",
617
+ zIndex: 10
618
+ }
619
+ }
620
+ ) : null;
621
+ return /* @__PURE__ */ React.createElement(
622
+ "div",
623
+ {
624
+ style: {
625
+ height: "100%",
626
+ width: "100%",
627
+ display: "flex",
628
+ flexDirection: "column",
629
+ alignItems: "flex-start",
630
+ justifyContent: "space-between",
631
+ background: backgroundStyle,
632
+ padding: `${padding}px`,
633
+ fontFamily: "system-ui, -apple-system, sans-serif",
634
+ position: "relative"
635
+ }
636
+ },
637
+ gridOverlay,
638
+ (showLogo && logo || showSiteName && siteName) && /* @__PURE__ */ React.createElement(
639
+ "div",
640
+ {
641
+ style: {
642
+ display: "flex",
643
+ alignItems: "center",
644
+ gap: "16px"
645
+ }
646
+ },
647
+ showLogo && logo && // eslint-disable-next-line @next/next/no-img-element
648
+ /* @__PURE__ */ React.createElement(
649
+ "img",
650
+ {
651
+ src: logo,
652
+ alt: "Logo",
653
+ width: logoSize,
654
+ height: logoSize,
655
+ style: {
656
+ borderRadius: "8px"
657
+ }
658
+ }
659
+ ),
660
+ showSiteName && siteName && /* @__PURE__ */ React.createElement(
661
+ "div",
662
+ {
663
+ style: {
664
+ fontSize: siteNameSize,
665
+ fontWeight: 600,
666
+ color: siteNameColor,
667
+ letterSpacing: "-0.02em"
668
+ }
669
+ },
670
+ siteName
671
+ )
672
+ ),
673
+ /* @__PURE__ */ React.createElement(
674
+ "div",
675
+ {
676
+ style: {
677
+ display: "flex",
678
+ flexDirection: "column",
679
+ gap: "24px",
680
+ flex: 1,
681
+ justifyContent: "center"
682
+ }
683
+ },
684
+ /* @__PURE__ */ React.createElement(
685
+ "div",
686
+ {
687
+ style: {
688
+ fontSize: calculatedTitleSize,
689
+ fontWeight: titleWeight,
690
+ color: titleColor,
691
+ lineHeight: 1.1,
692
+ letterSpacing: "-0.03em",
693
+ textShadow: backgroundType === "gradient" ? "0 2px 20px rgba(0, 0, 0, 0.2)" : "none",
694
+ maxWidth: "100%",
695
+ wordWrap: "break-word"
696
+ }
697
+ },
698
+ title
699
+ ),
700
+ description && /* @__PURE__ */ React.createElement(
701
+ "div",
702
+ {
703
+ style: {
704
+ fontSize: descriptionSize,
705
+ fontWeight: 400,
706
+ color: descriptionColor,
707
+ lineHeight: 1.5,
708
+ letterSpacing: "-0.01em",
709
+ maxWidth: "90%",
710
+ display: "-webkit-box",
711
+ WebkitLineClamp: 2,
712
+ WebkitBoxOrient: "vertical",
713
+ overflow: "hidden"
714
+ }
715
+ },
716
+ description
717
+ )
718
+ ),
719
+ /* @__PURE__ */ React.createElement(
720
+ "div",
721
+ {
722
+ style: {
723
+ display: "flex",
724
+ width: "100%",
725
+ height: "4px",
726
+ background: backgroundType === "gradient" ? `linear-gradient(90deg, ${gradientStart} 0%, ${gradientEnd} 100%)` : gradientStart,
727
+ borderRadius: "2px"
728
+ }
729
+ }
730
+ )
731
+ );
732
+ }
733
+ function LightTemplate({
734
+ title,
735
+ description,
736
+ siteName,
737
+ logo,
738
+ // Visibility flags
739
+ showLogo = true,
740
+ showSiteName = true,
741
+ // Background customization (defaults to light theme)
742
+ backgroundType = "solid",
743
+ gradientStart = "#667eea",
744
+ gradientEnd = "#764ba2",
745
+ backgroundColor = "#ffffff",
746
+ // Typography - Title
747
+ titleSize,
748
+ titleWeight = 800,
749
+ titleColor = "#111",
750
+ // Typography - Description
751
+ descriptionSize = 32,
752
+ descriptionColor = "#666",
753
+ // Typography - Site Name
754
+ siteNameSize = 28,
755
+ siteNameColor = "#111",
756
+ // Layout
757
+ padding = 80,
758
+ logoSize = 48,
759
+ // Dev mode
760
+ devMode = false
761
+ }) {
762
+ const calculatedTitleSize = titleSize || (title.length > 60 ? 56 : 72);
763
+ const backgroundStyle = backgroundType === "gradient" ? `linear-gradient(135deg, ${gradientStart} 0%, ${gradientEnd} 100%)` : backgroundColor;
764
+ const gridOverlay = devMode ? /* @__PURE__ */ React.createElement(
765
+ "div",
766
+ {
767
+ style: {
768
+ position: "absolute",
769
+ top: 0,
770
+ left: 0,
771
+ right: 0,
772
+ bottom: 0,
773
+ backgroundImage: `
774
+ linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px),
775
+ linear-gradient(90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px)
776
+ `,
777
+ backgroundSize: "20px 20px",
778
+ pointerEvents: "none",
779
+ zIndex: 10
780
+ }
781
+ }
782
+ ) : null;
783
+ return /* @__PURE__ */ React.createElement(
784
+ "div",
785
+ {
786
+ style: {
787
+ height: "100%",
788
+ width: "100%",
789
+ display: "flex",
790
+ flexDirection: "column",
791
+ alignItems: "flex-start",
792
+ justifyContent: "space-between",
793
+ background: backgroundStyle,
794
+ padding: `${padding}px`,
795
+ fontFamily: "system-ui, -apple-system, sans-serif",
796
+ position: "relative"
797
+ }
798
+ },
799
+ gridOverlay,
800
+ (showLogo && logo || showSiteName && siteName) && /* @__PURE__ */ React.createElement(
801
+ "div",
802
+ {
803
+ style: {
804
+ display: "flex",
805
+ alignItems: "center",
806
+ gap: "16px"
807
+ }
808
+ },
809
+ showLogo && logo && // eslint-disable-next-line @next/next/no-img-element
810
+ /* @__PURE__ */ React.createElement(
811
+ "img",
812
+ {
813
+ src: logo,
814
+ alt: "Logo",
815
+ width: logoSize,
816
+ height: logoSize,
817
+ style: {
818
+ borderRadius: "8px"
819
+ }
820
+ }
821
+ ),
822
+ showSiteName && siteName && /* @__PURE__ */ React.createElement(
823
+ "div",
824
+ {
825
+ style: {
826
+ fontSize: siteNameSize,
827
+ fontWeight: 600,
828
+ color: siteNameColor,
829
+ letterSpacing: "-0.02em"
830
+ }
831
+ },
832
+ siteName
833
+ )
834
+ ),
835
+ /* @__PURE__ */ React.createElement(
836
+ "div",
837
+ {
838
+ style: {
839
+ display: "flex",
840
+ flexDirection: "column",
841
+ gap: "24px",
842
+ flex: 1,
843
+ justifyContent: "center"
844
+ }
845
+ },
846
+ /* @__PURE__ */ React.createElement(
847
+ "div",
848
+ {
849
+ style: {
850
+ fontSize: calculatedTitleSize,
851
+ fontWeight: titleWeight,
852
+ color: titleColor,
853
+ lineHeight: 1.1,
854
+ letterSpacing: "-0.03em",
855
+ maxWidth: "100%",
856
+ wordWrap: "break-word"
857
+ }
858
+ },
859
+ title
860
+ ),
861
+ description && /* @__PURE__ */ React.createElement(
862
+ "div",
863
+ {
864
+ style: {
865
+ fontSize: descriptionSize,
866
+ fontWeight: 400,
867
+ color: descriptionColor,
868
+ lineHeight: 1.5,
869
+ letterSpacing: "-0.01em",
870
+ maxWidth: "90%"
871
+ }
872
+ },
873
+ description
874
+ )
875
+ ),
876
+ /* @__PURE__ */ React.createElement(
877
+ "div",
878
+ {
879
+ style: {
880
+ display: "flex",
881
+ width: "100%",
882
+ height: "4px",
883
+ background: backgroundType === "gradient" ? `linear-gradient(90deg, ${gradientStart} 0%, ${gradientEnd} 100%)` : gradientStart,
884
+ borderRadius: "2px"
885
+ }
886
+ }
887
+ )
888
+ );
889
+ }
890
+
891
+ // src/og-image/route.tsx
892
+ function createOgImageHandler(config) {
893
+ const {
894
+ template: Template = DefaultTemplate,
895
+ defaultProps = {},
896
+ fonts: fontConfig = [],
897
+ size = { width: 1200, height: 630 },
898
+ debug = false
899
+ } = config;
900
+ async function GET(req) {
901
+ let searchParams = new URLSearchParams();
902
+ if (req.nextUrl?.searchParams && req.nextUrl.searchParams.size > 0) {
903
+ searchParams = req.nextUrl.searchParams;
904
+ } else if (req.nextUrl?.search && req.nextUrl.search.length > 1) {
905
+ searchParams = new URLSearchParams(req.nextUrl.search);
906
+ } else {
907
+ try {
908
+ const url = new URL(req.url);
909
+ if (url.searchParams.size > 0) {
910
+ searchParams = url.searchParams;
911
+ }
912
+ } catch (error) {
913
+ }
914
+ if (searchParams.size === 0 && req.url) {
915
+ const queryIndex = req.url.indexOf("?");
916
+ if (queryIndex !== -1) {
917
+ const queryString = req.url.substring(queryIndex + 1);
918
+ searchParams = new URLSearchParams(queryString);
919
+ }
920
+ }
921
+ if (searchParams.size === 0) {
922
+ const customParams = req.headers.get("x-og-search-params");
923
+ if (customParams) {
924
+ searchParams = new URLSearchParams(customParams);
925
+ }
926
+ }
927
+ }
928
+ let title = defaultProps.title || "Untitled";
929
+ let subtitle = defaultProps.subtitle || "";
930
+ let description = defaultProps.description || subtitle;
931
+ const dataParam = searchParams.get("data");
932
+ let decodedParams = {};
933
+ if (dataParam) {
934
+ try {
935
+ const paramsObj = { data: dataParam };
936
+ for (const [key, value] of searchParams.entries()) {
937
+ if (key !== "data") {
938
+ paramsObj[key] = value;
939
+ }
940
+ }
941
+ decodedParams = parseOgImageData(paramsObj);
942
+ if (decodedParams.title && typeof decodedParams.title === "string" && decodedParams.title.trim() !== "") {
943
+ title = decodedParams.title.trim();
944
+ }
945
+ if (decodedParams.subtitle && typeof decodedParams.subtitle === "string" && decodedParams.subtitle.trim() !== "") {
946
+ subtitle = decodedParams.subtitle.trim();
947
+ }
948
+ if (decodedParams.description && typeof decodedParams.description === "string" && decodedParams.description.trim() !== "") {
949
+ description = decodedParams.description.trim();
950
+ }
951
+ } catch (error) {
952
+ }
953
+ }
954
+ if (!title || title === "Untitled") {
955
+ const titleParam = searchParams.get("title");
956
+ if (titleParam) {
957
+ title = titleParam;
958
+ }
959
+ }
960
+ if (!subtitle) {
961
+ const subtitleParam = searchParams.get("subtitle");
962
+ if (subtitleParam) {
963
+ subtitle = subtitleParam;
964
+ }
965
+ }
966
+ if (!description || description === subtitle) {
967
+ const descParam = searchParams.get("description");
968
+ if (descParam) {
969
+ description = descParam;
970
+ }
971
+ }
972
+ let fonts = [];
973
+ if (fontConfig.length > 0) {
974
+ fonts = await loadGoogleFonts(fontConfig);
975
+ }
976
+ const parseValue = (value, type = "string") => {
977
+ if (value === void 0 || value === null || value === "") {
978
+ return void 0;
979
+ }
980
+ if (type === "number") {
981
+ const num = Number(value);
982
+ return isNaN(num) ? void 0 : num;
983
+ }
984
+ if (type === "boolean") {
985
+ if (typeof value === "boolean") return value;
986
+ if (typeof value === "string") {
987
+ return value.toLowerCase() === "true" || value === "1";
988
+ }
989
+ return Boolean(value);
990
+ }
991
+ return String(value);
992
+ };
993
+ const templateProps = {
994
+ ...defaultProps,
995
+ // Content
996
+ title,
997
+ subtitle,
998
+ description,
999
+ // Override with decoded params if present
1000
+ siteName: decodedParams.siteName || defaultProps.siteName,
1001
+ logo: decodedParams.logo || defaultProps.logo,
1002
+ // Background
1003
+ backgroundType: decodedParams.backgroundType || defaultProps.backgroundType,
1004
+ gradientStart: decodedParams.gradientStart || defaultProps.gradientStart,
1005
+ gradientEnd: decodedParams.gradientEnd || defaultProps.gradientEnd,
1006
+ backgroundColor: decodedParams.backgroundColor || defaultProps.backgroundColor,
1007
+ // Typography - Title
1008
+ titleSize: parseValue(decodedParams.titleSize, "number") ?? defaultProps.titleSize,
1009
+ titleWeight: parseValue(decodedParams.titleWeight, "number") ?? defaultProps.titleWeight,
1010
+ titleColor: decodedParams.titleColor || defaultProps.titleColor,
1011
+ // Typography - Description
1012
+ descriptionSize: parseValue(decodedParams.descriptionSize, "number") ?? defaultProps.descriptionSize,
1013
+ descriptionColor: decodedParams.descriptionColor || defaultProps.descriptionColor,
1014
+ // Typography - Site Name
1015
+ siteNameSize: parseValue(decodedParams.siteNameSize, "number") ?? defaultProps.siteNameSize,
1016
+ siteNameColor: decodedParams.siteNameColor || defaultProps.siteNameColor,
1017
+ // Layout
1018
+ padding: parseValue(decodedParams.padding, "number") ?? defaultProps.padding,
1019
+ logoSize: parseValue(decodedParams.logoSize, "number") ?? defaultProps.logoSize,
1020
+ // Visibility flags
1021
+ showLogo: parseValue(decodedParams.showLogo, "boolean") ?? defaultProps.showLogo,
1022
+ showSiteName: parseValue(decodedParams.showSiteName, "boolean") ?? defaultProps.showSiteName
1023
+ };
1024
+ return new ImageResponse(
1025
+ /* @__PURE__ */ React.createElement(Template, { ...templateProps }),
1026
+ {
1027
+ width: size.width,
1028
+ height: size.height,
1029
+ fonts,
1030
+ debug: debug || process.env.NODE_ENV === "development"
1031
+ }
1032
+ );
1033
+ }
1034
+ return {
1035
+ GET,
1036
+ runtime: "edge"
1037
+ };
1038
+ }
1039
+ function createOgImageDynamicRoute(config) {
1040
+ const handler = createOgImageHandler(config);
1041
+ const isStaticBuild2 = typeof process !== "undefined" && process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
1042
+ async function GET(request, context) {
1043
+ if (isStaticBuild2) {
1044
+ return new Response("OG Image generation is not available in static export mode", {
1045
+ status: 404,
1046
+ headers: { "Content-Type": "text/plain" }
1047
+ });
1048
+ }
1049
+ const params = await context.params;
1050
+ const dataParam = params.data;
1051
+ const url = new URL(request.url);
1052
+ url.searchParams.set("data", dataParam);
1053
+ const modifiedRequest = new NextRequest(url.toString(), {
1054
+ method: request.method,
1055
+ headers: request.headers
1056
+ });
1057
+ return handler.GET(modifiedRequest);
1058
+ }
1059
+ async function generateStaticParams() {
1060
+ return [];
1061
+ }
1062
+ return {
1063
+ GET,
1064
+ generateStaticParams
1065
+ };
1066
+ }
1067
+
1068
+ // src/contact/submit.ts
1069
+ import { API, MemoryStorageAdapter, Fetchers } from "@djangocfg/api/server";
1070
+ async function submitContactForm({
1071
+ data,
1072
+ apiUrl,
1073
+ siteUrl
1074
+ }) {
1075
+ if (!data.name || !data.email || !data.message) {
1076
+ throw new Error("Missing required fields: name, email, message");
1077
+ }
1078
+ if (!apiUrl) {
1079
+ throw new Error("API URL is required");
1080
+ }
1081
+ const serverApi = new API(apiUrl, {
1082
+ storage: new MemoryStorageAdapter()
1083
+ });
1084
+ const submissionData = {
1085
+ ...data,
1086
+ site_url: data.site_url || siteUrl
1087
+ };
1088
+ try {
1089
+ const result = await Fetchers.createLeadsSubmitCreate(submissionData, serverApi);
1090
+ return {
1091
+ success: result.success ?? true,
1092
+ message: result.message || "Contact form submitted successfully",
1093
+ lead_id: result.lead_id
1094
+ };
1095
+ } catch (error) {
1096
+ if (error instanceof Error) {
1097
+ throw new Error(`Failed to submit contact form: ${error.message}`);
1098
+ }
1099
+ throw new Error("An unexpected error occurred while submitting the contact form");
1100
+ }
1101
+ }
1102
+
1103
+ // src/contact/route.ts
1104
+ import { NextResponse as NextResponse3 } from "next/server";
1105
+ function createContactRoute(options) {
1106
+ return async function POST2(request) {
1107
+ try {
1108
+ const body = await request.json();
1109
+ const apiUrl = body._apiUrl && body._apiUrl !== "" ? body._apiUrl : options?.apiUrl || process.env.NEXT_PUBLIC_API_URL || "";
1110
+ if (!apiUrl) {
1111
+ return NextResponse3.json(
1112
+ {
1113
+ success: false,
1114
+ message: "API URL not configured. Set NEXT_PUBLIC_API_URL, provide apiUrl option, or pass _apiUrl in request body."
1115
+ },
1116
+ { status: 500 }
1117
+ );
1118
+ }
1119
+ const { _apiUrl, ...submissionData } = body;
1120
+ const response = await submitContactForm({
1121
+ data: submissionData,
1122
+ apiUrl,
1123
+ siteUrl: request.headers.get("origin") || void 0
1124
+ });
1125
+ return NextResponse3.json(response);
1126
+ } catch (error) {
1127
+ console.error("Contact form submission error:", error);
1128
+ if (error instanceof Error && error.message.includes("Missing required fields")) {
1129
+ return NextResponse3.json(
1130
+ {
1131
+ success: false,
1132
+ message: error.message
1133
+ },
1134
+ { status: 400 }
1135
+ );
1136
+ }
1137
+ if (error instanceof Error) {
1138
+ return NextResponse3.json(
1139
+ {
1140
+ success: false,
1141
+ message: error.message || "Failed to submit contact form"
1142
+ },
1143
+ { status: 500 }
1144
+ );
1145
+ }
1146
+ return NextResponse3.json(
1147
+ {
1148
+ success: false,
1149
+ message: "An unexpected error occurred"
1150
+ },
1151
+ { status: 500 }
1152
+ );
1153
+ }
1154
+ };
1155
+ }
1156
+ async function POST(request) {
1157
+ const handler = createContactRoute();
1158
+ return handler(request);
1159
+ }
1160
+
1161
+ // src/navigation/utils.ts
1162
+ function defineRoute(path, metadata) {
1163
+ return {
1164
+ path,
1165
+ metadata
1166
+ };
1167
+ }
1168
+ function getUnauthenticatedRedirect(path, authPath = "/auth") {
1169
+ if (path.startsWith("/private") || path.startsWith("/admin")) {
1170
+ return authPath;
1171
+ }
1172
+ return null;
1173
+ }
1174
+ function redirectToAuth(authPath = "/auth") {
1175
+ return authPath;
1176
+ }
1177
+ function findRoute(routes, path) {
1178
+ return routes.find((r) => r.path === path);
1179
+ }
1180
+ function findRouteByPattern(routes, path) {
1181
+ const exact = findRoute(routes, path);
1182
+ if (exact) return exact;
1183
+ const segments = path.split("/").filter(Boolean);
1184
+ for (let i = segments.length; i > 0; i--) {
1185
+ const parentPath = "/" + segments.slice(0, i).join("/");
1186
+ const parent = findRoute(routes, parentPath);
1187
+ if (parent) return parent;
1188
+ }
1189
+ return void 0;
1190
+ }
1191
+ function getPageTitle(routes, path, fallback = "Dashboard") {
1192
+ const route = findRouteByPattern(routes, path);
1193
+ return route?.metadata.label || fallback;
1194
+ }
1195
+ function isActive(current, target, allRoutes) {
1196
+ const matches = current === target || target !== "/" && current.startsWith(target + "/");
1197
+ if (matches && allRoutes) {
1198
+ return !allRoutes.some(
1199
+ (otherRoute) => otherRoute.path !== target && otherRoute.path.startsWith(target + "/") && (current === otherRoute.path || current.startsWith(otherRoute.path + "/"))
1200
+ );
1201
+ }
1202
+ return matches;
1203
+ }
1204
+ function routesToMenuItems(routes, groupName) {
1205
+ return routes.filter(
1206
+ (r) => r.metadata.group === groupName && r.metadata.icon && (r.metadata.show === void 0 || r.metadata.show === true)
1207
+ ).sort((a, b) => (a.metadata.order || 0) - (b.metadata.order || 0)).map((r) => ({
1208
+ path: r.path,
1209
+ label: r.metadata.label,
1210
+ icon: r.metadata.icon
1211
+ }));
1212
+ }
1213
+
1214
+ // src/config/constants.ts
1215
+ var PACKAGE_NAME = "@djangocfg/nextjs";
1216
+ var VERSION_CACHE_TTL_MS = 60 * 60 * 1e3;
1217
+ var DJANGO_CFG_BANNER = `
1218
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557
1219
+ \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
1220
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2557
1221
+ \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551
1222
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
1223
+ \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
1224
+ `;
1225
+ var DJANGOCFG_PACKAGES = [
1226
+ "@djangocfg/ui-core",
1227
+ "@djangocfg/ui-nextjs",
1228
+ "@djangocfg/layouts",
1229
+ "@djangocfg/nextjs",
1230
+ "@djangocfg/api",
1231
+ "@djangocfg/centrifugo",
1232
+ "@djangocfg/eslint-config",
1233
+ "@djangocfg/typescript-config"
1234
+ ];
1235
+ var DEFAULT_TRANSPILE_PACKAGES = [
1236
+ "@djangocfg/ui-core",
1237
+ "@djangocfg/ui-nextjs",
1238
+ "@djangocfg/layouts",
1239
+ "@djangocfg/nextjs",
1240
+ "@djangocfg/api",
1241
+ "@djangocfg/centrifugo"
1242
+ ];
1243
+ var DEFAULT_OPTIMIZE_PACKAGES = [
1244
+ "@djangocfg/ui-core",
1245
+ "@djangocfg/ui-nextjs",
1246
+ "@djangocfg/layouts",
1247
+ "lucide-react",
1248
+ "recharts"
1249
+ ];
1250
+
1251
+ // src/config/utils/deepMerge.ts
1252
+ function deepMerge(target, source) {
1253
+ const output = { ...target };
1254
+ for (const key in source) {
1255
+ if (source[key] === void 0) continue;
1256
+ if (Array.isArray(source[key])) {
1257
+ output[key] = source[key];
1258
+ } else if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
1259
+ const targetValue = output[key];
1260
+ if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
1261
+ output[key] = deepMerge(targetValue, source[key]);
1262
+ } else {
1263
+ output[key] = source[key];
1264
+ }
1265
+ } else {
1266
+ output[key] = source[key];
1267
+ }
1268
+ }
1269
+ return output;
1270
+ }
1271
+
1272
+ // src/config/utils/env.ts
1273
+ var isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
1274
+ var isDev = process.env.NODE_ENV === "development";
1275
+ var isProduction = process.env.NODE_ENV === "production";
1276
+ var isCI = process.env.CI === "true";
1277
+ function getBasePath(isDefaultCfgAdmin) {
1278
+ if (!isStaticBuild) return "";
1279
+ return isDefaultCfgAdmin ? "/cfg/admin" : "/cfg/nextjs-admin";
1280
+ }
1281
+ function getApiUrl() {
1282
+ return isStaticBuild ? "" : process.env.NEXT_PUBLIC_API_URL || "";
1283
+ }
1284
+ function getSiteUrl2() {
1285
+ return isStaticBuild ? "" : process.env.NEXT_PUBLIC_SITE_URL || "";
1286
+ }
1287
+
1288
+ // src/config/plugins/devStartup.ts
1289
+ import chalk4 from "chalk";
1290
+
1291
+ // src/ai/constants.ts
1292
+ var MCP_BASE_URL = "https://mcp.djangocfg.com";
1293
+ var MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
1294
+ var MCP_API_URL = `${MCP_BASE_URL}/api/search`;
1295
+ var API_SEARCH_ENDPOINT = "/api/search";
1296
+ var API_INFO_ENDPOINT = "/api/info";
1297
+ var DEFAULT_TIMEOUT = 1e4;
1298
+ var AI_DOCS_HINT = `\u{1F916} AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search "query"`;
1299
+ var AI_HINT = `
1300
+ DjangoCFG Documentation is available via MCP server.
1301
+
1302
+ To get help with DjangoCFG configuration:
1303
+ 1. Use the MCP server: ${MCP_SERVER_URL}
1304
+ 2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5
1305
+
1306
+ Example queries:
1307
+ - "How to configure PostgreSQL database?"
1308
+ - "What is DatabaseConfig?"
1309
+ - "How to setup Redis cache?"
1310
+ - "Email configuration with SMTP"
1311
+ `;
1312
+
1313
+ // src/config/utils/version.ts
1314
+ import chalk from "chalk";
1315
+ import semver from "semver";
1316
+ import consola from "consola";
1317
+ import Conf from "conf";
1318
+ var versionCache = new Conf({
1319
+ projectName: "djangocfg-nextjs",
1320
+ projectVersion: "1.0.0"
1321
+ });
1322
+ function getCurrentVersion() {
1323
+ try {
1324
+ const packageJson = require_package();
1325
+ return packageJson.version || null;
1326
+ } catch {
1327
+ return null;
1328
+ }
1329
+ }
1330
+ async function fetchLatestVersion() {
1331
+ const lastCheck = versionCache.get("lastCheck") || 0;
1332
+ const cachedVersion = versionCache.get("latestVersion");
1333
+ if (cachedVersion && Date.now() - lastCheck < VERSION_CACHE_TTL_MS) {
1334
+ return cachedVersion;
1335
+ }
1336
+ try {
1337
+ const https = await import("https");
1338
+ return new Promise((resolve) => {
1339
+ const req = https.get(
1340
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
1341
+ { timeout: 5e3 },
1342
+ (res) => {
1343
+ let data = "";
1344
+ res.on("data", (chunk) => {
1345
+ data += chunk;
1346
+ });
1347
+ res.on("end", () => {
1348
+ try {
1349
+ const json = JSON.parse(data);
1350
+ const version = json.version || null;
1351
+ if (version) {
1352
+ versionCache.set("latestVersion", version);
1353
+ versionCache.set("lastCheck", Date.now());
1354
+ }
1355
+ resolve(version);
1356
+ } catch {
1357
+ resolve(cachedVersion || null);
1358
+ }
1359
+ });
1360
+ }
1361
+ );
1362
+ req.on("error", () => resolve(cachedVersion || null));
1363
+ req.on("timeout", () => {
1364
+ req.destroy();
1365
+ resolve(cachedVersion || null);
1366
+ });
1367
+ });
1368
+ } catch {
1369
+ return cachedVersion || null;
1370
+ }
1371
+ }
1372
+ async function checkForUpdate() {
1373
+ const currentVersion = getCurrentVersion();
1374
+ if (!currentVersion) {
1375
+ return { hasUpdate: false, currentVersion: null, latestVersion: null };
1376
+ }
1377
+ const latestVersion = await fetchLatestVersion();
1378
+ const hasUpdate = !!(latestVersion && semver.gt(latestVersion, currentVersion));
1379
+ return { hasUpdate, currentVersion, latestVersion };
1380
+ }
1381
+ function getUpdateCommand() {
1382
+ return `pnpm add ${DJANGOCFG_PACKAGES.map((p) => `${p}@latest`).join(" ")}`;
1383
+ }
1384
+ async function printVersionInfo() {
1385
+ const { hasUpdate, currentVersion, latestVersion } = await checkForUpdate();
1386
+ if (!currentVersion) return;
1387
+ consola.box(`\u{1F4E6} @djangocfg/nextjs v${currentVersion}`);
1388
+ if (hasUpdate && latestVersion) {
1389
+ consola.warn(`Update Available! ${chalk.red(currentVersion)} \u2192 ${chalk.green(latestVersion)}`);
1390
+ consola.info(`Run: ${chalk.cyan(getUpdateCommand())}`);
1391
+ console.log("");
1392
+ }
1393
+ }
1394
+
1395
+ // src/config/packages/installer.ts
1396
+ import { execSync, spawn } from "child_process";
1397
+ import { createInterface } from "readline";
1398
+ import chalk2 from "chalk";
1399
+ import consola2 from "consola";
1400
+ import Conf2 from "conf";
1401
+
1402
+ // src/config/packages/checker.ts
1403
+ import { createRequire } from "module";
1404
+ import { join } from "path";
1405
+
1406
+ // src/config/packages/definitions.ts
1407
+ var OPTIONAL_PACKAGES = [
1408
+ {
1409
+ name: "compression-webpack-plugin",
1410
+ description: "Gzip and Brotli compression for static builds",
1411
+ condition: "static-build",
1412
+ devDependency: true
1413
+ },
1414
+ {
1415
+ name: "@next/bundle-analyzer",
1416
+ description: "Bundle analyzer for analyzing build output",
1417
+ condition: "dev",
1418
+ devDependency: true,
1419
+ featureFlag: "ANALYZE"
1420
+ }
1421
+ ];
1422
+ var PEER_DEPENDENCIES = [
1423
+ "next",
1424
+ "react",
1425
+ "react-dom"
1426
+ ];
1427
+ function getPackagesForContext(options) {
1428
+ return OPTIONAL_PACKAGES.filter((pkg) => {
1429
+ switch (pkg.condition) {
1430
+ case "static-build":
1431
+ return options.isStaticBuild;
1432
+ case "dev":
1433
+ return options.isDev;
1434
+ case "always":
1435
+ return true;
1436
+ default:
1437
+ return false;
1438
+ }
1439
+ });
1440
+ }
1441
+
1442
+ // src/config/packages/checker.ts
1443
+ function isPackageInstalled(packageName) {
1444
+ try {
1445
+ const consumerRequire = createRequire(join(process.cwd(), "package.json"));
1446
+ consumerRequire.resolve(packageName);
1447
+ return true;
1448
+ } catch {
1449
+ try {
1450
+ __require.resolve(packageName);
1451
+ return true;
1452
+ } catch {
1453
+ return false;
1454
+ }
1455
+ }
1456
+ }
1457
+ function getMissingPackages() {
1458
+ const neededPackages = getPackagesForContext({ isStaticBuild, isDev });
1459
+ const missing = [];
1460
+ for (const pkg of neededPackages) {
1461
+ if (!isPackageInstalled(pkg.name)) {
1462
+ missing.push({
1463
+ ...pkg,
1464
+ reason: getReasonText(pkg)
1465
+ });
1466
+ }
1467
+ }
1468
+ return missing;
1469
+ }
1470
+ function checkPackages(packageNames) {
1471
+ const missing = [];
1472
+ for (const name of packageNames) {
1473
+ if (!isPackageInstalled(name)) {
1474
+ const definition = OPTIONAL_PACKAGES.find((p) => p.name === name);
1475
+ missing.push({
1476
+ name,
1477
+ description: definition?.description || "Optional package",
1478
+ condition: definition?.condition || "always",
1479
+ devDependency: definition?.devDependency ?? true,
1480
+ reason: definition ? getReasonText(definition) : "Requested by configuration"
1481
+ });
1482
+ }
1483
+ }
1484
+ return missing;
1485
+ }
1486
+ function getReasonText(pkg) {
1487
+ switch (pkg.condition) {
1488
+ case "static-build":
1489
+ return "Required for static build (NEXT_PUBLIC_STATIC_BUILD=true)";
1490
+ case "dev":
1491
+ return "Required for development mode";
1492
+ case "always":
1493
+ return "Required for all builds";
1494
+ default:
1495
+ return "Optional feature";
1496
+ }
1497
+ }
1498
+
1499
+ // src/config/packages/installer.ts
1500
+ var installerCache = new Conf2({
1501
+ projectName: "djangocfg-nextjs-installer",
1502
+ projectVersion: "1.0.0"
1503
+ });
1504
+ var PROMPT_COOLDOWN_MS = 60 * 60 * 1e3;
1505
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1506
+ function detectPackageManager() {
1507
+ try {
1508
+ const fs = __require("fs");
1509
+ const path = __require("path");
1510
+ const cwd = process.cwd();
1511
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1512
+ if (fs.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
1513
+ if (fs.existsSync(path.join(cwd, "package-lock.json"))) return "npm";
1514
+ try {
1515
+ execSync("pnpm --version", { stdio: "ignore" });
1516
+ return "pnpm";
1517
+ } catch {
1518
+ try {
1519
+ execSync("yarn --version", { stdio: "ignore" });
1520
+ return "yarn";
1521
+ } catch {
1522
+ return "npm";
1523
+ }
1524
+ }
1525
+ } catch {
1526
+ return "npm";
1527
+ }
1528
+ }
1529
+ function buildSingleInstallCommand(packageName, isDev2, pm) {
1530
+ const devFlag = isDev2 ? "-D " : "";
1531
+ switch (pm) {
1532
+ case "pnpm":
1533
+ return `pnpm add ${devFlag}${packageName}`;
1534
+ case "yarn":
1535
+ return `yarn add ${devFlag}${packageName}`;
1536
+ case "npm":
1537
+ return `npm install ${devFlag}${packageName}`;
1538
+ }
1539
+ }
1540
+ function buildInstallCommand(packages, pm) {
1541
+ const devPackages = packages.filter((p) => p.devDependency).map((p) => p.name);
1542
+ const prodPackages = packages.filter((p) => !p.devDependency).map((p) => p.name);
1543
+ const commands = [];
1544
+ if (devPackages.length > 0) {
1545
+ switch (pm) {
1546
+ case "pnpm":
1547
+ commands.push(`pnpm add -D ${devPackages.join(" ")}`);
1548
+ break;
1549
+ case "yarn":
1550
+ commands.push(`yarn add -D ${devPackages.join(" ")}`);
1551
+ break;
1552
+ case "npm":
1553
+ commands.push(`npm install -D ${devPackages.join(" ")}`);
1554
+ break;
1555
+ }
1556
+ }
1557
+ if (prodPackages.length > 0) {
1558
+ switch (pm) {
1559
+ case "pnpm":
1560
+ commands.push(`pnpm add ${prodPackages.join(" ")}`);
1561
+ break;
1562
+ case "yarn":
1563
+ commands.push(`yarn add ${prodPackages.join(" ")}`);
1564
+ break;
1565
+ case "npm":
1566
+ commands.push(`npm install ${prodPackages.join(" ")}`);
1567
+ break;
1568
+ }
1569
+ }
1570
+ return commands.join(" && ");
1571
+ }
1572
+ async function askConfirmation(question) {
1573
+ if (isCI || !process.stdin.isTTY) {
1574
+ return false;
1575
+ }
1576
+ return new Promise((resolve) => {
1577
+ const rl = createInterface({
1578
+ input: process.stdin,
1579
+ output: process.stdout
1580
+ });
1581
+ rl.question(question, (answer) => {
1582
+ rl.close();
1583
+ const normalized = answer.toLowerCase().trim();
1584
+ resolve(normalized === "" || normalized === "y" || normalized === "yes");
1585
+ });
1586
+ });
1587
+ }
1588
+ function createSpinner(text) {
1589
+ let frameIndex = 0;
1590
+ let interval = null;
1591
+ let currentText = text;
1592
+ const render = () => {
1593
+ const frame = SPINNER_FRAMES[frameIndex];
1594
+ process.stdout.write(`\r${chalk2.cyan(frame)} ${currentText}`);
1595
+ frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
1596
+ };
1597
+ return {
1598
+ start() {
1599
+ if (process.stdout.isTTY) {
1600
+ interval = setInterval(render, 80);
1601
+ render();
1602
+ } else {
1603
+ console.log(` ${currentText}`);
1604
+ }
1605
+ return this;
1606
+ },
1607
+ text(newText) {
1608
+ currentText = newText;
1609
+ if (!process.stdout.isTTY) {
1610
+ console.log(` ${newText}`);
1611
+ }
1612
+ return this;
1613
+ },
1614
+ succeed(text2) {
1615
+ if (interval) clearInterval(interval);
1616
+ if (process.stdout.isTTY) {
1617
+ process.stdout.write(`\r${chalk2.green("\u2713")} ${text2 || currentText}
1618
+ `);
1619
+ } else {
1620
+ console.log(` ${chalk2.green("\u2713")} ${text2 || currentText}`);
1621
+ }
1622
+ return this;
1623
+ },
1624
+ fail(text2) {
1625
+ if (interval) clearInterval(interval);
1626
+ if (process.stdout.isTTY) {
1627
+ process.stdout.write(`\r${chalk2.red("\u2717")} ${text2 || currentText}
1628
+ `);
1629
+ } else {
1630
+ console.log(` ${chalk2.red("\u2717")} ${text2 || currentText}`);
1631
+ }
1632
+ return this;
1633
+ },
1634
+ stop() {
1635
+ if (interval) clearInterval(interval);
1636
+ if (process.stdout.isTTY) {
1637
+ process.stdout.write("\r\x1B[K");
1638
+ }
1639
+ return this;
1640
+ }
1641
+ };
1642
+ }
1643
+ async function installSinglePackage(pkg, pm, index, total) {
1644
+ const command = buildSingleInstallCommand(pkg.name, pkg.devDependency, pm);
1645
+ const progress = `[${index + 1}/${total}]`;
1646
+ const spinner = createSpinner(`${chalk2.dim(progress)} Installing ${chalk2.cyan(pkg.name)}...`);
1647
+ spinner.start();
1648
+ return new Promise((resolve) => {
1649
+ const [cmd, ...args] = command.split(" ");
1650
+ const proc = spawn(cmd, args, {
1651
+ shell: true,
1652
+ cwd: process.cwd(),
1653
+ stdio: ["ignore", "pipe", "pipe"]
1654
+ });
1655
+ let stderr = "";
1656
+ proc.stderr?.on("data", (data) => {
1657
+ stderr += data.toString();
1658
+ });
1659
+ proc.on("close", (code) => {
1660
+ if (code === 0) {
1661
+ spinner.succeed(`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.green("installed")}`);
1662
+ resolve(true);
1663
+ } else {
1664
+ spinner.fail(`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.red("failed")}`);
1665
+ if (stderr) {
1666
+ console.log(chalk2.dim(` ${stderr.split("\n")[0]}`));
1667
+ }
1668
+ resolve(false);
1669
+ }
1670
+ });
1671
+ proc.on("error", () => {
1672
+ spinner.fail(`${chalk2.dim(progress)} ${chalk2.cyan(pkg.name)} ${chalk2.red("failed")}`);
1673
+ resolve(false);
1674
+ });
1675
+ });
1676
+ }
1677
+ async function installPackagesWithProgress(packages) {
1678
+ if (packages.length === 0) return true;
1679
+ const pm = detectPackageManager();
1680
+ const total = packages.length;
1681
+ console.log("");
1682
+ console.log(chalk2.bold(` Installing ${total} package${total > 1 ? "s" : ""}...`));
1683
+ console.log("");
1684
+ let successCount = 0;
1685
+ let failedPackages = [];
1686
+ for (let i = 0; i < packages.length; i++) {
1687
+ const success = await installSinglePackage(packages[i], pm, i, total);
1688
+ if (success) {
1689
+ successCount++;
1690
+ } else {
1691
+ failedPackages.push(packages[i].name);
1692
+ }
1693
+ }
1694
+ console.log("");
1695
+ if (failedPackages.length === 0) {
1696
+ consola2.success(`All ${total} packages installed successfully!`);
1697
+ return true;
1698
+ } else if (successCount > 0) {
1699
+ consola2.warn(`${successCount}/${total} packages installed. Failed: ${failedPackages.join(", ")}`);
1700
+ return false;
1701
+ } else {
1702
+ consola2.error(`Failed to install packages: ${failedPackages.join(", ")}`);
1703
+ return false;
1704
+ }
1705
+ }
1706
+ async function installPackages(packages) {
1707
+ if (packages.length > 1 && process.stdout.isTTY) {
1708
+ return installPackagesWithProgress(packages);
1709
+ }
1710
+ if (packages.length === 0) return true;
1711
+ const pm = detectPackageManager();
1712
+ const command = buildInstallCommand(packages, pm);
1713
+ consola2.info(`Installing: ${chalk2.cyan(packages.map((p) => p.name).join(", "))}`);
1714
+ const spinner = createSpinner("Installing packages...");
1715
+ spinner.start();
1716
+ return new Promise((resolve) => {
1717
+ const proc = spawn(command, {
1718
+ shell: true,
1719
+ cwd: process.cwd(),
1720
+ stdio: ["ignore", "pipe", "pipe"]
1721
+ });
1722
+ proc.on("close", (code) => {
1723
+ if (code === 0) {
1724
+ spinner.succeed("Packages installed successfully!");
1725
+ resolve(true);
1726
+ } else {
1727
+ spinner.fail("Failed to install packages");
1728
+ resolve(false);
1729
+ }
1730
+ });
1731
+ proc.on("error", () => {
1732
+ spinner.fail("Installation failed");
1733
+ resolve(false);
1734
+ });
1735
+ });
1736
+ }
1737
+ async function checkAndInstallPackages(options = {}) {
1738
+ const missing = getMissingPackages();
1739
+ const skipList = options.skipPackages || installerCache.get("skipPackages") || [];
1740
+ const toInstall = missing.filter((p) => !skipList.includes(p.name));
1741
+ if (toInstall.length === 0) {
1742
+ return true;
1743
+ }
1744
+ const lastPrompt = installerCache.get("lastPrompt") || 0;
1745
+ if (!options.force && Date.now() - lastPrompt < PROMPT_COOLDOWN_MS) {
1746
+ printMissingPackagesInfo(toInstall);
1747
+ return false;
1748
+ }
1749
+ if (options.autoInstall || installerCache.get("autoInstall")) {
1750
+ return installPackages(toInstall);
1751
+ }
1752
+ console.log("");
1753
+ consola2.box("\u{1F4E6} Missing Optional Packages");
1754
+ console.log("");
1755
+ for (const pkg of toInstall) {
1756
+ console.log(` ${chalk2.yellow("\u2022")} ${chalk2.bold(pkg.name)}`);
1757
+ console.log(` ${chalk2.dim(pkg.description)}`);
1758
+ console.log(` ${chalk2.dim(pkg.reason)}`);
1759
+ console.log("");
1760
+ }
1761
+ const pm = detectPackageManager();
1762
+ const command = buildInstallCommand(toInstall, pm);
1763
+ console.log(` ${chalk2.cyan("Command:")} ${command}`);
1764
+ console.log("");
1765
+ installerCache.set("lastPrompt", Date.now());
1766
+ const shouldInstall = await askConfirmation(
1767
+ `${chalk2.green("?")} Install these packages now? ${chalk2.dim("[Y/n]")} `
1768
+ );
1769
+ if (shouldInstall) {
1770
+ const success = await installPackages(toInstall);
1771
+ if (success) {
1772
+ const enableAuto = await askConfirmation(
1773
+ `${chalk2.green("?")} Enable auto-install for future? ${chalk2.dim("[y/N]")} `
1774
+ );
1775
+ if (enableAuto) {
1776
+ installerCache.set("autoInstall", true);
1777
+ consola2.info("Auto-install enabled. Run with --no-auto-install to disable.");
1778
+ }
1779
+ }
1780
+ return success;
1781
+ }
1782
+ const skipPermanently = await askConfirmation(
1783
+ `${chalk2.green("?")} Skip these packages in future prompts? ${chalk2.dim("[y/N]")} `
1784
+ );
1785
+ if (skipPermanently) {
1786
+ const currentSkip = installerCache.get("skipPackages") || [];
1787
+ installerCache.set("skipPackages", [...currentSkip, ...toInstall.map((p) => p.name)]);
1788
+ consola2.info("Packages added to skip list.");
1789
+ }
1790
+ return false;
1791
+ }
1792
+ function printMissingPackagesInfo(packages) {
1793
+ if (packages.length === 0) return;
1794
+ const pm = detectPackageManager();
1795
+ const command = buildInstallCommand(packages, pm);
1796
+ consola2.warn(`Missing optional packages: ${packages.map((p) => p.name).join(", ")}`);
1797
+ consola2.info(`Install with: ${chalk2.cyan(command)}`);
1798
+ }
1799
+ function resetInstallerPreferences() {
1800
+ installerCache.clear();
1801
+ consola2.success("Installer preferences reset");
1802
+ }
1803
+
1804
+ // src/config/packages/updater.ts
1805
+ import { spawn as spawn2 } from "child_process";
1806
+ import { createInterface as createInterface2 } from "readline";
1807
+ import { createRequire as createRequire2 } from "module";
1808
+ import { join as join2 } from "path";
1809
+ import chalk3 from "chalk";
1810
+ import consola3 from "consola";
1811
+ import Conf3 from "conf";
1812
+ import semver2 from "semver";
1813
+ var updaterCache = new Conf3({
1814
+ projectName: "djangocfg-nextjs-updater",
1815
+ projectVersion: "1.0.0"
1816
+ });
1817
+ var UPDATE_CHECK_COOLDOWN_MS = 60 * 60 * 1e3;
1818
+ var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1819
+ function isWorkspacePackage(packageName) {
1820
+ try {
1821
+ const fs = __require("fs");
1822
+ const pkgJsonPath = join2(process.cwd(), "package.json");
1823
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
1824
+ const deps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
1825
+ const version = deps[packageName];
1826
+ return version?.startsWith("workspace:") || false;
1827
+ } catch {
1828
+ return false;
1829
+ }
1830
+ }
1831
+ function getInstalledVersion(packageName) {
1832
+ const fs = __require("fs");
1833
+ const cwd = process.cwd();
1834
+ try {
1835
+ const directPath = join2(cwd, "node_modules", packageName, "package.json");
1836
+ if (fs.existsSync(directPath)) {
1837
+ const pkg = JSON.parse(fs.readFileSync(directPath, "utf-8"));
1838
+ return pkg.version || null;
1839
+ }
1840
+ } catch {
1841
+ }
1842
+ try {
1843
+ const consumerRequire = createRequire2(join2(cwd, "package.json"));
1844
+ const pkgPath = consumerRequire.resolve(`${packageName}/package.json`);
1845
+ const pkg = __require(pkgPath);
1846
+ return pkg.version || null;
1847
+ } catch {
1848
+ }
1849
+ try {
1850
+ const pkgPath = __require.resolve(`${packageName}/package.json`);
1851
+ const pkg = __require(pkgPath);
1852
+ return pkg.version || null;
1853
+ } catch {
1854
+ return null;
1855
+ }
1856
+ }
1857
+ function shouldCheckUpdates(packageName) {
1858
+ return !isWorkspacePackage(packageName);
1859
+ }
1860
+ async function fetchLatestVersion2(packageName) {
1861
+ try {
1862
+ const https = await import("https");
1863
+ return new Promise((resolve) => {
1864
+ const req = https.get(
1865
+ `https://registry.npmjs.org/${packageName}/latest`,
1866
+ { timeout: 5e3 },
1867
+ (res) => {
1868
+ let data = "";
1869
+ res.on("data", (chunk) => {
1870
+ data += chunk;
1871
+ });
1872
+ res.on("end", () => {
1873
+ try {
1874
+ const json = JSON.parse(data);
1875
+ resolve(json.version || null);
1876
+ } catch {
1877
+ resolve(null);
1878
+ }
1879
+ });
1880
+ }
1881
+ );
1882
+ req.on("error", () => resolve(null));
1883
+ req.on("timeout", () => {
1884
+ req.destroy();
1885
+ resolve(null);
1886
+ });
1887
+ });
1888
+ } catch {
1889
+ return null;
1890
+ }
1891
+ }
1892
+ async function checkForUpdates(options = {}) {
1893
+ const results = [];
1894
+ const masterLatest = await fetchLatestVersion2(PACKAGE_NAME);
1895
+ if (!masterLatest) {
1896
+ return results;
1897
+ }
1898
+ const checks = DJANGOCFG_PACKAGES.map(async (name) => {
1899
+ const isWorkspace = !shouldCheckUpdates(name);
1900
+ if (!options.forceCheckWorkspace && isWorkspace) {
1901
+ return null;
1902
+ }
1903
+ const current = getInstalledVersion(name);
1904
+ if (!current) {
1905
+ return null;
1906
+ }
1907
+ const hasUpdate = !!(masterLatest && current && semver2.gt(masterLatest, current));
1908
+ return { name, current, latest: masterLatest, hasUpdate };
1909
+ });
1910
+ const checkResults = await Promise.all(checks);
1911
+ for (const result of checkResults) {
1912
+ if (result) {
1913
+ results.push(result);
1914
+ }
1915
+ }
1916
+ return results;
1917
+ }
1918
+ async function getOutdatedPackages(options = {}) {
1919
+ const all = await checkForUpdates(options);
1920
+ const skipped = updaterCache.get("skippedVersions") || {};
1921
+ return all.filter((pkg) => {
1922
+ if (!pkg.hasUpdate) return false;
1923
+ if (skipped[pkg.name] === pkg.latest) return false;
1924
+ return true;
1925
+ });
1926
+ }
1927
+ function createSpinner2(text) {
1928
+ let frameIndex = 0;
1929
+ let interval = null;
1930
+ let currentText = text;
1931
+ const render = () => {
1932
+ const frame = SPINNER_FRAMES2[frameIndex];
1933
+ process.stdout.write(`\r${chalk3.cyan(frame)} ${currentText}`);
1934
+ frameIndex = (frameIndex + 1) % SPINNER_FRAMES2.length;
1935
+ };
1936
+ return {
1937
+ start() {
1938
+ if (process.stdout.isTTY) {
1939
+ interval = setInterval(render, 80);
1940
+ render();
1941
+ } else {
1942
+ console.log(` ${currentText}`);
1943
+ }
1944
+ return this;
1945
+ },
1946
+ text(newText) {
1947
+ currentText = newText;
1948
+ return this;
1949
+ },
1950
+ succeed(text2) {
1951
+ if (interval) clearInterval(interval);
1952
+ if (process.stdout.isTTY) {
1953
+ process.stdout.write(`\r${chalk3.green("\u2713")} ${text2 || currentText}
1954
+ `);
1955
+ } else {
1956
+ console.log(` ${chalk3.green("\u2713")} ${text2 || currentText}`);
1957
+ }
1958
+ return this;
1959
+ },
1960
+ fail(text2) {
1961
+ if (interval) clearInterval(interval);
1962
+ if (process.stdout.isTTY) {
1963
+ process.stdout.write(`\r${chalk3.red("\u2717")} ${text2 || currentText}
1964
+ `);
1965
+ } else {
1966
+ console.log(` ${chalk3.red("\u2717")} ${text2 || currentText}`);
1967
+ }
1968
+ return this;
1969
+ },
1970
+ stop() {
1971
+ if (interval) clearInterval(interval);
1972
+ if (process.stdout.isTTY) {
1973
+ process.stdout.write("\r\x1B[K");
1974
+ }
1975
+ return this;
1976
+ }
1977
+ };
1978
+ }
1979
+ async function askConfirmation2(question) {
1980
+ if (isCI || !process.stdin.isTTY) {
1981
+ return false;
1982
+ }
1983
+ return new Promise((resolve) => {
1984
+ const rl = createInterface2({
1985
+ input: process.stdin,
1986
+ output: process.stdout
1987
+ });
1988
+ rl.question(question, (answer) => {
1989
+ rl.close();
1990
+ const normalized = answer.toLowerCase().trim();
1991
+ resolve(normalized === "" || normalized === "y" || normalized === "yes");
1992
+ });
1993
+ });
1994
+ }
1995
+ async function updateSinglePackage(pkg, pm, index, total) {
1996
+ const progress = `[${index + 1}/${total}]`;
1997
+ const versionInfo = `${chalk3.red(pkg.current)} \u2192 ${chalk3.green(pkg.latest)}`;
1998
+ const spinner = createSpinner2(
1999
+ `${chalk3.dim(progress)} Updating ${chalk3.cyan(pkg.name)} ${versionInfo}`
2000
+ );
2001
+ spinner.start();
2002
+ const command = pm === "pnpm" ? `pnpm add ${pkg.name}@latest` : pm === "yarn" ? `yarn add ${pkg.name}@latest` : `npm install ${pkg.name}@latest`;
2003
+ return new Promise((resolve) => {
2004
+ const proc = spawn2(command, {
2005
+ shell: true,
2006
+ cwd: process.cwd(),
2007
+ stdio: ["ignore", "pipe", "pipe"]
2008
+ });
2009
+ proc.on("close", (code) => {
2010
+ if (code === 0) {
2011
+ spinner.succeed(
2012
+ `${chalk3.dim(progress)} ${chalk3.cyan(pkg.name)} ${chalk3.green(pkg.latest)}`
2013
+ );
2014
+ resolve(true);
2015
+ } else {
2016
+ spinner.fail(
2017
+ `${chalk3.dim(progress)} ${chalk3.cyan(pkg.name)} ${chalk3.red("failed")}`
2018
+ );
2019
+ resolve(false);
2020
+ }
2021
+ });
2022
+ proc.on("error", () => {
2023
+ spinner.fail(`${chalk3.dim(progress)} ${chalk3.cyan(pkg.name)} ${chalk3.red("failed")}`);
2024
+ resolve(false);
2025
+ });
2026
+ });
2027
+ }
2028
+ async function updatePackagesWithProgress(packages) {
2029
+ if (packages.length === 0) return true;
2030
+ const pm = detectPackageManager();
2031
+ const total = packages.length;
2032
+ console.log("");
2033
+ console.log(chalk3.bold(` Updating ${total} package${total > 1 ? "s" : ""}...`));
2034
+ console.log("");
2035
+ let successCount = 0;
2036
+ const failedPackages = [];
2037
+ for (let i = 0; i < packages.length; i++) {
2038
+ const success = await updateSinglePackage(packages[i], pm, i, total);
2039
+ if (success) {
2040
+ successCount++;
2041
+ } else {
2042
+ failedPackages.push(packages[i].name);
2043
+ }
2044
+ }
2045
+ console.log("");
2046
+ if (failedPackages.length === 0) {
2047
+ consola3.success(`All ${total} packages updated successfully!`);
2048
+ return true;
2049
+ } else if (successCount > 0) {
2050
+ consola3.warn(`${successCount}/${total} packages updated. Failed: ${failedPackages.join(", ")}`);
2051
+ return false;
2052
+ } else {
2053
+ consola3.error(`Failed to update packages: ${failedPackages.join(", ")}`);
2054
+ return false;
2055
+ }
2056
+ }
2057
+ async function checkAndUpdatePackages(options = {}) {
2058
+ const lastCheck = updaterCache.get("lastCheck") || 0;
2059
+ if (!options.force && Date.now() - lastCheck < UPDATE_CHECK_COOLDOWN_MS) {
2060
+ return true;
2061
+ }
2062
+ updaterCache.set("lastCheck", Date.now());
2063
+ const spinner = createSpinner2("Checking for updates...");
2064
+ spinner.start();
2065
+ const outdated = await getOutdatedPackages({
2066
+ forceCheckWorkspace: options.forceCheckWorkspace
2067
+ });
2068
+ spinner.stop();
2069
+ console.log(chalk3.dim(` Found ${outdated.length} outdated package(s)`));
2070
+ if (outdated.length === 0) {
2071
+ console.log(chalk3.green(" \u2713 All packages are up to date"));
2072
+ return true;
2073
+ }
2074
+ if (options.autoUpdate || updaterCache.get("autoUpdate")) {
2075
+ return updatePackagesWithProgress(outdated);
2076
+ }
2077
+ console.log("");
2078
+ consola3.box("\u{1F4E6} Updates Available");
2079
+ console.log("");
2080
+ for (const pkg of outdated) {
2081
+ console.log(
2082
+ ` ${chalk3.yellow("\u2022")} ${chalk3.bold(pkg.name)} ${chalk3.red(pkg.current)} \u2192 ${chalk3.green(pkg.latest)}`
2083
+ );
2084
+ }
2085
+ console.log("");
2086
+ const shouldUpdate = await askConfirmation2(
2087
+ `${chalk3.green("?")} Update these packages now? ${chalk3.dim("[Y/n]")} `
2088
+ );
2089
+ if (shouldUpdate) {
2090
+ const success = await updatePackagesWithProgress(outdated);
2091
+ if (success) {
2092
+ const enableAuto = await askConfirmation2(
2093
+ `${chalk3.green("?")} Enable auto-update for future? ${chalk3.dim("[y/N]")} `
2094
+ );
2095
+ if (enableAuto) {
2096
+ updaterCache.set("autoUpdate", true);
2097
+ consola3.info("Auto-update enabled.");
2098
+ }
2099
+ }
2100
+ return success;
2101
+ }
2102
+ const skipVersions = await askConfirmation2(
2103
+ `${chalk3.green("?")} Skip these versions in future? ${chalk3.dim("[y/N]")} `
2104
+ );
2105
+ if (skipVersions) {
2106
+ const skipped = updaterCache.get("skippedVersions") || {};
2107
+ for (const pkg of outdated) {
2108
+ if (pkg.latest) {
2109
+ skipped[pkg.name] = pkg.latest;
2110
+ }
2111
+ }
2112
+ updaterCache.set("skippedVersions", skipped);
2113
+ consola3.info("Versions skipped. Will prompt again for newer versions.");
2114
+ }
2115
+ return false;
2116
+ }
2117
+ function resetUpdaterPreferences() {
2118
+ updaterCache.clear();
2119
+ consola3.success("Updater preferences reset");
2120
+ }
2121
+
2122
+ // src/config/plugins/devStartup.ts
2123
+ var startupDone = false;
2124
+ var browserOpened = false;
2125
+ var DevStartupPlugin = class {
2126
+ constructor(options = {}) {
2127
+ this.options = options;
2128
+ }
2129
+ apply(compiler) {
2130
+ compiler.hooks.done.tapPromise("DevStartupPlugin", async () => {
2131
+ if (!startupDone) {
2132
+ startupDone = true;
2133
+ await this.runStartupTasks();
2134
+ }
2135
+ if (this.options.openBrowser && !browserOpened) {
2136
+ browserOpened = true;
2137
+ this.openBrowser();
2138
+ }
2139
+ });
2140
+ }
2141
+ async runStartupTasks() {
2142
+ console.log("\n" + chalk4.yellowBright.bold(DJANGO_CFG_BANNER));
2143
+ const version = getCurrentVersion();
2144
+ if (version) {
2145
+ console.log(chalk4.dim(` \u{1F4E6} @djangocfg/nextjs v${version}`));
2146
+ }
2147
+ console.log(chalk4.magenta(` ${AI_DOCS_HINT}
2148
+ `));
2149
+ if (this.options.checkUpdates !== false) {
2150
+ try {
2151
+ await checkAndUpdatePackages({
2152
+ autoUpdate: this.options.autoUpdate,
2153
+ forceCheckWorkspace: this.options.forceCheckWorkspace,
2154
+ force: true
2155
+ // Force check ignoring cooldown
2156
+ });
2157
+ } catch (err) {
2158
+ console.log(chalk4.red(" Update check failed:"), err);
2159
+ }
2160
+ }
2161
+ if (this.options.checkPackages !== false) {
2162
+ await checkAndInstallPackages({
2163
+ autoInstall: this.options.autoInstall
2164
+ });
2165
+ }
2166
+ }
2167
+ openBrowser() {
2168
+ setTimeout(async () => {
2169
+ try {
2170
+ const { exec } = await import("child_process");
2171
+ const port = process.env.PORT || "3000";
2172
+ const url = `http://localhost:${port}`;
2173
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2174
+ exec(`${command} ${url}`, (error) => {
2175
+ if (error) {
2176
+ console.warn(`Failed to open browser: ${error.message}`);
2177
+ }
2178
+ });
2179
+ } catch (error) {
2180
+ console.warn("Failed to open browser");
2181
+ }
2182
+ }, 2e3);
2183
+ }
2184
+ };
2185
+ function resetDevStartupState() {
2186
+ startupDone = false;
2187
+ browserOpened = false;
2188
+ }
2189
+
2190
+ // src/config/plugins/compression.ts
2191
+ var DEFAULT_OPTIONS = {
2192
+ gzip: true,
2193
+ brotli: true,
2194
+ threshold: 8192,
2195
+ minRatio: 0.8,
2196
+ brotliLevel: 8
2197
+ };
2198
+ function addCompressionPlugins(config, options = {}) {
2199
+ if (!isPackageInstalled("compression-webpack-plugin")) {
2200
+ return false;
2201
+ }
2202
+ const opts = { ...DEFAULT_OPTIONS, ...options };
2203
+ try {
2204
+ const CompressionPlugin = __require("compression-webpack-plugin");
2205
+ if (!config.plugins) {
2206
+ config.plugins = [];
2207
+ }
2208
+ if (opts.gzip) {
2209
+ config.plugins.push(
2210
+ new CompressionPlugin({
2211
+ filename: "[path][base].gz",
2212
+ algorithm: "gzip",
2213
+ test: /\.(js|css|html|svg|json)$/,
2214
+ threshold: opts.threshold,
2215
+ minRatio: opts.minRatio
2216
+ })
2217
+ );
2218
+ }
2219
+ if (opts.brotli) {
2220
+ config.plugins.push(
2221
+ new CompressionPlugin({
2222
+ filename: "[path][base].br",
2223
+ algorithm: "brotliCompress",
2224
+ test: /\.(js|css|html|svg|json)$/,
2225
+ threshold: opts.threshold,
2226
+ minRatio: opts.minRatio,
2227
+ compressionOptions: {
2228
+ level: opts.brotliLevel
2229
+ }
2230
+ })
2231
+ );
2232
+ }
2233
+ return true;
2234
+ } catch (error) {
2235
+ return false;
2236
+ }
2237
+ }
2238
+ function isCompressionAvailable() {
2239
+ return isPackageInstalled("compression-webpack-plugin");
2240
+ }
2241
+
2242
+ // src/config/createNextConfig.ts
2243
+ function createBaseNextConfig(options = {}) {
2244
+ const basePath = getBasePath(options.isDefaultCfgAdmin);
2245
+ const apiUrl = getApiUrl();
2246
+ const siteUrl = getSiteUrl2();
2247
+ const baseConfig = {
2248
+ reactStrictMode: true,
2249
+ trailingSlash: true,
2250
+ // Static export configuration
2251
+ ...isStaticBuild && {
2252
+ output: "export",
2253
+ distDir: "out",
2254
+ basePath,
2255
+ // Fix for Next.js 15.5.4: prevent 500.html generation issue
2256
+ generateBuildId: async () => {
2257
+ return "static-build";
2258
+ }
2259
+ },
2260
+ // Standalone output for Docker (only in production, not dev)
2261
+ ...!isStaticBuild && !isDev && {
2262
+ output: "standalone"
2263
+ },
2264
+ // Environment variables
2265
+ env: {
2266
+ NEXT_PUBLIC_BASE_PATH: basePath,
2267
+ NEXT_PUBLIC_API_URL: apiUrl,
2268
+ NEXT_PUBLIC_SITE_URL: siteUrl,
2269
+ ...options.env
2270
+ },
2271
+ // Images configuration
2272
+ images: {
2273
+ unoptimized: true
2274
+ },
2275
+ // CORS headers for static files and iframe embedding
2276
+ async headers() {
2277
+ const headers = [
2278
+ {
2279
+ source: "/static/:path*",
2280
+ headers: [
2281
+ { key: "Access-Control-Allow-Origin", value: "*" },
2282
+ { key: "Access-Control-Allow-Methods", value: "GET, OPTIONS" },
2283
+ { key: "Access-Control-Allow-Headers", value: "Origin, Content-Type, Accept" }
2284
+ ]
2285
+ }
2286
+ ];
2287
+ if (options.allowIframeFrom && options.allowIframeFrom.length > 0) {
2288
+ const frameAncestors = options.allowIframeFrom.includes("*") ? "*" : `'self' ${options.allowIframeFrom.join(" ")}`;
2289
+ headers.push({
2290
+ source: "/:path*",
2291
+ headers: [
2292
+ // Content-Security-Policy frame-ancestors directive
2293
+ { key: "Content-Security-Policy", value: `frame-ancestors ${frameAncestors}` },
2294
+ // X-Frame-Options for older browsers (ALLOW-FROM is deprecated, use CSP instead)
2295
+ // Only set SAMEORIGIN if allowing all, otherwise browsers will use CSP
2296
+ ...options.allowIframeFrom.includes("*") ? [] : [{ key: "X-Frame-Options", value: "SAMEORIGIN" }]
2297
+ ]
2298
+ });
2299
+ }
2300
+ return headers;
2301
+ },
2302
+ // Transpile packages (merge with user-provided)
2303
+ transpilePackages: [
2304
+ ...DEFAULT_TRANSPILE_PACKAGES,
2305
+ ...options.transpilePackages || []
2306
+ ],
2307
+ // Experimental features
2308
+ experimental: {
2309
+ // Optimize package imports (only in production)
2310
+ ...!isDev && {
2311
+ optimizePackageImports: [
2312
+ ...DEFAULT_OPTIMIZE_PACKAGES,
2313
+ ...options.optimizePackageImports || []
2314
+ ]
2315
+ },
2316
+ // Dev mode optimizations
2317
+ ...isDev && {
2318
+ optimizeCss: false
2319
+ },
2320
+ // User experimental options applied last (can override base settings)
2321
+ ...options.experimental
2322
+ },
2323
+ // Webpack configuration
2324
+ webpack: (config, webpackOptions) => {
2325
+ const { isServer, dev } = webpackOptions;
2326
+ if (dev && !isServer) {
2327
+ if (!config.plugins) {
2328
+ config.plugins = [];
2329
+ }
2330
+ config.plugins.push(
2331
+ new DevStartupPlugin({
2332
+ openBrowser: options.openBrowser,
2333
+ checkUpdates: options.checkUpdates,
2334
+ autoUpdate: options.autoUpdate,
2335
+ forceCheckWorkspace: options.forceCheckWorkspace,
2336
+ checkPackages: options.checkPackages,
2337
+ autoInstall: options.autoInstall
2338
+ })
2339
+ );
2340
+ }
2341
+ if (dev) {
2342
+ config.optimization = {
2343
+ ...config.optimization,
2344
+ removeAvailableModules: false,
2345
+ removeEmptyChunks: false,
2346
+ splitChunks: false
2347
+ // Disable code splitting in dev for faster compilation
2348
+ };
2349
+ }
2350
+ config.cache = {
2351
+ type: "filesystem",
2352
+ buildDependencies: {}
2353
+ };
2354
+ if (!isServer && isStaticBuild && !dev) {
2355
+ addCompressionPlugins(config);
2356
+ }
2357
+ if (options.webpack) {
2358
+ return options.webpack(config, webpackOptions);
2359
+ }
2360
+ return config;
2361
+ }
2362
+ };
2363
+ const finalConfig = deepMerge(baseConfig, options);
2364
+ delete finalConfig.optimizePackageImports;
2365
+ delete finalConfig.isDefaultCfgAdmin;
2366
+ delete finalConfig.openBrowser;
2367
+ delete finalConfig.checkUpdates;
2368
+ delete finalConfig.autoUpdate;
2369
+ delete finalConfig.forceCheckWorkspace;
2370
+ delete finalConfig.checkPackages;
2371
+ delete finalConfig.autoInstall;
2372
+ delete finalConfig.allowIframeFrom;
2373
+ return finalConfig;
2374
+ }
2375
+
2376
+ // src/ai/client.ts
2377
+ var DjangoCfgDocsClient = class {
2378
+ constructor(baseUrl = MCP_BASE_URL, timeout = DEFAULT_TIMEOUT) {
2379
+ this.baseUrl = baseUrl.replace(/\/$/, "");
2380
+ this.timeout = timeout;
2381
+ }
2382
+ async makeRequest(endpoint, params) {
2383
+ let url = `${this.baseUrl}${endpoint}`;
2384
+ if (params) {
2385
+ const searchParams = new URLSearchParams();
2386
+ for (const [key, value] of Object.entries(params)) {
2387
+ searchParams.set(key, String(value));
2388
+ }
2389
+ url = `${url}?${searchParams.toString()}`;
2390
+ }
2391
+ const controller = new AbortController();
2392
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2393
+ try {
2394
+ const response = await fetch(url, {
2395
+ method: "GET",
2396
+ headers: {
2397
+ Accept: "application/json",
2398
+ "User-Agent": "DjangoCFG-AI-Client/1.0"
2399
+ },
2400
+ signal: controller.signal
2401
+ });
2402
+ if (!response.ok) {
2403
+ throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);
2404
+ }
2405
+ return await response.json();
2406
+ } finally {
2407
+ clearTimeout(timeoutId);
2408
+ }
2409
+ }
2410
+ /**
2411
+ * Search documentation.
2412
+ */
2413
+ async search(query, options = {}) {
2414
+ const { limit = 5, category } = options;
2415
+ const params = { q: query, limit };
2416
+ if (category) {
2417
+ params.category = category;
2418
+ }
2419
+ const data = await this.makeRequest(API_SEARCH_ENDPOINT, params);
2420
+ const results = data.results || (Array.isArray(data) ? data : []);
2421
+ return results.map((item) => ({
2422
+ title: item.title || "",
2423
+ content: item.content || item.snippet || "",
2424
+ url: item.url || "",
2425
+ score: item.score || 0,
2426
+ category: item.category || ""
2427
+ }));
2428
+ }
2429
+ /**
2430
+ * Get detailed info about a specific topic.
2431
+ */
2432
+ async getInfo(topic) {
2433
+ return this.makeRequest(API_INFO_ENDPOINT, { topic });
2434
+ }
2435
+ /**
2436
+ * Get MCP server configuration for AI assistants.
2437
+ */
2438
+ getMcpConfig() {
2439
+ return {
2440
+ mcpServers: {
2441
+ "djangocfg-docs": {
2442
+ url: `${this.baseUrl}/mcp`
2443
+ }
2444
+ }
2445
+ };
2446
+ }
2447
+ };
2448
+ var defaultClient = null;
2449
+ function getClient() {
2450
+ if (!defaultClient) {
2451
+ defaultClient = new DjangoCfgDocsClient();
2452
+ }
2453
+ return defaultClient;
2454
+ }
2455
+ async function search(query, options = {}) {
2456
+ return getClient().search(query, options);
2457
+ }
2458
+ async function getDocs(query, limit = 3) {
2459
+ const results = await search(query, { limit });
2460
+ if (results.length === 0) {
2461
+ return `No documentation found for: ${query}`;
2462
+ }
2463
+ const output = [];
2464
+ results.forEach((r, i) => {
2465
+ output.push(`## ${i + 1}. ${r.title}`);
2466
+ output.push(r.content);
2467
+ if (r.url) {
2468
+ output.push(`\u{1F4D6} Read more: ${r.url}`);
2469
+ }
2470
+ output.push("");
2471
+ });
2472
+ return output.join("\n");
2473
+ }
2474
+ async function getInfo(topic) {
2475
+ return getClient().getInfo(topic);
2476
+ }
2477
+ function getMcpConfig() {
2478
+ return getClient().getMcpConfig();
2479
+ }
2480
+ export {
2481
+ AI_DOCS_HINT,
2482
+ AI_HINT,
2483
+ DEFAULT_OPTIMIZE_PACKAGES,
2484
+ DEFAULT_TRANSPILE_PACKAGES,
2485
+ DJANGOCFG_PACKAGES,
2486
+ DJANGO_CFG_BANNER,
2487
+ DefaultTemplate,
2488
+ DevStartupPlugin,
2489
+ DjangoCfgDocsClient,
2490
+ LightTemplate,
2491
+ MCP_API_URL,
2492
+ MCP_BASE_URL,
2493
+ MCP_SERVER_URL,
2494
+ OPTIONAL_PACKAGES,
2495
+ PACKAGE_NAME,
2496
+ PEER_DEPENDENCIES,
2497
+ POST,
2498
+ addCompressionPlugins,
2499
+ buildInstallCommand,
2500
+ buildSingleInstallCommand,
2501
+ checkAndInstallPackages,
2502
+ checkAndUpdatePackages,
2503
+ checkForUpdate,
2504
+ checkForUpdates,
2505
+ checkPackages,
2506
+ createBaseNextConfig,
2507
+ createContactRoute,
2508
+ createFontLoader,
2509
+ createHealthHandler,
2510
+ createOgImageDynamicRoute,
2511
+ createOgImageHandler,
2512
+ createOgImageMetadataGenerator,
2513
+ createOgImageUrlBuilder,
2514
+ createSitemapHandler,
2515
+ decodeBase64,
2516
+ deepMerge,
2517
+ defineRoute,
2518
+ detectPackageManager,
2519
+ encodeBase64,
2520
+ fetchLatestVersion,
2521
+ findRoute,
2522
+ findRouteByPattern,
2523
+ generateOgImageMetadata,
2524
+ generateOgImageUrl,
2525
+ generateSitemapXml,
2526
+ getAbsoluteOgImageUrl,
2527
+ getApiUrl,
2528
+ getBasePath,
2529
+ getCurrentVersion,
2530
+ getDocs,
2531
+ getInfo,
2532
+ getInstalledVersion,
2533
+ getMcpConfig,
2534
+ getMissingPackages,
2535
+ getOutdatedPackages,
2536
+ getPackagesForContext,
2537
+ getPageTitle,
2538
+ getSiteUrl2 as getSiteUrl,
2539
+ getUnauthenticatedRedirect,
2540
+ getUpdateCommand,
2541
+ installPackages,
2542
+ installPackagesWithProgress,
2543
+ isActive,
2544
+ isCI,
2545
+ isCompressionAvailable,
2546
+ isDev,
2547
+ isPackageInstalled,
2548
+ isProduction,
2549
+ isStaticBuild,
2550
+ loadGoogleFont,
2551
+ loadGoogleFonts,
2552
+ normalizeUrl,
2553
+ parseOgImageData,
2554
+ parseOgImageUrl,
2555
+ printVersionInfo,
2556
+ redirectToAuth,
2557
+ resetDevStartupState,
2558
+ resetInstallerPreferences,
2559
+ resetUpdaterPreferences,
2560
+ routesToMenuItems,
2561
+ search,
2562
+ submitContactForm,
2563
+ updatePackagesWithProgress
2564
+ };
2565
+ //# sourceMappingURL=index.mjs.map