@djangocfg/nextjs 1.0.17 → 2.1.2

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/README.md CHANGED
@@ -18,6 +18,7 @@
18
18
  ## Features
19
19
 
20
20
  - **Base Next.js Config** - Universal, reusable Next.js configuration factory for monorepos
21
+ - **AI Documentation** - Search DjangoCFG docs via MCP server and CLI
21
22
  - **Sitemap Generation** - Dynamic XML sitemap generation for SEO
22
23
  - **Health Checks** - Production-ready health monitoring endpoints
23
24
  - **OG Images** - Dynamic Open Graph image generation with templates
@@ -38,6 +39,46 @@ yarn add @djangocfg/nextjs
38
39
 
39
40
  ## Quick Start
40
41
 
42
+ ### AI Documentation Search
43
+
44
+ Search DjangoCFG documentation from the terminal:
45
+
46
+ ```bash
47
+ # CLI
48
+ pnpm ai-docs search "database configuration"
49
+ pnpm ai-docs mcp
50
+ ```
51
+
52
+ Or use the TypeScript API:
53
+
54
+ ```tsx
55
+ import { search, getDocs, getMcpConfig } from '@djangocfg/nextjs/ai';
56
+
57
+ // Search documentation
58
+ const results = await search('database configuration');
59
+ results.forEach(r => console.log(r.title, r.url));
60
+
61
+ // Get formatted docs
62
+ const docs = await getDocs('How to configure PostgreSQL?');
63
+
64
+ // Get MCP server config for AI assistants
65
+ const config = getMcpConfig();
66
+ ```
67
+
68
+ ### MCP Server for AI Assistants
69
+
70
+ Add to your AI assistant configuration:
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "djangocfg-docs": {
76
+ "url": "https://mcp.djangocfg.com/mcp"
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
41
82
  ### Base Next.js Configuration
42
83
 
43
84
  Create a reusable base configuration for all your Next.js projects:
@@ -203,6 +244,7 @@ import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';
203
244
  | Path | Description |
204
245
  |------|-------------|
205
246
  | `@djangocfg/nextjs` | Main exports (all modules) |
247
+ | `@djangocfg/nextjs/ai` | AI documentation search and MCP config |
206
248
  | `@djangocfg/nextjs/config` | Base Next.js configuration factory |
207
249
  | `@djangocfg/nextjs/sitemap` | Sitemap generation utilities |
208
250
  | `@djangocfg/nextjs/health` | Health check handlers |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/nextjs",
3
- "version": "1.0.17",
3
+ "version": "2.1.2",
4
4
  "description": "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
5
5
  "keywords": [
6
6
  "nextjs",
@@ -79,6 +79,11 @@
79
79
  "types": "./src/scripts/index.ts",
80
80
  "import": "./src/scripts/index.ts",
81
81
  "default": "./src/scripts/index.ts"
82
+ },
83
+ "./ai": {
84
+ "types": "./src/ai/index.ts",
85
+ "import": "./src/ai/index.ts",
86
+ "default": "./src/ai/index.ts"
82
87
  }
83
88
  },
84
89
  "files": [
@@ -86,22 +91,26 @@
86
91
  "README.md",
87
92
  "LICENSE"
88
93
  ],
94
+ "bin": {
95
+ "ai-docs": "./src/ai/cli.ts"
96
+ },
89
97
  "scripts": {
90
98
  "build": "tsup",
91
99
  "dev": "tsup --watch",
92
100
  "clean": "rm -rf dist",
93
101
  "lint": "eslint .",
94
102
  "check": "tsc --noEmit",
95
- "check-links": "tsx src/scripts/check-links.ts"
103
+ "check-links": "tsx src/scripts/check-links.ts",
104
+ "ai-docs": "tsx src/ai/cli.ts"
96
105
  },
