@djangocfg/nextjs 2.1.7 ā 2.1.9
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 +3 -3
- package/dist/ai/cli.mjs +52 -27
- package/dist/ai/cli.mjs.map +1 -1
- package/dist/config/index.mjs +2 -2
- package/dist/config/index.mjs.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/ai/CLAUDE.md +12 -0
- package/src/ai/cli.ts +61 -29
package/README.md
CHANGED
|
@@ -44,9 +44,9 @@ yarn add @djangocfg/nextjs
|
|
|
44
44
|
Search DjangoCFG documentation from the terminal:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
# CLI
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
# CLI (works anywhere via npx)
|
|
48
|
+
npx @djangocfg/nextjs ai-docs search "database configuration"
|
|
49
|
+
npx @djangocfg/nextjs ai-docs mcp
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Or use the TypeScript API:
|
package/dist/ai/cli.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/ai/cli.ts
|
|
4
|
+
import { consola } from "consola";
|
|
5
|
+
|
|
3
6
|
// src/ai/constants.ts
|
|
4
7
|
var MCP_BASE_URL = "https://mcp.djangocfg.com";
|
|
5
8
|
var MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;
|
|
@@ -112,58 +115,80 @@ function getMcpConfig() {
|
|
|
112
115
|
var args = process.argv.slice(2);
|
|
113
116
|
var command = args[0];
|
|
114
117
|
var query = args.slice(1).join(" ");
|
|
118
|
+
function wrapText(text, indent = 3, maxWidth) {
|
|
119
|
+
const width = maxWidth || process.stdout.columns || 80;
|
|
120
|
+
const effectiveWidth = width - indent;
|
|
121
|
+
const prefix = " ".repeat(indent);
|
|
122
|
+
const cleaned = text.replace(/\s+/g, " ").trim();
|
|
123
|
+
if (cleaned.length <= effectiveWidth) {
|
|
124
|
+
return prefix + cleaned;
|
|
125
|
+
}
|
|
126
|
+
const words = cleaned.split(" ");
|
|
127
|
+
const lines = [];
|
|
128
|
+
let currentLine = "";
|
|
129
|
+
for (const word of words) {
|
|
130
|
+
if (currentLine.length + word.length + 1 <= effectiveWidth) {
|
|
131
|
+
currentLine += (currentLine ? " " : "") + word;
|
|
132
|
+
} else {
|
|
133
|
+
if (currentLine) lines.push(prefix + currentLine);
|
|
134
|
+
currentLine = word;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (currentLine) lines.push(prefix + currentLine);
|
|
138
|
+
return lines.join("\n");
|
|
139
|
+
}
|
|
115
140
|
async function main() {
|
|
116
141
|
switch (command) {
|
|
117
142
|
case "search":
|
|
118
143
|
case "s":
|
|
119
144
|
if (!query) {
|
|
120
|
-
|
|
145
|
+
consola.error('Usage: djangocfg-docs search "your query"');
|
|
121
146
|
process.exit(1);
|
|
122
147
|
}
|
|
123
|
-
|
|
124
|
-
\u{1F50D} Searching: ${query}
|
|
148
|
+
consola.info(`Searching: ${query}
|
|
125
149
|
`);
|
|
126
150
|
try {
|
|
127
151
|
const results = await search(query, { limit: 5 });
|
|
128
152
|
if (results.length === 0) {
|
|
129
|
-
|
|
153
|
+
consola.warn("No results found.");
|
|
130
154
|
} else {
|
|
131
155
|
results.forEach((r, i) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
consola.success(`${i + 1}. ${r.title}`);
|
|
157
|
+
const contentPreview = r.content.slice(0, 200);
|
|
158
|
+
console.log(wrapText(contentPreview + "..."));
|
|
159
|
+
if (r.url) consola.log(` ${r.url}`);
|
|
160
|
+
consola.log("");
|
|
136
161
|
});
|
|
137
162
|
}
|
|
138
163
|
} catch (err) {
|
|
139
|
-
|
|
164
|
+
consola.error("Error:", err instanceof Error ? err.message : err);
|
|
140
165
|
process.exit(1);
|
|
141
166
|
}
|
|
142
167
|
break;
|
|
143
168
|
case "mcp":
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
169
|
+
consola.box("MCP Server Configuration");
|
|
170
|
+
consola.log(JSON.stringify(getMcpConfig(), null, 2));
|
|
171
|
+
consola.info("Add this to your AI assistant configuration.");
|
|
147
172
|
break;
|
|
148
173
|
case "info":
|
|
149
174
|
case "i":
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
175
|
+
consola.box("DjangoCFG AI Documentation");
|
|
176
|
+
consola.info(`MCP Server: ${MCP_SERVER_URL}`);
|
|
177
|
+
consola.info(`Search API: ${MCP_API_URL}`);
|
|
178
|
+
consola.log("\nUsage:");
|
|
179
|
+
consola.log(' npx djangocfg-docs search "database configuration"');
|
|
180
|
+
consola.log(" npx djangocfg-docs mcp");
|
|
156
181
|
break;
|
|
157
182
|
default:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
183
|
+
consola.box("DjangoCFG AI Documentation CLI");
|
|
184
|
+
consola.log("Commands:");
|
|
185
|
+
consola.log(" search <query> Search documentation");
|
|
186
|
+
consola.log(" mcp Show MCP server config");
|
|
187
|
+
consola.log(" info Show help\n");
|
|
188
|
+
consola.log("Examples:");
|
|
189
|
+
consola.log(' npx djangocfg-docs search "database configuration"');
|
|
190
|
+
consola.log(' npx djangocfg-docs search "redis cache"');
|
|
191
|
+
consola.log(" npx djangocfg-docs mcp");
|
|
167
192
|
break;
|
|
168
193
|
}
|
|
169
194
|
}
|
package/dist/ai/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ai/constants.ts","../../src/ai/client.ts","../../src/ai/cli.ts"],"sourcesContent":["/**\n * AI Documentation Constants\n */\n\n// MCP Server URLs\nexport const MCP_BASE_URL = 'https://mcp.djangocfg.com';\nexport const MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;\nexport const MCP_API_URL = `${MCP_BASE_URL}/api/search`;\n\n// API Endpoints\nexport const API_SEARCH_ENDPOINT = '/api/search';\nexport const API_INFO_ENDPOINT = '/api/info';\nexport const DEFAULT_TIMEOUT = 10000; // ms\n\n// AI Hint for console output\nexport const AI_DOCS_HINT = `š¤ AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search \"query\"`;\n\n// Full AI Hint description\nexport const AI_HINT = `\nDjangoCFG Documentation is available via MCP server.\n\nTo get help with DjangoCFG configuration:\n1. Use the MCP server: ${MCP_SERVER_URL}\n2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5\n\nExample queries:\n- \"How to configure PostgreSQL database?\"\n- \"What is DatabaseConfig?\"\n- \"How to setup Redis cache?\"\n- \"Email configuration with SMTP\"\n`;\n","/**\n * DjangoCFG Documentation Client\n *\n * HTTP client for accessing DjangoCFG documentation via MCP server API.\n */\n\nimport {\n MCP_BASE_URL,\n API_SEARCH_ENDPOINT,\n API_INFO_ENDPOINT,\n DEFAULT_TIMEOUT,\n} from './constants';\nimport type { SearchResult, SearchOptions, McpConfig, ApiSearchResponse } from './types';\n\n/**\n * Client for DjangoCFG Documentation API.\n */\nexport class DjangoCfgDocsClient {\n private baseUrl: string;\n private timeout: number;\n\n constructor(baseUrl: string = MCP_BASE_URL, timeout: number = DEFAULT_TIMEOUT) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.timeout = timeout;\n }\n\n private async makeRequest<T>(endpoint: string, params?: Record<string, string | number>): Promise<T> {\n let url = `${this.baseUrl}${endpoint}`;\n\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n searchParams.set(key, String(value));\n }\n url = `${url}?${searchParams.toString()}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n 'User-Agent': 'DjangoCFG-AI-Client/1.0',\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);\n }\n\n return await response.json();\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Search documentation.\n */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { limit = 5, category } = options;\n\n const params: Record<string, string | number> = { q: query, limit };\n if (category) {\n params.category = category;\n }\n\n const data = await this.makeRequest<ApiSearchResponse>(API_SEARCH_ENDPOINT, params);\n\n const results = data.results || (Array.isArray(data) ? data : []);\n\n return results.map((item) => ({\n title: item.title || '',\n content: item.content || item.snippet || '',\n url: item.url || '',\n score: item.score || 0,\n category: item.category || '',\n }));\n }\n\n /**\n * Get detailed info about a specific topic.\n */\n async getInfo(topic: string): Promise<Record<string, unknown>> {\n return this.makeRequest(API_INFO_ENDPOINT, { topic });\n }\n\n /**\n * Get MCP server configuration for AI assistants.\n */\n getMcpConfig(): McpConfig {\n return {\n mcpServers: {\n 'djangocfg-docs': {\n url: `${this.baseUrl}/mcp`,\n },\n },\n };\n }\n}\n\n// Default client instance\nlet defaultClient: DjangoCfgDocsClient | null = null;\n\nfunction getClient(): DjangoCfgDocsClient {\n if (!defaultClient) {\n defaultClient = new DjangoCfgDocsClient();\n }\n return defaultClient;\n}\n\n/**\n * Search DjangoCFG documentation.\n *\n * @example\n * ```ts\n * const results = await search('database configuration');\n * results.forEach(r => console.log(r.title, r.url));\n * ```\n */\nexport async function search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return getClient().search(query, options);\n}\n\n/**\n * Get documentation as formatted text.\n *\n * @example\n * ```ts\n * const docs = await getDocs('How to configure PostgreSQL?');\n * console.log(docs);\n * ```\n */\nexport async function getDocs(query: string, limit: number = 3): Promise<string> {\n const results = await search(query, { limit });\n\n if (results.length === 0) {\n return `No documentation found for: ${query}`;\n }\n\n const output: string[] = [];\n\n results.forEach((r, i) => {\n output.push(`## ${i + 1}. ${r.title}`);\n output.push(r.content);\n if (r.url) {\n output.push(`š Read more: ${r.url}`);\n }\n output.push('');\n });\n\n return output.join('\\n');\n}\n\n/**\n * Get detailed info about a topic.\n */\nexport async function getInfo(topic: string): Promise<Record<string, unknown>> {\n return getClient().getInfo(topic);\n}\n\n/**\n * Get MCP server configuration.\n */\nexport function getMcpConfig(): McpConfig {\n return getClient().getMcpConfig();\n}\n","#!/usr/bin/env node\n/**\n * DjangoCFG AI Docs CLI\n *\n * Usage:\n * pnpm exec ai-docs search \"database configuration\"\n * pnpm exec ai-docs mcp\n * npx @djangocfg/nextjs ai-docs search \"query\"\n */\n\nimport { search, getMcpConfig, MCP_SERVER_URL, MCP_API_URL } from './index';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\nconst query = args.slice(1).join(' ');\n\nasync function main() {\n switch (command) {\n case 'search':\n case 's':\n if (!query) {\n console.error('Usage: ai-docs search \"your query\"');\n process.exit(1);\n }\n console.log(`\\nš Searching: ${query}\\n`);\n try {\n const results = await search(query, { limit: 5 });\n if (results.length === 0) {\n console.log('No results found.');\n } else {\n results.forEach((r, i) => {\n console.log(`${i + 1}. ${r.title}`);\n console.log(` ${r.content.slice(0, 150)}...`);\n if (r.url) console.log(` š ${r.url}`);\n console.log('');\n });\n }\n } catch (err) {\n console.error('Error:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n break;\n\n case 'mcp':\n console.log('\\nš” MCP Server Configuration:\\n');\n console.log(JSON.stringify(getMcpConfig(), null, 2));\n console.log('\\nAdd this to your AI assistant configuration.');\n break;\n\n case 'info':\n case 'i':\n console.log('\\nš¤ DjangoCFG AI Documentation\\n');\n console.log(`MCP Server: ${MCP_SERVER_URL}`);\n console.log(`Search API: ${MCP_API_URL}`);\n console.log('\\nUsage:');\n console.log(' pnpm exec ai-docs search \"database configuration\"');\n console.log(' pnpm exec ai-docs mcp');\n break;\n\n default:\n console.log('š¤ DjangoCFG AI Documentation CLI\\n');\n console.log('Commands:');\n console.log(' search <query> Search documentation');\n console.log(' mcp Show MCP server config');\n console.log(' info Show help\\n');\n console.log('Examples:');\n console.log(' pnpm exec ai-docs search \"database configuration\"');\n console.log(' pnpm exec ai-docs search \"redis cache\"');\n console.log(' pnpm exec ai-docs mcp');\n break;\n }\n}\n\nmain();\n"],"mappings":"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","names":["query"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ai/cli.ts","../../src/ai/constants.ts","../../src/ai/client.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * DjangoCFG AI Docs CLI\n *\n * Usage:\n * npx djangocfg-docs search \"database configuration\"\n * npx djangocfg-docs mcp\n */\n\nimport { consola } from 'consola';\nimport { search, getMcpConfig, MCP_SERVER_URL, MCP_API_URL } from './index';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\nconst query = args.slice(1).join(' ');\n\n/** Wrap text to terminal width with indent */\nfunction wrapText(text: string, indent = 3, maxWidth?: number): string {\n const width = maxWidth || process.stdout.columns || 80;\n const effectiveWidth = width - indent;\n const prefix = ' '.repeat(indent);\n\n // Clean up text - remove extra whitespace and newlines\n const cleaned = text.replace(/\\s+/g, ' ').trim();\n\n if (cleaned.length <= effectiveWidth) {\n return prefix + cleaned;\n }\n\n const words = cleaned.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (currentLine.length + word.length + 1 <= effectiveWidth) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) lines.push(prefix + currentLine);\n currentLine = word;\n }\n }\n if (currentLine) lines.push(prefix + currentLine);\n\n return lines.join('\\n');\n}\n\nasync function main() {\n switch (command) {\n case 'search':\n case 's':\n if (!query) {\n consola.error('Usage: djangocfg-docs search \"your query\"');\n process.exit(1);\n }\n consola.info(`Searching: ${query}\\n`);\n try {\n const results = await search(query, { limit: 5 });\n if (results.length === 0) {\n consola.warn('No results found.');\n } else {\n results.forEach((r, i) => {\n consola.success(`${i + 1}. ${r.title}`);\n // Wrap content to terminal width\n const contentPreview = r.content.slice(0, 200);\n console.log(wrapText(contentPreview + '...'));\n if (r.url) consola.log(` ${r.url}`);\n consola.log('');\n });\n }\n } catch (err) {\n consola.error('Error:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n break;\n\n case 'mcp':\n consola.box('MCP Server Configuration');\n consola.log(JSON.stringify(getMcpConfig(), null, 2));\n consola.info('Add this to your AI assistant configuration.');\n break;\n\n case 'info':\n case 'i':\n consola.box('DjangoCFG AI Documentation');\n consola.info(`MCP Server: ${MCP_SERVER_URL}`);\n consola.info(`Search API: ${MCP_API_URL}`);\n consola.log('\\nUsage:');\n consola.log(' npx djangocfg-docs search \"database configuration\"');\n consola.log(' npx djangocfg-docs mcp');\n break;\n\n default:\n consola.box('DjangoCFG AI Documentation CLI');\n consola.log('Commands:');\n consola.log(' search <query> Search documentation');\n consola.log(' mcp Show MCP server config');\n consola.log(' info Show help\\n');\n consola.log('Examples:');\n consola.log(' npx djangocfg-docs search \"database configuration\"');\n consola.log(' npx djangocfg-docs search \"redis cache\"');\n consola.log(' npx djangocfg-docs mcp');\n break;\n }\n}\n\nmain();\n","/**\n * AI Documentation Constants\n */\n\n// MCP Server URLs\nexport const MCP_BASE_URL = 'https://mcp.djangocfg.com';\nexport const MCP_SERVER_URL = `${MCP_BASE_URL}/mcp`;\nexport const MCP_API_URL = `${MCP_BASE_URL}/api/search`;\n\n// API Endpoints\nexport const API_SEARCH_ENDPOINT = '/api/search';\nexport const API_INFO_ENDPOINT = '/api/info';\nexport const DEFAULT_TIMEOUT = 10000; // ms\n\n// AI Hint for console output\nexport const AI_DOCS_HINT = `š¤ AI Docs: ${MCP_SERVER_URL} | pnpm ai-docs search \"query\"`;\n\n// Full AI Hint description\nexport const AI_HINT = `\nDjangoCFG Documentation is available via MCP server.\n\nTo get help with DjangoCFG configuration:\n1. Use the MCP server: ${MCP_SERVER_URL}\n2. Or search directly: ${MCP_API_URL}?q=YOUR_QUERY&limit=5\n\nExample queries:\n- \"How to configure PostgreSQL database?\"\n- \"What is DatabaseConfig?\"\n- \"How to setup Redis cache?\"\n- \"Email configuration with SMTP\"\n`;\n","/**\n * DjangoCFG Documentation Client\n *\n * HTTP client for accessing DjangoCFG documentation via MCP server API.\n */\n\nimport {\n MCP_BASE_URL,\n API_SEARCH_ENDPOINT,\n API_INFO_ENDPOINT,\n DEFAULT_TIMEOUT,\n} from './constants';\nimport type { SearchResult, SearchOptions, McpConfig, ApiSearchResponse } from './types';\n\n/**\n * Client for DjangoCFG Documentation API.\n */\nexport class DjangoCfgDocsClient {\n private baseUrl: string;\n private timeout: number;\n\n constructor(baseUrl: string = MCP_BASE_URL, timeout: number = DEFAULT_TIMEOUT) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.timeout = timeout;\n }\n\n private async makeRequest<T>(endpoint: string, params?: Record<string, string | number>): Promise<T> {\n let url = `${this.baseUrl}${endpoint}`;\n\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n searchParams.set(key, String(value));\n }\n url = `${url}?${searchParams.toString()}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n 'User-Agent': 'DjangoCFG-AI-Client/1.0',\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);\n }\n\n return await response.json();\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Search documentation.\n */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { limit = 5, category } = options;\n\n const params: Record<string, string | number> = { q: query, limit };\n if (category) {\n params.category = category;\n }\n\n const data = await this.makeRequest<ApiSearchResponse>(API_SEARCH_ENDPOINT, params);\n\n const results = data.results || (Array.isArray(data) ? data : []);\n\n return results.map((item) => ({\n title: item.title || '',\n content: item.content || item.snippet || '',\n url: item.url || '',\n score: item.score || 0,\n category: item.category || '',\n }));\n }\n\n /**\n * Get detailed info about a specific topic.\n */\n async getInfo(topic: string): Promise<Record<string, unknown>> {\n return this.makeRequest(API_INFO_ENDPOINT, { topic });\n }\n\n /**\n * Get MCP server configuration for AI assistants.\n */\n getMcpConfig(): McpConfig {\n return {\n mcpServers: {\n 'djangocfg-docs': {\n url: `${this.baseUrl}/mcp`,\n },\n },\n };\n }\n}\n\n// Default client instance\nlet defaultClient: DjangoCfgDocsClient | null = null;\n\nfunction getClient(): DjangoCfgDocsClient {\n if (!defaultClient) {\n defaultClient = new DjangoCfgDocsClient();\n }\n return defaultClient;\n}\n\n/**\n * Search DjangoCFG documentation.\n *\n * @example\n * ```ts\n * const results = await search('database configuration');\n * results.forEach(r => console.log(r.title, r.url));\n * ```\n */\nexport async function search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return getClient().search(query, options);\n}\n\n/**\n * Get documentation as formatted text.\n *\n * @example\n * ```ts\n * const docs = await getDocs('How to configure PostgreSQL?');\n * console.log(docs);\n * ```\n */\nexport async function getDocs(query: string, limit: number = 3): Promise<string> {\n const results = await search(query, { limit });\n\n if (results.length === 0) {\n return `No documentation found for: ${query}`;\n }\n\n const output: string[] = [];\n\n results.forEach((r, i) => {\n output.push(`## ${i + 1}. ${r.title}`);\n output.push(r.content);\n if (r.url) {\n output.push(`š Read more: ${r.url}`);\n }\n output.push('');\n });\n\n return output.join('\\n');\n}\n\n/**\n * Get detailed info about a topic.\n */\nexport async function getInfo(topic: string): Promise<Record<string, unknown>> {\n return getClient().getInfo(topic);\n}\n\n/**\n * Get MCP server configuration.\n */\nexport function getMcpConfig(): McpConfig {\n return getClient().getMcpConfig();\n}\n"],"mappings":"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","names":["query"]}
|
package/dist/config/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var require_package = __commonJS({
|
|
|
14
14
|
"package.json"(exports, module) {
|
|
15
15
|
module.exports = {
|
|
16
16
|
name: "@djangocfg/nextjs",
|
|
17
|
-
version: "2.1.
|
|
17
|
+
version: "2.1.9",
|
|
18
18
|
description: "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
|
|
19
19
|
keywords: [
|
|
20
20
|
"nextjs",
|
|
@@ -107,7 +107,7 @@ var require_package = __commonJS({
|
|
|
107
107
|
"LICENSE"
|
|
108
108
|
],
|
|
109
109
|
bin: {
|
|
110
|
-
"
|
|
110
|
+
"djangocfg-docs": "./dist/ai/cli.mjs"
|
|
111
111
|
},
|
|
112
112
|
scripts: {
|
|
113
113
|
build: "tsup",
|