97
106
  "peerDependencies": {
98
- "@djangocfg/api": "^1.4.47",
107
+ "@djangocfg/api": "^2.1.2",
99
108
  "next": "^15.5.7"
100
109
  },
101
110
  "devDependencies": {
102
- "@djangocfg/imgai": "^1.0.33",
103
- "@djangocfg/layouts": "^2.0.17",
104
- "@djangocfg/typescript-config": "^1.4.47",
111
+ "@djangocfg/imgai": "^2.1.2",
112
+ "@djangocfg/layouts": "^2.1.2",
113
+ "@djangocfg/typescript-config": "^2.1.2",
105
114
  "@types/node": "^24.7.2",
106
115
  "@types/react": "19.2.2",
107
116
  "@types/react-dom": "19.2.1",
@@ -0,0 +1,48 @@
1
+ # @djangocfg/nextjs - AI Documentation
2
+
3
+ DjangoCFG documentation is available via MCP server.
4
+
5
+ ## MCP Server
6
+
7
+ ```json
8
+ {
9
+ "mcpServers": {
10
+ "djangocfg-docs": {
11
+ "url": "https://mcp.djangocfg.com/mcp"
12
+ }
13
+ }
14
+ }
15
+ ```
16
+
17
+ ## API
18
+
19
+ ```bash
20
+ curl 'https://mcp.djangocfg.com/api/search?q=database+configuration&limit=5'
21
+ ```
22
+
23
+ ## TypeScript
24
+
25
+ ```ts
26
+ import { search, getDocs, getMcpConfig } from '@djangocfg/nextjs/ai';
27
+
28
+ // Search documentation
29
+ const results = await search('database configuration');
30
+ results.forEach(r => console.log(r.title, r.url));
31
+
32
+ // Get formatted docs
33
+ const docs = await getDocs('How to configure PostgreSQL?');
34
+
35
+ // Get MCP config
36
+ const config = getMcpConfig();
37
+ ```
38
+
39
+ ## Common Topics
40
+
41
+ - DatabaseConfig - PostgreSQL, MySQL, SQLite
42
+ - CacheConfig - Redis, Memcached
43
+ - EmailConfig - SMTP, SendGrid
44
+ - LoggingConfig - Logging setup
45
+ - SecurityConfig - CORS, CSRF
46
+ - DRFConfig - Django REST Framework
47
+ - OG Image - Open Graph image generation
48
+ - Sitemap - XML sitemap generation
package/src/ai/cli.ts ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * DjangoCFG AI Docs CLI
4
+ *
5
+ * Usage:
6
+ * pnpm exec ai-docs search "database configuration"
7
+ * pnpm exec ai-docs mcp
8
+ * npx @djangocfg/nextjs ai-docs search "query"
9
+ */
10
+
11
+ import { search, getMcpConfig, MCP_SERVER_URL, MCP_API_URL } from './index';
12
+
13
+ const args = process.argv.slice(2);
14
+ const command = args[0];
15
+ const query = args.slice(1).join(' ');
16
+
17
+ async function main() {
18
+ switch (command) {
19
+ case 'search':
20
+ case 's':
21
+ if (!query) {
22
+ console.error('Usage: ai-docs search "your query"');
23
+ process.exit(1);
24
+ }
25
+ console.log(`\n🔍 Searching: ${query}\n`);
26
+ try {
27
+ const results = await search(query, { limit: 5 });
28
+ if (results.length === 0) {
29
+ console.log('No results found.');
30
+ } else {
31
+ results.forEach((r, i) => {
32
+ console.log(`${i + 1}. ${r.title}`);
33
+ console.log(` ${r.content.slice(0, 150)}...`);
34
+ if (r.url) console.log(` 📖 ${r.url}`);
35
+ console.log('');
36
+ });
37
+ }
38
+ } catch (err) {
39
+ console.error('Error:', err instanceof Error ? err.message : err);
40
+ process.exit(1);
41
+ }
42
+ break;
43
+
44
+ case 'mcp':
45
+ console.log('\n📡 MCP Server Configuration:\n');
46
+ console.log(JSON.stringify(getMcpConfig(), null, 2));
47
+ console.log('\nAdd this to your AI assistant configuration.');
48
+ break;
49
+
50
+ case 'info':
51
+ case 'i':
52
+ console.log('\n🤖 DjangoCFG AI Documentation\n');
53
+ console.log(`MCP Server: ${MCP_SERVER_URL}`);
54
+ console.log(`Search API: ${MCP_API_URL}`);
55
+ console.log('\nUsage:');
56
+ console.log(' pnpm exec ai-docs search "database configuration"');
57
+ console.log(' pnpm exec ai-docs mcp');
58
+ break;
59
+
60
+ default:
61
+ console.log('🤖 DjangoCFG AI Documentation CLI\n');
62
+ console.log('Commands:');
63
+ console.log(' search <query> Search documentation');
64
+ console.log(' mcp Show MCP server config');
65
+ console.log(' info Show help\n');
66
+ console.log('Examples:');
67
+ console.log(' pnpm exec ai-docs search "database configuration"');
68
+ console.log(' pnpm exec ai-docs search "redis cache"');
69
+ console.log(' pnpm exec ai-docs mcp');
70
+ break;
71
+ }
72
+ }
73
+
74
+ main();
@@ -0,0 +1,171 @@
1
+ /**
2
+ * DjangoCFG Documentation Client
3
+ *
4
+ * HTTP client for accessing DjangoCFG documentation via MCP server API.
5
+ */
6
+
7
+ import {
8
+ MCP_BASE_URL,
9
+ API_SEARCH_ENDPOINT,
10
+ API_INFO_ENDPOINT,
11
+ DEFAULT_TIMEOUT,
12
+ } from './constants';
13
+ import type { SearchResult, SearchOptions, McpConfig, ApiSearchResponse } from './types';
14
+
15
+ /**
16
+ * Client for DjangoCFG Documentation API.
17
+ */
18
+ export class DjangoCfgDocsClient {
19
+ private baseUrl: string;
20
+ private timeout: number;
21
+
22
+ constructor(baseUrl: string = MCP_BASE_URL, timeout: number = DEFAULT_TIMEOUT) {
23
+ this.baseUrl = baseUrl.replace(/\/$/, '');
24
+ this.timeout = timeout;
25
+ }
26
+
27
+ private async makeRequest<T>(endpoint: string, params?: Record<string, string | number>): Promise<T> {
28
+ let url = `${this.baseUrl}${endpoint}`;
29
+
30
+ if (params) {
31
+ const searchParams = new URLSearchParams();
32
+ for (const [key, value] of Object.entries(params)) {
33
+ searchParams.set(key, String(value));
34
+ }
35
+ url = `${url}?${searchParams.toString()}`;
36
+ }
37
+
38
+ const controller = new AbortController();
39
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
40
+
41
+ try {
42
+ const response = await fetch(url, {
43
+ method: 'GET',
44
+ headers: {
45
+ Accept: 'application/json',
46
+ 'User-Agent': 'DjangoCFG-AI-Client/1.0',
47
+ },
48
+ signal: controller.signal,
49
+ });
50
+
51
+ if (!response.ok) {
52
+ throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);
53
+ }
54
+
55
+ return await response.json();
56
+ } finally {
57
+ clearTimeout(timeoutId);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Search documentation.
63
+ */
64
+ async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {
65
+ const { limit = 5, category } = options;
66
+
67
+ const params: Record<string, string | number> = { q: query, limit };
68
+ if (category) {
69
+ params.category = category;
70
+ }
71
+
72
+ const data = await this.makeRequest<ApiSearchResponse>(API_SEARCH_ENDPOINT, params);
73
+
74
+ const results = data.results || (Array.isArray(data) ? data : []);
75
+
76
+ return results.map((item) => ({
77
+ title: item.title || '',
78
+ content: item.content || item.snippet || '',
79
+ url: item.url || '',
80
+ score: item.score || 0,
81
+ category: item.category || '',
82
+ }));
83
+ }
84
+
85
+ /**
86
+ * Get detailed info about a specific topic.
87
+ */
88
+ async getInfo(topic: string): Promise<Record<string, unknown>> {
89
+ return this.makeRequest(API_INFO_ENDPOINT, { topic });
90
+ }
91
+
92
+ /**
93
+ * Get MCP server configuration for AI assistants.
94
+ */
95
+ getMcpConfig(): McpConfig {
96
+ return {
97
+ mcpServers: {
98
+ 'djangocfg-docs': {
99
+ url: `${this.baseUrl}/mcp`,
100
+ },
101
+ },
102
+ };
103
+ }
104
+ }
105
+
106
+ // Default client instance
107
+ let defaultClient: DjangoCfgDocsClient | null = null;
108
+
109
+ function getClient(): DjangoCfgDocsClient {
110
+ if (!defaultClient) {
111
+ defaultClient = new DjangoCfgDocsClient();
112
+ }
113
+ return defaultClient;
114
+ }
115
+
116
+ /**
117
+ * Search DjangoCFG documentation.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * const results = await search('database configuration');
122
+ * results.forEach(r => console.log(r.title, r.url));
123
+ * ```
124
+ */
125
+ export async function search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {
126
+ return getClient().search(query, options);
127
+ }
128
+
129
+ /**
130
+ * Get documentation as formatted text.
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * const docs = await getDocs('How to configure PostgreSQL?');
135
+ * console.log(docs);
136
+ * ```
137
+ */
138
+ export async function getDocs(query: string, limit: number = 3): Promise<string> {
139
+ const results = await search(query, { limit });
140
+
141
+ if (results.length === 0) {
142
+ return `No documentation found for: ${query}`;
143
+ }
144
+
145
+ const output: string[] = [];
146
+
147
+ results.forEach((r, i) => {
148
+ output.push(`## ${i + 1}. ${r.title}`);
149
+ output.push(r.content);
150
+ if (r.url) {
151
+ output.push(`📖 Read more: ${r.url}`);
152
+ }
153
+ output.push('');
154
+ });
155
+
156
+ return output.join('\n');
157
+ }
158
+
159
+ /**
160
+ * Get detailed info about a topic.
161
+ */
162
+ export async function getInfo(topic: string): Promise<Record<string, unknown>> {
163
+ return getClient().getInfo(topic);
164
+ }
165
+
166
+ /**
167
+ * Get MCP server configuration.
168
+ */
169
+ export function getMcpConfig(): McpConfig {
170
+ return getClient().getMcpConfig();
171
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * AI Documentation Constants
3
+ */
4
+
5
+ // MCP Server URLs
6
+ export const MCP_BASE_URL = 'https://mcp.djangocfg.com';
7
+ export const MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
8
+ export const MCP_API_URL = `${MCP_BASE_URL}/api/search`;
9
+
10
+ // API Endpoints
11
+ export const API_SEARCH_ENDPOINT = '/api/search';
12
+ export const API_INFO_ENDPOINT = '/api/info';
13
+ export const DEFAULT_TIMEOUT = 10000; // ms
14
+
15
+ // AI Hint for console output
16
+ export const AI_DOCS_HINT = `🤖 AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search "query"`;
17
+
18
+ // Full AI Hint description
19
+ export const AI_HINT = `
20
+ DjangoCFG Documentation is available via MCP server.
21
+
22
+ To get help with DjangoCFG configuration:
23
+ 1. Use the MCP server: ${MCP_SERVER_URL}
24
+ 2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5
25
+
26
+ Example queries:
27
+ - "How to configure PostgreSQL database?"
28
+ - "What is DatabaseConfig?"
29
+ - "How to setup Redis cache?"
30
+ - "Email configuration with SMTP"
31
+ `;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * DjangoCFG AI Documentation Client
3
+ *
4
+ * Provides access to DjangoCFG documentation via MCP server API.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { search, getDocs, getMcpConfig } from '@djangocfg/nextjs/ai';
9
+ *
10
+ * // Search documentation
11
+ * const results = await search('database configuration');
12
+ *
13
+ * // Get formatted docs
14
+ * const docs = await getDocs('How to configure PostgreSQL?');
15
+ *
16
+ * // Get MCP config for AI assistants
17
+ * const config = getMcpConfig();
18
+ * ```
19
+ */
20
+
21
+ export { DjangoCfgDocsClient, search, getDocs, getInfo, getMcpConfig } from './client';
22
+ export type { SearchResult, SearchOptions, McpConfig } from './types';
23
+ export {
24
+ MCP_BASE_URL,
25
+ MCP_SERVER_URL,
26
+ MCP_API_URL,
27
+ AI_DOCS_HINT,
28
+ AI_HINT,
29
+ } from './constants';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * AI Documentation Types
3
+ */
4
+
5
+ export interface SearchResult {
6
+ title: string;
7
+ content: string;
8
+ url: string;
9
+ score: number;
10
+ category: string;
11
+ }
12
+
13
+ export interface SearchOptions {
14
+ limit?: number;
15
+ category?: string;
16
+ }
17
+
18
+ export interface McpConfig {
19
+ mcpServers: {
20
+ 'djangocfg-docs': {
21
+ url: string;
22
+ };
23
+ };
24
+ }
25
+
26
+ export interface ApiSearchResponse {
27
+ results: Array<{
28
+ title: string;
29
+ content?: string;
30
+ snippet?: string;
31
+ url: string;
32
+ score?: number;
33
+ category?: string;
34
+ }>;
35
+ }
@@ -31,7 +31,6 @@ export const DJANGOCFG_PACKAGES = [
31
31
  '@djangocfg/nextjs',
32
32
  '@djangocfg/api',
33
33
  '@djangocfg/centrifugo',
34
- '@djangocfg/imgai',
35
34
  '@djangocfg/eslint-config',
36
35
  '@djangocfg/typescript-config',
37
36
  ] as const;
@@ -24,6 +24,14 @@ export {
24
24
  DJANGO_CFG_BANNER,
25
25
  } from './constants';
26
26
 
27
+ // Re-export AI constants from ai module
28
+ export {
29
+ MCP_BASE_URL,
30
+ MCP_SERVER_URL,
31
+ MCP_API_URL,
32
+ AI_DOCS_HINT,
33
+ } from '../ai/constants';
34
+
27
35
  // Utils
28
36
  export { deepMerge } from './utils/deepMerge';
29
37
  export {
@@ -12,7 +12,7 @@ import chalk from 'chalk';
12
12
  import consola from 'consola';
13
13
  import Conf from 'conf';
14
14
  import semver from 'semver';
15
- import { DJANGOCFG_PACKAGES } from '../constants';
15
+ import { DJANGOCFG_PACKAGES, PACKAGE_NAME } from '../constants';
16
16
  import { isCI } from '../utils/env';
17
17
  import { detectPackageManager } from './installer';
18
18
 
@@ -146,12 +146,21 @@ async function fetchLatestVersion(packageName: string): Promise<string | null> {
146
146
 
147
147
  /**
148
148
  * Check all @djangocfg packages for updates
149
+ * All packages are aligned to the version of @djangocfg/nextjs (master package)
149
150
  * Skips workspace:* packages unless forceCheckWorkspace is true
150
151
  */
151
152
  export async function checkForUpdates(options: { forceCheckWorkspace?: boolean } = {}): Promise<PackageVersion[]> {
152
153
  const results: PackageVersion[] = [];
153
154
 
154
- // Check packages in parallel
155
+ // First, get the latest version of master package (@djangocfg/nextjs)
156
+ // All other packages should align to this version
157
+ const masterLatest = await fetchLatestVersion(PACKAGE_NAME);
158
+ if (!masterLatest) {
159
+ // Can't determine target version, skip update check
160
+ return results;
161
+ }
162
+
163
+ // Check packages against master version
155
164
  const checks = DJANGOCFG_PACKAGES.map(async (name) => {
156
165
  // Skip workspace packages unless force mode
157
166
  const isWorkspace = !shouldCheckUpdates(name);
@@ -164,10 +173,10 @@ export async function checkForUpdates(options: { forceCheckWorkspace?: boolean }
164
173
  return null;
165
174
  }
166
175
 
167
- const latest = await fetchLatestVersion(name);
168
- const hasUpdate = !!(latest && current && semver.gt(latest, current));
176
+ // All packages should update to master package version
177
+ const hasUpdate = !!(masterLatest && current && semver.gt(masterLatest, current));
169
178
 
170
- return { name, current, latest, hasUpdate };
179
+ return { name, current, latest: masterLatest, hasUpdate };
171
180
  });
172
181
 
173
182
  const checkResults = await Promise.all(checks);
@@ -291,11 +300,12 @@ async function updateSinglePackage(
291
300
 
292
301
  spinner.start();
293
302
 
303
+ // Always install with @latest to keep package.json consistent
294
304
  const command = pm === 'pnpm'
295
- ? `pnpm add ${pkg.name}@${pkg.latest}`
305
+ ? `pnpm add ${pkg.name}@latest`
296
306
  : pm === 'yarn'
297
- ? `yarn add ${pkg.name}@${pkg.latest}`
298
- : `npm install ${pkg.name}@${pkg.latest}`;
307
+ ? `yarn add ${pkg.name}@latest`
308
+ : `npm install ${pkg.name}@latest`;
299
309
 
300
310
  return new Promise((resolve) => {
301
311
  const proc = spawn(command, {
@@ -7,6 +7,7 @@
7
7
  import type { Compiler } from 'webpack';
8
8
  import chalk from 'chalk';
9
9
  import { DJANGO_CFG_BANNER } from '../constants';
10
+ import { AI_DOCS_HINT } from '../../ai/constants';
10
11
  import { getCurrentVersion } from '../utils/version';
11
12
  import { checkAndInstallPackages } from '../packages/installer';
12
13
  import { checkAndUpdatePackages } from '../packages/updater';
@@ -64,10 +65,13 @@ export class DevStartupPlugin {
64
65
  // 2. Print current version
65
66
  const version = getCurrentVersion();
66
67
  if (version) {
67
- console.log(chalk.dim(` 📦 @djangocfg/nextjs v${version}\n`));
68
+ console.log(chalk.dim(` 📦 @djangocfg/nextjs v${version}`));
68
69
  }
69
70
 
70
- // 3. Check for package updates
71
+ // 3. Print AI docs hint
72
+ console.log(chalk.magenta(` ${AI_DOCS_HINT}\n`));
73
+
74
+ // 4. Check for package updates
71
75
  if (this.options.checkUpdates !== false) {
72
76
  try {
73
77
  await checkAndUpdatePackages({
@@ -80,7 +84,7 @@ export class DevStartupPlugin {
80
84
  }
81
85
  }
82
86
 
83
- // 4. Check for missing optional packages
87
+ // 5. Check for missing optional packages
84
88
  if (this.options.checkPackages !== false) {
85
89
  await checkAndInstallPackages({
86
90
  autoInstall: this.options.autoInstall,
package/src/index.ts CHANGED
@@ -22,6 +22,9 @@ export * from './navigation';
22
22
  // Config
23
23
  export * from './config';
24
24
 
25
+ // AI Documentation
26
+ export * from './ai';
27
+
25
28
  // Types
26
29
  export type * from './types';
27
30